Skip to content

Commit 1d18068

Browse files
committed
Clean-up floating point tutorial.
1 parent e9eb7b6 commit 1d18068

File tree

1 file changed

+28
-23
lines changed

1 file changed

+28
-23
lines changed

Doc/tutorial/floatingpoint.rst

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ decimal value 0.1 cannot be represented exactly as a base 2 fraction. In base
5050

5151
Stop at any finite number of bits, and you get an approximation. On most
5252
machines today, floats are approximated using a binary fraction with
53-
the numerator using the first 53 bits following the most significant bit and
53+
the numerator using the first 53 bits starting with the most significant bit and
5454
with the denominator as a power of two. In the case of 1/10, the binary fraction
5555
is ``3602879701896397 / 2 ** 55`` which is close to but not exactly
5656
equal to the true value of 1/10.
@@ -230,12 +230,8 @@ as ::
230230
and recalling that *J* has exactly 53 bits (is ``>= 2**52`` but ``< 2**53``),
231231
the best value for *N* is 56::
232232

233-
>>> 2**52
234-
4503599627370496
235-
>>> 2**53
236-
9007199254740992
237-
>>> 2**56/10
238-
7205759403792794.0
233+
>>> 2**52 <= 2**56 // 10 < 2**53
234+
True
239235

240236
That is, 56 is the only value for *N* that leaves *J* with exactly 53 bits. The
241237
best possible value for *J* is then that quotient rounded::
@@ -250,14 +246,13 @@ by rounding up::
250246
>>> q+1
251247
7205759403792794
252248

253-
Therefore the best possible approximation to 1/10 in 754 double precision is
254-
that over 2\*\*56, or ::
249+
Therefore the best possible approximation to 1/10 in 754 double precision is::
255250

256-
7205759403792794 / 72057594037927936
251+
7205759403792794 / 2 ** 56
257252

258253
Dividing both the numerator and denominator by two reduces the fraction to::
259254

260-
3602879701896397 / 36028797018963968
255+
3602879701896397 / 2 ** 55
261256

262257
Note that since we rounded up, this is actually a little bit larger than 1/10;
263258
if we had not rounded up, the quotient would have been a little bit smaller than
@@ -269,24 +264,34 @@ above, the best 754 double approximation it can get::
269264
>>> 0.1 * 2 ** 55
270265
3602879701896397.0
271266

272-
If we multiply that fraction by 10\*\*60, we can see the value of out to
273-
60 decimal digits::
267+
If we multiply that fraction by 10\*\*55, we can see the value out to
268+
55 decimal digits::
274269

275-
>>> 3602879701896397 * 10 ** 60 // 2 ** 55
270+
>>> 3602879701896397 * 10 ** 55 // 2 ** 55
276271
1000000000000000055511151231257827021181583404541015625
277272

278-
meaning that the exact number stored in the computer is approximately equal to
279-
the decimal value 0.100000000000000005551115123125. Rounding that to 17
280-
significant digits gives the 0.10000000000000001 that Python displays (well,
281-
will display on any 754-conforming platform that does best-possible input and
282-
output conversions in its C library --- yours may not!).
273+
meaning that the exact number stored in the computer is equal to
274+
the decimal value 0.1000000000000000055511151231257827021181583404541015625.
275+
Instead of displaying the full decimal value, many languages (including
276+
older versions of Python), round the result to 17 significant digits::
277+
278+
>>> format(0.1, '.17f')
279+
'0.10000000000000001'
283280

284281
The :mod:`fractions` and :mod:`decimal` modules make these calculations
285282
easy::
286283

287284
>>> from decimal import Decimal
288285
>>> from fractions import Fraction
289-
>>> print(Fraction.from_float(0.1))
290-
3602879701896397/36028797018963968
291-
>>> print(Decimal.from_float(0.1))
292-
0.1000000000000000055511151231257827021181583404541015625
286+
287+
>>> Fraction.from_float(0.1)
288+
Fraction(3602879701896397, 36028797018963968)
289+
290+
>>> (0.1).as_integer_ratio()
291+
(3602879701896397, 36028797018963968)
292+
293+
>>> Decimal.from_float(0.1)
294+
Decimal('0.1000000000000000055511151231257827021181583404541015625')
295+
296+
>>> format(Decimal.from_float(0.1), '.17')
297+
'0.10000000000000001'

0 commit comments

Comments
 (0)