問(wèn)題描述
我觀察到一些非常奇怪的事情.如果你在 Swift 中運(yùn)行這段代碼:
I observed something really strange. If you run this code in Swift:
Int(Float(Int.max))
它崩潰并顯示錯(cuò)誤消息:
It crashes with the error message:
致命錯(cuò)誤:浮點(diǎn)值無(wú)法轉(zhuǎn)換為 Int,因?yàn)榻Y(jié)果會(huì)大于 Int.max
fatal error: Float value cannot be converted to Int because the result would be greater than Int.max
這真的很違反直覺(jué),所以我將表達(dá)式擴(kuò)展為 3 行,并嘗試查看操場(chǎng)中的每個(gè)步驟會(huì)發(fā)生什么:
This is really counter-intuitive, so I expanded the expression into 3 lines and tried to see what happens in each step in a playground:
let a = Int.max
let b = Float(a)
let c = Int(b)
它崩潰并顯示相同的消息.這一次,我看到 a
是 9223372036854775807 而 b
是 9.223372e+18.很明顯 a
比 b
大 36854775807.我也知道浮點(diǎn)數(shù)是不準(zhǔn)確的,所以我期望小于 Int.max
,最后幾位為0.
It crashes with the same message. This time, I see that a
is 9223372036854775807 and b
is 9.223372e+18. It is obvious that a
is greater than b
by 36854775807. I also understand that floating points are inaccurate, so I expected something less than Int.max
, with the last few digits being 0.
我也用 Double
試過(guò)這個(gè),它也崩潰了.
I also tried this with Double
, it crashes too.
然后我想,也許這就是浮點(diǎn)數(shù)的行為方式,所以我在 Java 中測(cè)試了同樣的東西:
Then I thought, maybe this is just how floating point numbers behave, so I tested the same thing in Java:
long a = Long.MAX_VALUE;
float b = (float)a;
long c = (long)b;
System.out.println(c);
它打印出預(yù)期的 9223372036854775807!
It prints the expected 9223372036854775807!
swift 有什么問(wèn)題?
What is wrong with swift?
推薦答案
Double
或 Float
的尾數(shù)中沒(méi)有足夠的位來(lái)準(zhǔn)確表示 19
位有效數(shù)字,因此您得到的是四舍五入的結(jié)果.
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.
如果您使用 String(format:)
打印 Float
,您可以看到 Float
值的更準(zhǔn)確表示:
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
所以Float
所代表的值是1
大于Int.max
.
So the value represented by the Float
is 1
larger than Int.max
.
許多值將被轉(zhuǎn)換為相同的 Float
值.問(wèn)題變成了,在導(dǎo)致不同的 Double
或 Float
值之前,您需要減少多少 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.
從Double
開(kāi)始:
var y = Int.max
while Double(y) == Double(Int.max) {
y -= 1
}
print(Int.max - y) // 512
所以使用 Double
,最后的 512
Int
都轉(zhuǎn)換為相同的 Double
.
So with Double
, the last 512
Int
s all convert to the same Double
.
Float
有更少的位來(lái)表示值,因此有更多的值都映射到相同的 Float
.切換到 - 1000
以便它在合理的時(shí)間內(nèi)運(yùn)行:
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
因此,您對(duì) Float
可以準(zhǔn)確表示特定 Int
的期望是錯(cuò)誤的.
So, your expectation that a Float
could accurately represent a specific Int
was misplaced.
從評(píng)論中跟進(jìn)問(wèn)題:
如果float沒(méi)有足夠的位來(lái)表示Int.max,怎么辦能代表比它大一的數(shù)字嗎?
If float does not have enough bits to represent Int.max, how is it able to represent a number one larger than that?
浮點(diǎn)數(shù)表示為兩部分:尾數(shù)和指數(shù).尾數(shù)表示有效數(shù)字(二進(jìn)制??),指數(shù)表示 2 的冪.因此,浮點(diǎn)數(shù)可以準(zhǔn)確地表示 2 的偶數(shù)冪,方法是尾數(shù)為 1,指數(shù)表示冪.
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.
甚至不是 2 的冪的數(shù)字可能具有二進(jìn)制模式,其中包含的數(shù)字多于尾數(shù)中可以表示的數(shù)字.Int.max
(即 2^63 - 1)就是這種情況,因?yàn)樵诙M(jìn)制中是 111111111111111111111111111111111111111111111111111111111111111
(63 個(gè) 1).32 位的 Float
不能存儲(chǔ) 63 位的尾數(shù),因此必須對(duì)其進(jìn)行舍入或截?cái)?在 Int.max
的情況下,向上舍入 1 會(huì)得到值10000000000000000000000000000000000000000000000000000000000000000
.從左邊開(kāi)始,尾數(shù)只有1個(gè)有效位(后面的0
是免費(fèi)的),所以這個(gè)數(shù)是1
的尾數(shù)和 64
的指數(shù).
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
.
請(qǐng)參閱@MartinR 的回答,了解 Java 正在做什么.
See @MartinR's answer for an explanation of what Java is doing.
這篇關(guān)于為什么 Int(Float(Int.max)) 給我一個(gè)錯(cuò)誤?的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!