diff --git a/build/j-spec.pdf b/build/j-spec.pdf index e10de81..b8f7af2 100644 Binary files a/build/j-spec.pdf and b/build/j-spec.pdf differ diff --git a/build/jtc2-02a.pdf b/build/jtc2-02a.pdf index 7579e74..432a0ee 100644 Binary files a/build/jtc2-02a.pdf and b/build/jtc2-02a.pdf differ diff --git a/j-spec.tex b/j-spec.tex index cf746f3..bfc54d0 100644 --- a/j-spec.tex +++ b/j-spec.tex @@ -1,5 +1,4 @@ \immediate\write18{texcount -sum -1 -inc j-spec.tex > /tmp/wordcount.tex} - \documentclass[a4paper,12pt]{article} \usepackage[english,russian]{babel} diff --git a/jtc2-02a.tex b/jtc2-02a.tex index 22d1116..d43cacf 100644 --- a/jtc2-02a.tex +++ b/jtc2-02a.tex @@ -1,6 +1,7 @@ \documentclass[j-spec.tex]{subfiles} \begin{document} +\tableofcontents \section{Специализация: данные и функции} \subsection{В предыдущем разделе} \begin{itemize} @@ -95,12 +96,6 @@ \end{center} \end{frm} - -\subsubsection{Задания для самопроверки} -\begin{enumerate} -\item длдлдл -\end{enumerate} - \subsubsection{Бинарное (битовое) представление данных} После разговора о переполнении, нельзя не сказать о том, что именно переполняется. Далее будут представлены сведения которые касаются не только языка Java но и любого другого языка программирования. Эти сведения помогут разобраться в деталях того как хранится значение переменной в программе и как, в целом, происходит работа компьютерной техники. @@ -157,7 +152,236 @@ \item длдлдл \end{enumerate} -\subsubsection{} +\subsubsection{Целочисленные типы} +Целочисленных типов четыре, и они занимают 1, 2, 4 и 8 байт. +\begin{frm} +\info Технически, целочисленых типов пять, но \code{char} устроен чуть сложнее других, поэтому не рассматривается в этом разделе. +\end{frm} + +Значения в целочисленных типах могут быть только целые, никак и никогда невозможно присвоить им дробных значений. Про эти типы следует помнить следующее: +\begin{itemize} +\item \code{int} - это самый часто используемый тип. Если сомневаетесь, какой целочисленный тип использовать, используйте \code{int}; +\item все целые числа, которые пишутся в коде - это \code{int}, даже если вы пытаетесь их присвоить переменной другого типа. +\end{itemize} + +Как \code{int} преобразуется в меньше типы? Если написать цифрами справа число, которое может поместиться в переменную меньшего типа слева, то статический анализатор кода его пропустит, а компилятор преобразует в меньший тип автоматически (строка 9 на рис. \hrf{pic:byte-overflow}). +\begin{figure}[H] + \centering + \includegraphics[width=12cm]{jc-02-byte-overflow.png} + \caption{Присваивание валидных и переполняющих значений} + \label{pic:byte-overflow} +\end{figure} + +Как видно, к маленькому \code{byte} успешно присваивается \code{int}. Если же написать число которое больше типа слева и, соответственно, поместиться не может, среда разработки выдает предупреждение компилятора, что ожидался \code{byte}, а передан \code{int} (строка 10 рис \hrf{pic:byte-overflow}). + +Часто нужно записать в виде числа какое-то значение большее чем может принимать \code{int}, и явно присвоить начальное значение переменной типа \code{long}. + +\begin{figure}[H] + \centering + \includegraphics[width=12cm]{jc-02-int-overflow.png} + \caption{Попытка инициализации переменной типа \code{long}} + \label{pic:int-overflow} +\end{figure} + +В примере на рис. \hrf{pic:int-overflow} показана попытка присвоить значение 5000000000 переменной типа \code{long}. Из текста ошибки ясно, что невозможно положить такое большое значение в переменную типа \code{int}, а это значит, что справа \code{int}. Почему большой \code{int} без проблем присваивается к маленькому байту? + +\begin{figure}[H] + \centering + \includegraphics[width=12cm]{jc-02-float-overflow.png} + \caption{Решение проблемы переполнения числовых констант} + \label{pic:overflow-solution} +\end{figure} + +На рис. \hrf{pic:overflow-solution} продемонстрировано, что аналогичная ситуация возникает с типами \code{float} и \code{double}. Все дробные числа, написанные в коде - это \code{double}, поэтому положить их во \code{float} без дополнительных усилий невозможно. В этих случаях к написанному справа числу нужно добавить явное указание на его тип. Для \code{long} пишем \code{L}, а для \code{float} - \code{f}. Чаще всего \code{L} пишут заглавную, чтобы подчеркнуть, что тип больше, а \code{f} пишут маленькую, чтобы подчеркнуть, что мы уменьшаем тип. Но регистр в этом конкретном случае значения не имеет, можно писать и так и так. + +\subsubsection{Числа с плавающей запятой (точкой)} +Как видно из таблицы \hrf{tab:types}, два из восьми типов не имеют диапазонов значений. Это связано с тем, что диапазоны значений флоута и дабла заключаются не в величине возможных хранимых чисел, а в точности этих чисел после запятой. + +\begin{frm} \info Числа с плавающей запятой в англоязычной литературе называются числа с плавающей точкой (от англ. floating point). Такое различие связано с тем, что в русскоязычной литературе принято отделять дробную часть числа запятой, а в европейской и американской - точкой. \end{frm} + +Хранение чисел с плавающей запятой\footnote{хорошо и подробно, но на С в посте на \href{https://habr.com/ru/post/112953/}{Хабре}.} работает по стандарту IEEE 754 (1985 г). Для работы с числами с плавающей запятой на аппаратурном уровне к обычному процессору добавляют математический сопроцессор (FPU, floating point unit). + +\begin{figure}[H] + \centering + \begin{subfigure}[b]{0.48\textwidth} + \centering + \def\svgwidth{\textwidth} + \input{pics/jc-02-float-struct.pdf_tex} + \caption{double} + \label{pic:float-double} + \end{subfigure} + \hfill + \begin{subfigure}[b]{0.48\textwidth} + \centering + \def\svgwidth{\textwidth} + \input{pics/jc-02-float-struct32.pdf_tex} + \caption{float} + \label{pic:float-float} + \end{subfigure} + \caption{Типы с плавающей запятой} + \label{pic:float-struct} +\end{figure} + +Рисунок \hrf{pic:float-struct} демонстрирует, как распределяются биты в числах с плавающей запятой разных разрядностей, где S - Sign (знак), E - Exponent (8(11) разрядов поля порядка, экспонента), M - Mantissa (23(52) бита мантиссы, дробная часть числа). + +Если попытаться уложить весь стандарт в два предложения, то получится примерно следующее: получить число в соответствующих разрядностях возможно по формулам: +\begin{equation*} + \begin{gathered} + F_{32} = (-1)^S \times 2^{E-127} \times (1 + \frac{M}{2^{23}}) \\ + F_{64} = (-1)^S \times 2^{E-1023} \times (1 + \frac{M}{2^{52}}) + \end{gathered} +\end{equation*} + +\begin{frm} \info Например: + $+0,5 = 2^{-1}$ поэтому, число будет записано как + + \code{0_01111110_00000000000000000000000}, то есть знак $= 0$, мантисса $= 0$, порядок = $127 - 1 = 126$, чтобы получить следующие результаты вычислений: + + $-1^0$ положительный знак, умножить на порядок + + $2^{126-127 = -1} = 0,5$ и умножить на мантиссу + + $1 + 0$. То есть, $-1^0 \times 2^{-1} \times (1 + 0) = 0,5.$ + + Отсюда становится очевидно, что чем сложнее мантисса и чем меньше порядок, тем более точные и интересные числа мы можем получить. +\end{frm} + +Возьмём для примера число $-0,15625$, чтобы понять как его записывать, откинем знак, это будет единица в разряде, отвечающем за знак, и посчитаем мантиссу с порядком. Представим число как положительное и будем от него последовательно отнимать числа, являющиеся отрицательными степенями двойки, чтобы получить максимально близкое к нулю значение. + +\begin{equation*} + \begin{gathered} +2^{1} = 2 \\ 2^{0} = 1.0 \\ 2^{-1} = 0.5 \\ 2^{-2} = 0.25 \\ 2^{-3} = 0.125 \\ 2^{-4} = 0.0625 \\ 2^{-5} = 0.03125 \\ 2^{-6} = 0.015625 \\ 2^{-7} = 0.0078125 \\ 2^{-8} = 0.00390625 + \end{gathered} +\end{equation*} + +Очевидно, что $-1$ и $-2$ степени отнять не получится, поскольку мы явно уходим за границу нуля, а вот $-3$ прекрасно отнимается, значит порядок будет $127-3 = 124$, осталось понять, что получится в мантиссе. + +Видим, что оставшееся после первого вычитания ($0,15625 - 0,125$) число - это $2^{-5}$. Значит в мантиссе пишем \code{01} и остальные нули, то есть слева направо указываем, какие степени после $-3$ будут нужны. $-4$ не нужна, а $-5$ нужна. + +Получится, что +\begin{equation*} + \begin{gathered} +(-1)^1 \times 2^{(124-127)} \times (1 + \frac{2097152}{2^{23}}) = 1,15652 \\ +\text{или, тождественно,}\\ +(-1)^1 \times 1,01e-3 = \\ +1\times2^{-3} + 0\times2^{-4} + 1\times2^{-5} = \\ +1\times0,125 + 0\times0,0625 + 1\times0,03125 = \\ +0,125 + 0,03125 = 0,15625 + \end{gathered} +\end{equation*} + +Так число с плавающей запятой возможно посчитать двумя способами: по приведённой формуле, или последовательно складывая разряды мантиссы умноженные на двойку в степени порядка, уменьшая порядок на каждом шагу. + +\begin{figure}[h] + \centering + \includegraphics[width=17cm]{jc-02-float02.png} + \caption{Особенности работы с числами с плавающей запятой} + \label{pic:float-points} +\end{figure} + +К особенностям работы чисел с плавающей запятой можно отнести: +\begin{itemize} +\item возможен как положительный, так и отрицательный ноль (в целых числах ноль всегда положительный); +\item есть огромная зона, отмеченная на рисунке \hrf{pic:float-points}, которая являет собой непредставимые числа, слишком большие для хранения внутри такой переменной или настолько маленькие, что мнимая единица в мантиссе отсутствует; +\item в таком числе можно хранить значения положительной и отрицательной бесконечности; +\item при работе с такими числами появляется понятие не-числа, при этом важно помнить, что \code{NaN != NaN}. +\end{itemize} + +\subsubsection{Символы и булевы} +Шесть из восьми примитивных типов могут иметь как положительные, так и отрицательные значения, они называются \textbf{«знаковые»} типы. В таблице есть два типа, у которых есть диапазон но нет отрицательных значений, это \code{boolean} и \code{char} + +Булев тип хранит значение \code{true} или \code{false}. На собеседованиях иногда спрашивают, сколько места занимает \code{boolean}. В Java объём хранения не определён и зависит от конкретной JVM, обычно считают, что это один байт. + +\begin{table}[h!] + \centering + \begin{tabular}{||c|c|c||c|c|c||c|c|c||c|c|c||} + \hline + dec & hex & val & dec & hex & val & dec & hex & val & dec & hex & val \\ + \hline + 000 & 0x00 & (nul) & 032 & 0x20 & \textvisiblespace & 064 & 0x40 & @ & 096 & 0x60 & \textquoteleft \\ + 001 & 0x01 & (soh) & 033 & 0x21 & ! & 065 & 0x41 & A & 097 & 0x61 & a \\ + 002 & 0x02 & (stx) & 034 & 0x22 & " & 066 & 0x42 & B & 098 & 0x62 & b \\ + 003 & 0x03 & (etx) & 035 & 0x23 & \# & 067 & 0x43 & C & 099 & 0x63 & c \\ + 004 & 0x04 & (eot) & 036 & 0x24 & \$ & 068 & 0x44 & D & 100 & 0x64 & d \\ + 005 & 0x05 & (enq) & 037 & 0x25 & \% & 069 & 0x45 & E & 101 & 0x65 & e \\ + 006 & 0x06 & (ack) & 038 & 0x26 & \& & 070 & 0x46 & F & 102 & 0x66 & f \\ + 007 & 0x07 & (bel) & 039 & 0x27 & \textquotesingle & 071 & 0x47 & G & 103 & 0x67 & g \\ + 008 & 0x08 & (bs) & 040 & 0x28 & ( & 072 & 0x48 & H & 104 & 0x68 & h \\ + 009 & 0x09 & (tab) & 041 & 0x29 & ) & 073 & 0x49 & I & 105 & 0x69 & i \\ + 010 & 0x0A & (lf) & 042 & 0x2A & * & 074 & 0x4A & J & 106 & 0x6A & j \\ + 011 & 0x0B & (vt) & 043 & 0x2B & + & 075 & 0x4B & K & 107 & 0x6B & k \\ + 012 & 0x0C & (np) & 044 & 0x2C & \textquoteright & 076 & 0x4C & L & 108 & 0x6C & l \\ + 013 & 0x0D & (cr) & 045 & 0x2D & - & 077 & 0x4D & M & 109 & 0x6D & m \\ + 014 & 0x0E & (so) & 046 & 0x2E & . & 078 & 0x4E & N & 110 & 0x6E & n \\ + 015 & 0x0F & (si) & 047 & 0x2F & / & 079 & 0x4F & O & 111 & 0x6F & o \\ + 016 & 0x10 & (dle) & 048 & 0x30 & 0 & 080 & 0x50 & P & 112 & 0x70 & p \\ + 017 & 0x11 & (dc1) & 049 & 0x31 & 1 & 081 & 0x51 & Q & 113 & 0x71 & q \\ + 018 & 0x12 & (dc2) & 050 & 0x32 & 2 & 082 & 0x52 & R & 114 & 0x72 & r \\ + 019 & 0x13 & (dc3) & 051 & 0x33 & 3 & 083 & 0x53 & S & 115 & 0x73 & s \\ + 020 & 0x14 & (dc4) & 052 & 0x34 & 4 & 084 & 0x54 & T & 116 & 0x74 & t \\ + 021 & 0x15 & (nak) & 053 & 0x35 & 5 & 085 & 0x55 & U & 117 & 0x75 & u \\ + 022 & 0x16 & (syn) & 054 & 0x36 & 6 & 086 & 0x56 & V & 118 & 0x76 & v \\ + 023 & 0x17 & (etb) & 055 & 0x37 & 7 & 087 & 0x57 & W & 119 & 0x77 & w \\ + 024 & 0x18 & (can) & 056 & 0x38 & 8 & 088 & 0x58 & X & 120 & 0x78 & x \\ + 025 & 0x19 & (em) & 057 & 0x39 & 9 & 089 & 0x59 & Y & 121 & 0x79 & y \\ + 026 & 0x1A & (eof) & 058 & 0x3A & : & 090 & 0x5A & Z & 122 & 0x7A & z \\ + 027 & 0x1B & (esc) & 059 & 0x3B & ; & 091 & 0x5B & [ & 123 & 0x7B & \char`\{ \\ + 028 & 0x1C & (fs) & 060 & 0x3C & < & 092 & 0x5C & \char`\\ & 124 & 0x7C & | \\ + 029 & 0x1D & (gs) & 061 & 0x3D & = & 093 & 0x5D & ] & 125 & 0x7D & \char`\} \\ + 030 & 0x1E & (rs) & 062 & 0x3E & > & 094 & 0x5E & \^{} & 126 & 0x7E & \~{} \\ + 031 & 0x1F & (us) & 063 & 0x3F & ? & 095 & 0x5F & \char`\_ & 127 & 0x7F & \code{\DEL} \\ + \hline + \end{tabular} + \caption{Фрагмент UTF-8 (ASCII) таблицы} + \label{table:utf-8-ascii} +\end{table} + +Тип \code{char} единственный беззнаковый целочисленный тип в языке, то есть его старший разряд хранит полезное значение, а не признак положительности. Тип целочисленный но по умолчанию среда исполнения интерпретирует его как символ по таблице utf-8 (см фрагмент в таблице \hrf{table:utf-8-ascii}). В языке Java есть разница между одинарными и двойными кавычками. В одинарных кавычках всегда записывается символ, который на самом деле является целочисленным значением, а в двойных кавычках всегда записывается строка, которая фактически является экземпляром класса \code{String}. Поскольку типизация строгая, то невозможно записать в \code{char} строки, а в строки числа. + +\begin{frm} \info В Java есть три основных понятия, связанных с данными переменными и использованием значений: объявление, присваивание, инициализация. + + Для того чтобы \textit{объявить} переменную, нужно написать её тип и название, также часто вместо названия можно встретить термин идентификатор. + + Далее в любой момент можно \textit{присвоить} этой переменной значение, то есть необходимо написать идентификатор использовать оператор присваивания и справа написать значение, которое вы хотите присвоить данной переменной, поставить в конце строки точку с запятой. + + Также существует понятие \textit{инициализации} - это когда объединяются на одной строке объявление и присваивание.\end{frm} + +\subsubsection{Преобразование типов} +Java - это язык со строгой статической типизацией, но преобразование типов в ней всё равно есть. Простыми словами, преобразование типов - это когда компилятор видит, что типы переменных по разные стороны присваивания разные, начинает разрешать это противоречие. Преобразование типов бывает явное и неявное. + +\begin{frm} +\info В разговоре или в сообществах можно услышать или прочитать термины тайпкастинг, кастинг, каст, кастануть, и другие производные от английского typecasting. +\end{frm} + +Неявное преобразование типов происходит, когда присваиваются числа переменным меньшей размерности, чем \code{int}. Число справа это \code{int}, а значит 32 разряда, а слева, например, \code{byte}, и в нём всего 8 разрядов, но ни среда ни компилятор не поругались, потому что значение в большом \code{int} не превысило 8 разрядов маленького \code{byte}. Итак неявное преобразование типов происходит в случаях, когда, «всё и так понятно». В случае, если неявное преобразование невозможно, статический анализатор кода выдаёт ошибку, что ожидался один тип, а был дан другой. + +Явное преобразование типов происходит, когда мы явно пишем в коде, что некоторое значение должно иметь определённый тип. Этот вариант приведения типов тоже был рассмотрен, когда к числам дописывались типовые квалификаторы \code{L} и \code{f}. Но чаще всего случается, что происходит присваивание переменным не тех значений, которые были написаны в тексте программы, а те, которые получились в результате каких-то вычислений. +\begin{figure}[H] + \centering + \includegraphics[width=12cm]{jc-02-byte-cast-error.png} + \caption{Ошибка приведения типов} + \label{pic:byte-cast-error} +\end{figure} + +На рис. \hrf{pic:byte-cast-error} приведён простейший пример, в котором очевидно, что внутри переменной \code{i0} содержится значение, не превышающее одного байта хранения, а значит возможно явно сообщить компилятору, что значение точно поместится в \code{byte}. \textit{Явно преобразовать типы}. Для этого нужно в правой части оператора присваивания перед идентификатором переменной в скобках добавить название типа, к которому необходимо преобразовать значение этой переменной. +\begin{figure}[H] + \centering + \includegraphics[width=12cm]{jc-02-byte-cast-fix.png} + \caption{Верное приведение типов} + \label{pic:byte-cast-error} +\end{figure} + +\subsubsection{Константность} +Constare - (лат. стоять твёрдо). Константность это свойство неизменяемости. В Java ключевое слово \code{const} не реализовано, хоть и входит в список ключевых, зарезервированных. Константы создаются при помощи ключевого слова \code{final}. Ключевое слово файнал возможно применять не только с примитивами, но и со ссылочными типами, методами, классами. + +\begin{frm} +\info Константа - это переменная или идентификатор с конечным значением. +\end{frm} + +\subsubsection{Задания для самопроверки} +\begin{enumerate} +\item длдлдл +\end{enumerate} \subsection{Базовый функционал языка} \subsubsection{Математические операторы} @@ -177,68 +401,6 @@ \end{document} -% таблица «Основные типы данных» & целочисленных типов аж 4 и они занимают 1,2,4,8 байт соответственно. про чар, несмотря на то, что он целочисленный мы поговорим чуть позднее. с четырьмя основными целочисленными типами всё просто - значения в них могут быть только целые, никак и никогда невозможно присвоить им дробных значений, хотя и тут можно сделать оговорку и поклон в сторону арифметики с фиксированной запятой, но мы этого делать не будем, чтобы не взрывать себе мозг и не сбиваться с основной мысли. итак, целочисленные типы с диапазонами минус 128 плюс 127, минус 32768 плюс 32767, я никогда не запомню что там после минус и плюс 2млрд, и четвёртый, который лично я никогда даже не давал себе труд дочитать до конца - -% про эти типы важно помнить два факта: инт - это самый часто используемый тип, если сомневаетесь, какой использовать, используйте инт. все числа, которые вы пишете в коде - это инты, даже если вы пытаетесь их присвоить переменной другого типа - -% Я вот сказал, что инт самый часто используемый и внезапно подумал: а ведь на практике, чаще всего, было бы достаточно шорта, например, в циклах, итерирующихся по подавляющему большинству коллекций, или при хранении значений, скажем, возраста человека, но всё равно все по привычке используют инт \\ \hline - -% byte b = 120; byte b1 = 200; & Теперь плавно подошли к тому что все написанное нами в коде программы цифры - это по умолчанию интеджеры, а дробные даблы, и становится достаточно интересно как они преобразуются например в меньше типы. Тут все просто - если мы пишем цифрами справа число, которое может поместиться в меньший тип слева то статический анализатор кода его пропустит, а компилятор преобразует в меньший тип автоматически. Как мы видим, к маленькому байту вполне успешно присваивается инт. получается, обманул, сказав, что все числа это инты? - -% если же мы пишем число которое больше типа слева и соответственно поместиться не может, среда разработки нам выдает сообщение о том что произойдёт переполнение и вообще невозможно положить так много в такой маленький контейнер. А в предупреждении компилятора мы видим, что ожидался байт, а даём мы инт. \\ \hline - -% лайвкод в котором нужно показать попытку присвоения лонга, показать предупреждения среды & Интересное начинается когда мы хотим записать в виде числа какое-то значение большее чем может принимать инт, и явно присвоить начальное значение переменной типа лонг. давайте посмотрим на следующий пример - попытку присвоить значение 5 млрд переменной типа лонг. помним, что в лонге можно хранить очень большие числа, мы то явно видим, что слева лонг и точно знаем что присваиваемое значение в него поместится, но среду и компилятор это почему-то мало волнует, значит и тут наврал? давайте разбираться по порядку: если мы посмотрим на ошибку, там английскими буквами будет очень понятно написано - не могу положить такое большое значение в переменную типа инт. а это может значить только одно: справа - инт. не соврал. Почему большой инт без проблем присваивается к маленькому байту? поговорм буквально через несколько минут, пока просто запомним, что это происходит \\ \hline - -% \code{long l0 = 3_000_000_000L; float f = 0.123f;} & Аналогичная ситуация с флоутами и даблами. Все дробные числа, написанные в коде - это даблы, поэтому положить их во флоут без дополнительных плясок с бубном невозможно по понятной причине, они туда не помещаются. В этих случаях к написанному справа числу нужно добавить явное указание на его тип, то есть мы как бы говорим компилятору, что мы точно уверены, что справа большой лонг (или маленький флоут, в зависимости от контекста). Это уводит нас в сторону разговора о преобразовании типов, опять же, поговорим об этом через несколько минут, чтобы не отвлекаться от хранения примитивов. Просто запоминаем, что для лонга пишем Л а для флоута ф. Чаще всего л пишут заглавную, чтобы подчеркнуть, что тип большой, а ф пишут маленькую, чтобы подчеркнуть, что мы уменьшаем тип. но регистр значения не имеет, можно писать и так и так.\\ \hline - -% Слайд & Далее речь пойдёт о том, что называется числами с плавающей запятой. в англоязычной литературе эти числа называются числа с плавающей точкой (от английского флоутин поинт), такое различие связано с тем, что в русскоязычной литературе принято отделять дробную часть числа запятой, а в европейской и американской - точкой. - -% Как мы видим, два из восьми типов не имеют диапазонов значений, это связано с тем, что диапазоны значений флоута и дабла заключаются не в величине возможных хранимых чисел, а в точности этих чисел после запятой. до какого знака будет сохранена точность. Говорить о числах с плавающей точкой и ничего не сказать об особенности их хранения - преступление, поэтому, снова немного отвлечёмся на общее развитие, несколько минут поговорим не о джаве, а о компьютерах в целом. \\ \hline - -% много хорошо и подробно, но на С https://habr.com/ ru/post/112953/ \includegraphics[width=30mm]{../pics/jc-02-float01.png} & Работает по стандарту IEEE 754 (1985 года). Для работы с числами с плавающей запятой на аппаратурном уровне к обычному процессору который находится в вашем устройстве ещё прикручивают математический сопроцессор, он нужен, чтобы постоянно вычислять эти ужасные плавающие запятые. Если попытаться уложить весь стандарт в два предложения, то получится примерно следующее: формат подразумевает три поля (знак, 8(11) разрядов поля порядка, 23(52) бита мантисса). Чтобы получить из этой битовой каши число надо $-1$ возвести в степень знака, умножить на 2 в степени порядка минус 127 и умножить на 1 + мантиссу делёную на два в степени размера мантиссы. Формула на экране, она не очень сложная. В остальном, ничего не понятно, но очень интересно, понимаю, давайте попробуем на примере. \\ \hline - -% возьмём число +0,5 & с ним всё довольно просто, чтобы получить $+0,5$ нужно 2 возвести в $-1$ степень. поэтому, если развернуть обратно формулу, описанную выше, в знак и мантиссу мы ничего не пишем, оставляем 0, а в порядке должно быть 126, тогда мы должны будем $-1$ возвести в 0ю степень и получить положительный знак, умножить на 2 в степени $126-127 = -1$, получив внезапно 0,5 и умножить на 1 плюс пустая мантисса, в которой по сути не очень важно, что делить, что умножать и в какие степени возводить, всё равно 0 будет. Отсюда становится очевидно, что чем сложнее мантисса и чем меньше порядок, тем более точные и интересные числа мы можем получить. \\ \hline - -% а что если -0,15625 & Попробуем немного сложнее: число $-0,15625$, чтобы понять как его записывать, откинем знак, это будет единица в разряде, отвечающем за знак, и посчитаем мантиссу с порядком. представим число как положительное и будем от него последовательно отнимать числа, являющиеся отрицательными степенями двойки, чтобы получить максимально близкое к нулю значение \\ \hline - -% $2^{1} = 2$ $2^{0} = 1.0$ $2^{-1} = 0.5$ $2^{-2} = 0.25$ $2^{-3} = 0.125$ $2^{-4} = 0.0625$ $2^{-5} = 0.03125$ $2^{-6} = 0.015625$ $2^{-7} = 0.0078125$ $2^{-8} = 0.00390625$ & получается, что $-1$ и $-2$ степени отнять не получится, мы явно уходим за границу нуля, а вот $-3$ прекрасно отнимается, значит порядок будет $127-3 = 124$, осталось понять, что получается в мантиссе. видим, что оставшееся после первого вычитания число - это 2 в $-5$ степени. значит в мантиссе мы пишем 01 и остальные нули, то есть слева направо указываем, какие степени после $-3$ будут нужны. $-4$ не нужна, а $-5$ нужна. Получится, что \\ \hline - -% $(-1)^1 \times 2^{(124-127)} \times (1 + \frac{2097152}{2^{23}}) = 1,15652$ -% \vspace{1em} -% $(-1)^1 \times 1,01e-3 = 1\times2^{-3} + 0\times2^{-4} + 1\times2^{-5} = 1\times0,125 + 0\times0,0625 + 1\times0,03125 = 0,125 + 0,03125 = 0,15625$ & так наше число можно посчитать двумя способами: по приведённой на слайде формуле или последовательно складывая разряды мантиссы умноженные на двойку в степени порядка, уменьшая порядок на каждом шагу, как это показано на слайде \\ \hline - -% Особенности \includegraphics[width=30mm]{../pics/jc-02-float02.png} & Ну, что, поковырялись в детальках и винтиках, можно коротко поговорить об особенностях чисел с плавающей точкой, а именно: в числах с плавающей точкой бывает как положительный, так и отрицательный ноль, в отличие от целых чисел, где ноль всегда положительный; у чисел с плавающей запятой есть огромная зона, отмеченная на слайде, которая являет собой непредставимые числа слишком большие для хранения внутри такой переменной или настолько маленькие, что мнимая единица в мантиссе отсутствует; в таком числе можно хранить значения положительной и отрицательной бесконечности; при работе с такими числами появляется понятие не-числа, при этом важно помнить, что NaN != NaN, а если очень сильно постараться, можно хранить там собственные данные, но это выходит далеко за пределы курса, и используется в каких-нибудь чрезвычайно маломощных процессорах для цифровой обработки сигналов, например \\ \hline - -% Проблемы \includegraphics[width=30mm]{../pics/jc-02-float03.png} & у чисел с плавающей запятой могут иногда встречаться и проблемы в вычислениях, пример на слайде чрезвычайно грубый, но при работе, например, со статысячными или миллионными долями во флоуте, с такой проблемой вполне можно столкнуться. порядок выполнения действий может влиять на результат выполнения этих действий, что противоречит математике \\ \hline - -% Слайд & Задание для самопроверки: \\ \hline - -% таблица «Основные типы данных» & Казалось бы, это было так давно, но вернёмся к нашей таблице с примитивными типами данных. Что ещё важного мы видим в этой таблице? шесть из восьми примитивных типов могут иметь как положительные, так и отрицательные значения они называются одним словом «знаковые» типы. Можно заметить что в таблице есть два типа, у которых есть диапазон но нет отрицательных значений, это булин и чар. По порядку с простого, булев тип хранит тру и фолс, тут я вам ничего нового не скажу, на собесах иногда спрашивают сколько места он занимает, в Java объём хранения не определён и зависит от конкретной жвм, обычно считают, что это байт, несмотря на то что хватит и бита, но тогда значительно усложнятся алгоритмы хранения и доступа в коллекциях, но беседа об этом ведёт нас в сложные дебри оптимизации адресации памяти и прочих регистровых алгоритмов и структур данных \\ \hline - -% таблица UTF-8 & Что касается чара я нахожу его самым интересным примитивным типом данных. Он единственный беззнаковый целочисленный тип в языке, то есть его старший разряд хранит полезное значение, а не признак положительности. Тип целочисленный но по умолчанию среда исполнения интерпретирует его как символ по таблице utf-8. Таблицу несложно найти в интернете и хранимое в чаре число является индексом в этой таблице, а значит совершенно точно не может быть отрицательным \\ \hline - -% Слайд & Вы конечно же об этом уже знаете но именно сейчас важно дополнительно упомянуть о том что в языке Java есть разница между одинарными и двойными кавычками. В одинарных кавычках мы всегда записываем символ который на самом деле является целочисленным значением а в двойных кавычках мы всегда записываем строку, которая фактически является экземпляром класса стринг. Поскольку типизация строгая то мы не можем записывать в чары строки а в строки числа \\ \hline - -% Слайд & С типизации вроде разобрались давайте разберёмся с основными понятиями чтобы больше в них никогда не путаться в Java как и в любом другом языке программирования есть три основных понятия, связанных с данными переменными и использованием значений. это объявление присваивание инициализация. Для того чтобы объявить переменную нужно написать её тип и название также часто вместо названия можно встретить термин идентификатор. Далее в любой момент можно присвоить этой переменной значение то есть необходимо написать идентификатор использовать оператор присваивания, который выглядит как обычный знак равенства и справа написать значение которое вы хотите присвоить данной переменной, поставить в конце строки точку с запятой. статический анализатор кода автоматически проверит соответствие типов и при выполнении программы значение будет присвоено. Также существует понятие инициализации - это когда объединяются на одной строке объявление и присваивание. Всё довольно просто и прозрачно. \\ \hline - -% преобразование типов & джава это язык со строгой статической типизацией, но преобразование типов в ней всё равно есть. прямо сейчас нам имеет смысл поговорить о преобразовании примитивных типов. преобразование типов - это когда компилятор видит, что типы переменных по разные стороны присваивания разные, помнит, что типизация статическая, и надо как-то решать это противоречие. В разговоре или в сообществах можно услышать термины тайпкастинг, кастинг, каст, кастануть, и другие производные от англ тайпкастинг.\\ \hline - -% Слайд & Преобразование типов бывает явное и неявное. Начнём с более простого, неявного. Неявное преобразование типов мы с вами уже даже могли заметить, когда присваивали числа всяким маленьким переменным. Припоминаем,что число справа это инт, а значит 32 разряда, а слева было что-то небольшое, например, байт, и в нём всего 8 разрядов, но ни среда ни компилятор на нас не поругались. потому что значение в большом инте не превысило 8 разрядов маленького байта, и компилятор решил, что раз уж у него все числа в тексте программы инты - нет смысла ругаться на пользователя, он всё равно ничего не исправит. \\ \hline - -% Слайд & Итак неявное преобразование типов происходит в случаях, когда, если можно так выразиться, всё и так понятно. В случае, если неявное преобразование невозможно, статический анализатор кода выдаёт нам ошибку, что ожидался один тип, а мы даём другой. \\ \hline - -% Слайд & Явное преобразование типов - это когда мы прям пишем в коде, что такая-то переменная должна иметь такой-то тип. Этот вариант типизации мы уже тоже видели, когда дописывали к лонгу Л а к флоуту ф. Но чаще всего случается, что мы присваиваем переменным не те значения, которые пишем в тексте программы, а те, которые получились в результате каких-то вычислений. И часто эти результаты вычислений хранятся в более больших переменных. \\ \hline - -% int i = 10; byte b = i; & вот простейший пример, мы совершенно точно уверены, что внутри переменной ай лежит значение не превышающее байт по хранению, и допустим, что точно знаем, что по нашим бизнес-задачам ни в каких вычислениях никогда не сможет это значение превысить, а значит мы можем явно сообщить компилятору, что значение точно поместится в байт. явно преобразовать типы. \\ \hline - -% byte b = (byte)i ; & для явного преобразования типов нужно в правой части оператора присваивания перед идентификатором переменной в скобках добавить название типа, к которому мы хотим преобразовать значение этой переменной Преобразование типов, очевидно, затрагивает не только примитивные типы, но и ссылочные, но не будем забегать вперёд, пока остановимся на этом. \\ \hline - -% константность & Последнее о примитивах на сегодня - это константность. поскольку мало кто сегодня хорошо умеет в латынь скажу, констаре - это глагол, означающий стоять твёрдо. а значит для математики и языков программирования константность это свойство неизменяемости. в джаве ключевое слово конст не реализовано, хоть и входит в список ключевых. константы же можно создавать при помощи ключевого слова final, что решает довольно забавный парадокс терминологии, ведь от программистов на других языках часто можно часто услышать словосочетание константная переменная, а здесь прямой перевод говорит, что это переменная с конечным значением.\\ \hline - -% Слайд & Конечно, ключевое слово файнал возможно применять не только с примитивами, но и со ссылочными типами, методами, классами, но как и в случае с преобразованием типов - не будем забегать вперёд. Пока просто запомним - переменная или идентификатор с конечным значением, именно такая формулировка нам поможет с константностью объектов. \\ \hline - -% Слайд & Задание для самопроверки: \\ \hline - % Слайд & Разобравшись с примитивными типами данных мы можем переходить к ссылочным помните я в самом начале говорил что есть два больших вида данных примитивные и Ссылочное вот примитивных восемь а ссылочные это все остальные и это скорее хорошая новость чем плохая потому что не надо запоминать их бесконечные названия. \\ \hline % Слайд & Самым простым из ссылочных типов является массив. фактически массив выведен на уровень языка и не имеет специального ключевого слова как названия хотя если копнуть гораздо глубже то можно увидеть что у него есть внутреннее название слово эррэй с большой буквы обрамлённое двумя символами нижнего подчёркивания с каждой стороны. Не буду утомлять вас скучной частью о назначении массива и тем что там хранятся наборы однотипных данных, сразу к делу. \\ \hline diff --git a/pics/jc-02-byte-cast-error.png b/pics/jc-02-byte-cast-error.png new file mode 100644 index 0000000..e67e486 Binary files /dev/null and b/pics/jc-02-byte-cast-error.png differ diff --git a/pics/jc-02-byte-cast-fix.png b/pics/jc-02-byte-cast-fix.png new file mode 100644 index 0000000..55803dc Binary files /dev/null and b/pics/jc-02-byte-cast-fix.png differ diff --git a/pics/jc-02-byte-overflow.png b/pics/jc-02-byte-overflow.png new file mode 100644 index 0000000..c1da50a Binary files /dev/null and b/pics/jc-02-byte-overflow.png differ diff --git a/pics/jc-02-float-overflow.png b/pics/jc-02-float-overflow.png new file mode 100644 index 0000000..c1dec15 Binary files /dev/null and b/pics/jc-02-float-overflow.png differ diff --git a/pics/jc-02-float-struct.pdf b/pics/jc-02-float-struct.pdf new file mode 100644 index 0000000..efc60e9 Binary files /dev/null and b/pics/jc-02-float-struct.pdf differ diff --git a/pics/jc-02-float-struct.pdf_tex b/pics/jc-02-float-struct.pdf_tex new file mode 100644 index 0000000..49190f6 --- /dev/null +++ b/pics/jc-02-float-struct.pdf_tex @@ -0,0 +1,69 @@ +%% Creator: Inkscape 1.2.1 (9c6d41e4, 2022-07-14), www.inkscape.org +%% PDF/EPS/PS + LaTeX output extension by Johan Engelen, 2010 +%% Accompanies image file 'jc-02-float-struct.pdf' (pdf, eps, ps) +%% +%% To include the image in your LaTeX document, write +%% \input{.pdf_tex} +%% instead of +%% \includegraphics{.pdf} +%% To scale the image, write +%% \def\svgwidth{} +%% \input{.pdf_tex} +%% instead of +%% \includegraphics[width=]{.pdf} +%% +%% Images with a different path to the parent latex file can +%% be accessed with the `import' package (which may need to be +%% installed) using +%% \usepackage{import} +%% in the preamble, and then including the image with +%% \import{}{.pdf_tex} +%% Alternatively, one can specify +%% \graphicspath{{/}} +%% +%% For more information, please see info/svg-inkscape on CTAN: +%% http://tug.ctan.org/tex-archive/info/svg-inkscape +%% +\begingroup% + \makeatletter% + \providecommand\color[2][]{% + \errmessage{(Inkscape) Color is used for the text in Inkscape, but the package 'color.sty' is not loaded}% + \renewcommand\color[2][]{}% + }% + \providecommand\transparent[1]{% + \errmessage{(Inkscape) Transparency is used (non-zero) for the text in Inkscape, but the package 'transparent.sty' is not loaded}% + \renewcommand\transparent[1]{}% + }% + \providecommand\rotatebox[2]{#2}% + \newcommand*\fsize{\dimexpr\f@size pt\relax}% + \newcommand*\lineheight[1]{\fontsize{\fsize}{#1\fsize}\selectfont}% + \ifx\svgwidth\undefined% + \setlength{\unitlength}{210.78195154bp}% + \ifx\svgscale\undefined% + \relax% + \else% + \setlength{\unitlength}{\unitlength * \real{\svgscale}}% + \fi% + \else% + \setlength{\unitlength}{\svgwidth}% + \fi% + \global\let\svgwidth\undefined% + \global\let\svgscale\undefined% + \makeatother% + \begin{picture}(1,0.41203482)% + \lineheight{1}% + \setlength\tabcolsep{0pt}% + \put(-0.00233506,0.2961197){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l}63\end{tabular}}}}% + \put(0.10452934,0.29606801){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l}62\end{tabular}}}}% + \put(0.38925456,0.29603656){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l}51\end{tabular}}}}% + \put(0.06898476,0.36731193){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l}S\end{tabular}}}}% + \put(0.26305811,0.36743369){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l}E\end{tabular}}}}% + \put(0.67384536,0.36726328){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l}M\end{tabular}}}}% + \put(0.07064691,0.20173741){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l}1\end{tabular}}}}% + \put(0.25213532,0.20313959){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l}11\end{tabular}}}}% + \put(0.67681651,0.20337675){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l}52\end{tabular}}}}% + \put(0.38933048,0.11840811){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l}1,\end{tabular}}}}% + \put(0.47718254,0.04702366){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l}64\end{tabular}}}}% + \put(0,0){\includegraphics[width=\unitlength,page=1]{jc-02-float-struct.pdf}}% + \end{picture}% +\endgroup% diff --git a/pics/jc-02-float-struct.svg b/pics/jc-02-float-struct.svg new file mode 100644 index 0000000..ef1b85e --- /dev/null +++ b/pics/jc-02-float-struct.svg @@ -0,0 +1,202 @@ + + + + + + + + + + 63 + 62 + 51 + S + E + M + 1 + 11 + 52 + 1, + 64 + + + + + + + + diff --git a/pics/jc-02-float-struct32.pdf b/pics/jc-02-float-struct32.pdf new file mode 100644 index 0000000..d366595 Binary files /dev/null and b/pics/jc-02-float-struct32.pdf differ diff --git a/pics/jc-02-float-struct32.pdf_tex b/pics/jc-02-float-struct32.pdf_tex new file mode 100644 index 0000000..034cd45 --- /dev/null +++ b/pics/jc-02-float-struct32.pdf_tex @@ -0,0 +1,69 @@ +%% Creator: Inkscape 1.2.1 (9c6d41e4, 2022-07-14), www.inkscape.org +%% PDF/EPS/PS + LaTeX output extension by Johan Engelen, 2010 +%% Accompanies image file 'jc-02-float-struct32.pdf' (pdf, eps, ps) +%% +%% To include the image in your LaTeX document, write +%% \input{.pdf_tex} +%% instead of +%% \includegraphics{.pdf} +%% To scale the image, write +%% \def\svgwidth{} +%% \input{.pdf_tex} +%% instead of +%% \includegraphics[width=]{.pdf} +%% +%% Images with a different path to the parent latex file can +%% be accessed with the `import' package (which may need to be +%% installed) using +%% \usepackage{import} +%% in the preamble, and then including the image with +%% \import{}{.pdf_tex} +%% Alternatively, one can specify +%% \graphicspath{{/}} +%% +%% For more information, please see info/svg-inkscape on CTAN: +%% http://tug.ctan.org/tex-archive/info/svg-inkscape +%% +\begingroup% + \makeatletter% + \providecommand\color[2][]{% + \errmessage{(Inkscape) Color is used for the text in Inkscape, but the package 'color.sty' is not loaded}% + \renewcommand\color[2][]{}% + }% + \providecommand\transparent[1]{% + \errmessage{(Inkscape) Transparency is used (non-zero) for the text in Inkscape, but the package 'transparent.sty' is not loaded}% + \renewcommand\transparent[1]{}% + }% + \providecommand\rotatebox[2]{#2}% + \newcommand*\fsize{\dimexpr\f@size pt\relax}% + \newcommand*\lineheight[1]{\fontsize{\fsize}{#1\fsize}\selectfont}% + \ifx\svgwidth\undefined% + \setlength{\unitlength}{210.49484152bp}% + \ifx\svgscale\undefined% + \relax% + \else% + \setlength{\unitlength}{\unitlength * \real{\svgscale}}% + \fi% + \else% + \setlength{\unitlength}{\svgwidth}% + \fi% + \global\let\svgwidth\undefined% + \global\let\svgscale\undefined% + \makeatother% + \begin{picture}(1,0.41259683)% + \lineheight{1}% + \setlength\tabcolsep{0pt}% + \put(-0.00370222,0.2965236){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l}31\end{tabular}}}}% + \put(0.10330794,0.29647184){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l}30\end{tabular}}}}% + \put(0.38842151,0.29644035){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l}22\end{tabular}}}}% + \put(0.06771487,0.36781293){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l}S\end{tabular}}}}% + \put(0.26205294,0.36793486){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l}E\end{tabular}}}}% + \put(0.6734005,0.36776422){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l}M\end{tabular}}}}% + \put(0.06937929,0.20201257){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l}1\end{tabular}}}}% + \put(0.25111525,0.20341667){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l}8\end{tabular}}}}% + \put(0.6763757,0.20365416){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l}23\end{tabular}}}}% + \put(0.38849754,0.11856962){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l}1,\end{tabular}}}}% + \put(0.47646943,0.0470878){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l}32\end{tabular}}}}% + \put(0,0){\includegraphics[width=\unitlength,page=1]{jc-02-float-struct32.pdf}}% + \end{picture}% +\endgroup% diff --git a/pics/jc-02-float-struct32.svg b/pics/jc-02-float-struct32.svg new file mode 100644 index 0000000..c264d71 --- /dev/null +++ b/pics/jc-02-float-struct32.svg @@ -0,0 +1,202 @@ + + + + + + + + + + 31 + 30 + 22 + S + E + M + 1 + 8 + 23 + 1, + 32 + + + + + + + + diff --git a/pics/jc-02-float02.png b/pics/jc-02-float02.png index 22f112b..a7ee60c 100644 Binary files a/pics/jc-02-float02.png and b/pics/jc-02-float02.png differ diff --git a/pics/jc-02-int-overflow.png b/pics/jc-02-int-overflow.png new file mode 100644 index 0000000..138e130 Binary files /dev/null and b/pics/jc-02-int-overflow.png differ diff --git a/settings/main-style-preamble.tex b/settings/main-style-preamble.tex index 9ae5327..ae1d932 100644 --- a/settings/main-style-preamble.tex +++ b/settings/main-style-preamble.tex @@ -2,11 +2,11 @@ \usepackage{graphicx} \usepackage{xcolor,colortbl}% http://ctan.org/pkg/xcolor \usepackage{titlesec} -\usepackage{tikz} \usepackage{indentfirst} \usepackage{datetime2} \usepackage{geometry,lscape} \usepackage{enumitem} +\usepackage{caption,subcaption} \usepackage{multicol,multirow} \usepackage{float,adjustbox} \usepackage{fontawesome} @@ -19,6 +19,7 @@ \usepackage{booktabs}% http://ctan.org/pkg/booktabs \newcommand{\tabitem}{~~\llap{\textbullet}~~} \usepackage{setspace,fontspec} +\usepackage{amsmath} \spacing{1.15} \babelfont{rm}{IBM Plex Sans} @@ -30,15 +31,6 @@ \makeindex \makenomenclature -\newcounter{slidenum} -\setcounter{slidenum}{1} % set to 2 if want to exclude title page of presentation -\newcommand{\showslide}[1]{ - \noindent\makebox[\linewidth]{\rule{.90\paperwidth}{1.4pt}} - \begin{center} - \framebox{\includegraphics[page=\arabic{slidenum},width=.85\textwidth]{#1}} - \stepcounter{slidenum} - \end{center} -} \newcommand\hrf[1]{\hyperref[#1]{\ref{#1}}} \newcommand\hRf[1]{\hyperref[#1]{\nameref{#1}}} \newcommand{\wordcount}{\input{/tmp/wordcount.tex}}