There aren't enough bits in the mantissa of a Double
or Float
to accurately represent 19
significant digits, so you are getting a rounded result.
If you print the Float
using String(format:)
you can see a more accurate representation of the value of the Float
:
let a = Int.max
print(a) // 9223372036854775807
let b = Float(a)
print(String(format: "%.1f", b)) // 9223372036854775808.0
So the value represented by the Float
is 1
larger than Int.max
.
Many values will be converted to the same Float
value. The question becomes, how much would you have to reduce Int.max
before it results in a different Double
or Float
value.
Starting with Double
:
var y = Int.max
while Double(y) == Double(Int.max) {
y -= 1
}
print(Int.max - y) // 512
So with Double
, the last 512
Int
s all convert to the same Double
.
Float
has fewer bits to represent the value, so there are more values that all map to the same Float
. Switching to - 1000
so that it runs in reasonable time:
var y = Int.max
while Float(y) == Float(Int.max) {
y -= 1000
}
print(Int.max - y) // 274877907000
So, your expectation that a Float
could accurately represent a specific Int
was misplaced.
Follow up question from the comments:
If float does not have enough bits to represent Int.max, how is it
able to represent a number one larger than that?
Floating point numbers are represented as two parts: mantissa and exponent. The mantissa represents the significant digits (in binary) and the exponent represents the power of 2. As a result, a floating point number can accurately express an even power of 2 by having a mantissa of 1 with an exponent that represents the power.
Numbers that are not even powers of 2 may have a binary pattern that contains more digits than can be represented in the mantissa. This is the case for Int.max
(which is 2^63 - 1) because in binary that is 111111111111111111111111111111111111111111111111111111111111111
(63 1's). A Float
which is 32 bits cannot store a mantissa which is 63 bits, so it has to be rounded or truncated. In the case of Int.max
, rounding up by 1 results in the value
1000000000000000000000000000000000000000000000000000000000000000
. Starting from the left, there is only 1 significant bit to be represented by the mantissa (the trailing 0
's come for free), so this number is a mantissa of 1
and an exponent of 64
.
See @MartinR's answer for an explanation of what Java is doing.