|
37 | 37 | You can jump right to the next section.}%
|
38 | 38 | %
|
39 | 39 | The first part, the so-called \pgls{significand} or \pgls{mantissa}, consists of 52~bits, represents the digits of the number.
|
40 |
| -52~bits can represent $52\log_2 10\approx 15$~decimal digits, meaning that we can represent numbers to a precision of about 15~digits. |
| 40 | +52~bits can represent $52\log_2 10\approx 15$~to 16~decimal digits, meaning that we can represent numbers to a precision of about 15~digits. |
41 | 41 | If we would just use 52~bits, then this would limit us to represent numbers maybe from~$0$ to~$2^{52}-1$ at a resolution of~$1$.
|
42 | 42 | Of course, we could also choose some other resolution, say~$0.001$.
|
43 | 43 | In this case, we could represent numbers from~$0$ to $0.001*(2^{52}-1)$ and the smallest non-zero number would be~$0.001$ instead of~$1$.
|
|
143 | 143 | \centering%
|
144 | 144 | \begin{tabular}{r@{}r@{{\color{orange}\textbf{e}}}l@{~~$\equiv$~~}r@{}l}%
|
145 | 145 | \multicolumn{2}{c}{$\beta$}&$\gamma$&\multicolumn{2}{c}{$\alpha$}\\\hline%
|
146 |
| -&\texttt{A.BCDEFG}{\dots}&\texttt{\color{red}{+}}\texttt{HIJ}&&$\texttt{A.BCDEFG}{\dots}*10^{HIJ}$\\ |
147 |
| -&\texttt{A.BCDEFG}{\dots}&\texttt{\color{red}{-}}\texttt{HIJ}&&$\texttt{A.BCDEFG}{\dots}*10^{{\color{red}{-}}HIJ}$\\ |
148 |
| -{\color{blue}{-}}&\texttt{A.BCDEFG}{\dots}&\texttt{\color{red}{+}}\texttt{HIJ}&${\color{blue}{-}}$&$\texttt{A.BCDEFG}{\dots}*10^{HIJ}$\\ |
149 |
| -{\color{blue}{-}}&\texttt{A.BCDEFG}{\dots}&\texttt{\color{red}{-}}\texttt{HIJ}&${\color{blue}{-}}$&$\texttt{A.BCDEFG}{\dots}*10^{{\color{red}{-}}HIJ}$% |
| 146 | +&\texttt{A.BCDEFG}{\dots}&\texttt{\color{red}{+}}\texttt{HIJ}&&$\texttt{A.BCDEFG}{\dots}*{\color{orange}10}^{HIJ}$\\ |
| 147 | +&\texttt{A.BCDEFG}{\dots}&\texttt{\color{red}{-}}\texttt{HIJ}&&$\texttt{A.BCDEFG}{\dots}*{\color{orange}10}^{{\color{red}{-}}HIJ}$\\ |
| 148 | +{\color{blue}{-}}&\texttt{A.BCDEFG}{\dots}&\texttt{\color{red}{+}}\texttt{HIJ}&${\color{blue}{-}}$&$\texttt{A.BCDEFG}{\dots}*{\color{orange}10}^{HIJ}$\\ |
| 149 | +{\color{blue}{-}}&\texttt{A.BCDEFG}{\dots}&\texttt{\color{red}{-}}\texttt{HIJ}&${\color{blue}{-}}$&$\texttt{A.BCDEFG}{\dots}*{\color{orange}10}^{{\color{red}{-}}HIJ}$% |
150 | 150 | \end{tabular}%
|
151 | 151 | %
|
152 | 152 | \caption{The structure of the scientific notation for floating point numbers in \python, which represent a value~$\alpha$ in the form~$\beta*10^{\gamma}$.}%
|
|
212 | 212 | Similarly, \pythonil{0.023e-20} becomes \pythonil{2.3e-22}.
|
213 | 213 | \endhsection%
|
214 | 214 | %
|
| 215 | +\hsection{Limits and Special Floating Point Values: Infinity and \inQuotes{Not a Number}}% |
| 216 | +% |
| 217 | +\begin{figure}% |
| 218 | +\centering% |
| 219 | +\includegraphics[width=0.7\linewidth]{\currentDir/floatMathInConsoleZero}% |
| 220 | +\caption{What happens with very small floating point numbers in \python?}% |
| 221 | +\label{fig:floatMathInConsoleZero}% |
| 222 | +\end{figure}% |
| 223 | +% |
| 224 | +We already learned that the floating point type \pythonil{float} can represent both very small and very large numbers. |
| 225 | +But we also know that it is internally stored as chunk of 64~bits. |
| 226 | +So its range must be somehow finite. |
| 227 | +What happens if we exceed this finite range? |
| 228 | + |
| 229 | +First the easy part: |
| 230 | +Now, we said that \python\ can store very small numbers, like $10^{-300}$ in \pythonil{float} data types. |
| 231 | +But how small really? |
| 232 | +Finding this out from the documentation is actually not so easy. |
| 233 | +Luckily, \pgls{Java} uses the same standard for its class \pythonil{Double}. |
| 234 | +In its documentation~\cite{O2024CD}, we find that the minimum value is~$2^{-1074}$, which is approximately~$4.940\decSep656\decSep458\decSep412\decSep465\decSep44*10^{-324}$. |
| 235 | +So we would expect the smallest possible floating point value in \python\ to also be in this range. |
| 236 | + |
| 237 | +In \cref{fig:floatMathInConsoleInf}, we take a look what happens if we approach this number. |
| 238 | +We use the scientific notation and begin to print the number~\pythonil{1e-323} (which is~$10^{-323}$). |
| 239 | +This number is correctly represented as \pythonil{float} and shows up in the console exactly as we wrote it. |
| 240 | +However, if we go a bit smaller and enter \pythonil{9e-324}, which is~$9*10^{-324}=0.9*10^{-323}$, we find that it again shows up in the console as \pythonil{1e-323}. |
| 241 | +This is because the number is already subnormal~\cite{IEEE2019ISFFPA,H1997IS7FPN}, i.e., uses only a few of the significand bits. |
| 242 | +The full precision of 15~digits is no longer available at this small scale. |
| 243 | +Thus \pythonil{9e-324} and \pythonil{1e-323} map to the same \pythonil{float}. |
| 244 | +Converting this \pythonil{float} to text yields \pythonil{'1e-323'}. |
| 245 | +The same happens for \pythonil{8e-324}, which also maps to \pythonil{1e-323}. |
| 246 | +\pythonil{7e-324}, however, is the same as \pythonil{5e-324}. |
| 247 | +Matter of fact, \pythonil{6e-324}, \pythonil{5e-324}, \pythonil{4e-324}, and \pythonil{3e-324} all map to this same \pythonil{float}. |
| 248 | + |
| 249 | +It turns out that this number is already the smallest \pythonil{float} that can be represented: |
| 250 | +\pythonil{2e-324} simply becomes \pythonil{0.0}. |
| 251 | +This value is simply too small to be represented as a 64~bit / double precision IEEE~Standard 754 floating point number~\cite{IEEE2019ISFFPA,H1997IS7FPN}. |
| 252 | +The text \pythonil{2e-324} that we enter into the \python\ console will therefore be translated to the \pythonil{float}~\pythonil{0.0}. |
| 253 | +The comparison \pythonil{2e-324 == 0.0} therefore results in \pythonil{True}, while \pythonil{3e-324 == 0.0} is still \pythonil{False}. |
| 254 | +So we learned what happens if we try to define very small floating point numbers: |
| 255 | +They become zero. |
| 256 | + |
| 257 | +\begin{figure}% |
| 258 | +\centering% |
| 259 | +\includegraphics[width=0.7\linewidth]{\currentDir/floatMathInConsoleInf}% |
| 260 | +\caption{What happens with very large floating point numbers in \python?}% |
| 261 | +\label{fig:floatMathInConsoleInf}% |
| 262 | +\end{figure}% |
| 263 | + |
| 264 | +But what happens to numbers that are too big for the available range? |
| 265 | +Again, according to the nice documentation of \pgls{Java}, the maximum 64~bit double precision floating point number value is~$(2-2^{-52})*2^{1023}\approx1.797\decSep693\decSep134\decSep862\decSep315\decSep708\dots*10^{308}$. |
| 266 | +We can enter this value as \pythonil{1.7976931348623157e+308} and it indeed prints correctly in \cref{fig:floatMathInConsoleInf}. |
| 267 | +If we step it up a little bit and enter \pythonil{1.7976931348623158e+308}, due to the limited precision, we again get \pythonil{1.7976931348623157e+308}. |
| 268 | +However, if we try entering \pythonil{1.7976931348623159e+308} into the \python\ console, something strange happens: |
| 269 | +The output is \pythonil{inf}. |
| 270 | +\pythonil{-1.7976931348623159e+308} gives us \pythonil{-inf}. |
| 271 | +Multiplying this value by two, i.e., computing \pythonil{-1.7976931348623157e+308 * 2}, still yields \pythonil{-inf}. |
| 272 | +\pythonil{inf} stands for \inQuotes{infinity} or~$\infty$. |
| 273 | +However, it \emph{actually} means \emph{too big to represent as \pythonil{float}}. |
| 274 | +If we enter numbers that are too big or exceed the valid range of \pythonil{float} by multiplication, addition, subtraction, or division, we simply get~\pythonil{inf}. |
| 275 | +This does not actually mean \inQuotes{mathematical infinity,} because, while \pythonil{-1.7976931348623159e+308} is very big, it is not infinitely big. |
| 276 | +It simply means that the number is too big to put it into a 64~bit \pythonil{float}. |
| 277 | + |
| 278 | +Actually, the \pythonil{int} type can represent larger numbers easily.includegraphics |
| 279 | +\pythonil{1.7976931348623157e+308} is equivalent to \pythonil{17_976_931_348_623_157 * 10 ** 292}. |
| 280 | +This prints as a number with many zeros. |
| 281 | +Multiplying it with \pythonil{1.0} yields a \pythonil{float} with value \pythonil{1.7976931348623157e+308}, exactly as expected. |
| 282 | +If we try a number ten times as large, i.e., \pythonil{17_976_931_348_623_157 * 10 ** 293}, this is no problem with the \pythonil{int}. |
| 283 | +But we can no longer convert it to a \pythonil{float} by multiplying with~\pythonil{1.0}. |
| 284 | +Trying to do that with a ten times larger number, i.e., computing \pythonil{17_976_931_348_623_157 * 10 ** 293 * 1.0} leads to an exception: |
| 285 | +The output is \pythonil{OverflowError: int too large to convert to float}. |
| 286 | +An exception terminates the current flow of execution and signals an error. |
| 287 | +We will learn later what exceptions actually are and how to handle them properly. |
| 288 | + |
| 289 | +The important thing to realize is that an overflow of a \pythonil{float} may either lead to the \pythonil{inf} value or to an error that stops your computation from continuing. |
| 290 | +As another example, let us again import the natural logarithm function \pythonil{log} and the Euler's constant~\pythonil{e} from the \pythonil{math} module by doing \pythonil{from math import e, log}. |
| 291 | +We now can compute the natural logrithm from the largest possible \pythonil{float} via \pythonil{log(1.7976931348623157e+308)}. |
| 292 | +We get \pythonil{709.782712893384}. |
| 293 | +Raising~$e$ to this power by doing \pythonil{e ** 709.782712893384} leads to the slightly smaller number~\pythonil{1.7976931348622053e+308} due to the limited precision of the \pythonil{float} type. |
| 294 | +However, if we try to raise~$e$ to a slightly larger power, and, for example, try to do \pythonil{e ** 709.782712893385}, we again face an \pythonil{OverflowError}. |
| 295 | + |
| 296 | +We can also try to divide~1 by the largest \pythonil{float} and do \pythonil{1 / 1.7976931348623157e+308}. |
| 297 | +The result is the very small number \pythonil{5.562684646268003e-309}. |
| 298 | +However, if we divide~1 by \pythonil{1.7976931348623159e+308}, we get~\pythonil{0.0}. |
| 299 | +The reason is that \pythonil{1.7976931348623159e+308} becomes \pythonil{inf} and \pythonil{1 / inf} is~\pythonil{0}. |
| 300 | + |
| 301 | +Finally, \pythonil{inf} also exists as constant in the \pythonil{math} module. |
| 302 | +We can import it via \pythonil{from math import inf}. |
| 303 | +And indeed, since the text \pythonil{1.7976931348623159e+308} is parsed to a \pythonil{float} value of \pythonil{inf}, we find that \pythonil{1.7976931348623159e+308 == inf} yields~\pythonil{True}.% |
| 304 | +% |
| 305 | +\endhsection% |
| 306 | +% |
215 | 307 | \endhsection%
|
216 | 308 | %
|
0 commit comments