From Floating Point Arithmetic: Issues and Limitations\Representation Error in The Python Tutorial:
Almost all machines today (November 2000) use IEEE-754 floating point arithmetic, and almost all platforms map Python floats to IEEE-754 “double precision”. 754 doubles contain 53 bits of precision, so on input the computer strives to convert 0.1 to the closest fraction it can of the form J/2**N where J is an integer containing exactly 53 bits.
It's likely that your Python implementation uses the IEEE 754 standard to represent numbers where, loosely, all numbers (except NaN and infinity) are represented as
x = f * 2^e
where f
and e
(you can think of them as the fractional part and the exponent) are integers.
In this case:
1.499999999999999
is represented as 0x3FF7FFFFFFFFFFFB
.
This corresponds to 6755399441055739*2^-52
which is exactly 1.4999999999999988897769753748434595763683319091796875.
1.4999999999999999
is represented as 0x3FF8000000000000
.
This corresponds to 6755399441055744*2^-52
which is exactly 1.5.
The reason that 1.4999999999999999
is represented as 1.5 in Python is because 1.5 is the closest value that can be represented in IEEE 754 to 1.4999999999999999
.
As the standard only represents a finite number of values (it effectively discretises the real number line to a fixed number of points) compromises must be made when a number that does not lie exactly on one of those points.
1.499999999999999
is sandwiched between two numbers that can be represented in IEEE 754 - you can look at it as
6755399441055739*2^-52 is closest to 1.499999999999999 (note that the fractional part is smaller than 0.5, so rounding down is chosen).
Likewise, 1.4999999999999999
is sandwiched between two numbers that can be represented in IEEE 754 - you can look at it as
6755399441055744*2^-52 is closest to 1.4999999999999999 (note that the fractional part is greater than 0.5, so rounding up is chosen) so the IEEE 754 representation equivalent to 1.5 is chosen.
To answer your question, the results are
round(1.499999999999999)
1
and
round(1.4999999999999999)
2
because the second statement is functionally the same as
round(1.5)
2
since 1.4999999999999999
and 1.5
are treated as identical - you can probably confirm this by doing something like
1.4999999999999999 == 1.5
Note: I'll emphasise that this is dependent on the Python implementation that you're running implementing IEEE 754 for its floating-point numbers.