为什么将整数字符串转换为浮点数和双精度型会产生不同的结果?


let n = "77777777"
let i = Int(n)!
let f = Float(n)!
let d = Double(n)!
print(i)
print(f)
print(d)
print(Int(f))
print(Int(d))

生产:

77777777

7.777778e+07

77777777.0

77777776

77777777

为什么?使用 Xcode 11、Swift 5。这个问题看起来很相似,但它以十进制数开头,而不是整数。此外,这里实际上没有浮点数学。

好的,请查看 https://www.h-schmidt.net/FloatConverter/IEEE754.html 的浮点转换器。 它显示了以二进制和十六进制表示形式输入数字时存储的位,并为您提供由于转换而导致的错误。 问题在于数字在标准中的表示方式。 在浮点数中,误差确实是 -1。

实际上,7777777277777780范围内的任何数字都为您提供77777776尾数的内部表示。

数字存储在有限的内存中。无论您是否进行浮点运算,您都需要一种方法在二进制内存中对十进制数进行编码。只要你有有限的内存(即总是在现实世界中),你必须选择把你的位花在高范围或高精度上,或者两者之间的一些权衡。

超过 7 位数字会让您进入Float权衡的第一个"领域"。你可以"做到",但有一个权衡:在这么高的幅度下,你会失去一些精度。在这种情况下,整数四舍五入到最接近的 10。

Float是单精度 IEEE 754 浮点数。它的第一个"权衡"区域是16,777,217.从016,777,216,每个整数都是可精确表示的。之后,没有足够的精度来指定一个数字到2^0(一,又名单位)。下一个最好的办法是正确地表示它,直到最接近的2^1(二)。

看看这个:

import Foundation
for originalInt in 16_777_210 ... 16_777_227 {
let interMediateFloat = Float(originalInt)
let backAsInt = Int(interMediateFloat)
print("(originalInt) -> (backAsInt)")
}
print("n...n")
for originalInt in 33_554_430 ... 33_554_443 {
let interMediateFloat = Float(originalInt)
let backAsInt = Int(interMediateFloat)
print("(originalInt) -> (backAsInt)")
}

指纹:

16777210 -> 16777210
16777211 -> 16777211
16777212 -> 16777212
16777213 -> 16777213
16777214 -> 16777214
16777215 -> 16777215
16777216 -> 16777216 // Last precisely representable whole number
16777217 -> 16777216 // rounds down
16777218 -> 16777218 // starts skipping by 2s
16777219 -> 16777220
16777220 -> 16777220
16777221 -> 16777220
16777222 -> 16777222
16777223 -> 16777224
16777224 -> 16777224
16777225 -> 16777224
16777226 -> 16777226
16777227 -> 16777228
...
33554430 -> 33554430
33554431 -> 33554432
33554432 -> 33554432
33554433 -> 33554432
33554434 -> 33554432 // Last whole number representable to the closest "two"
33554435 -> 33554436 // rounds up
33554436 -> 33554436
33554437 -> 33554436 // starts skipping by 4s
33554438 -> 33554440
33554439 -> 33554440
33554440 -> 33554440
33554441 -> 33554440
33554442 -> 33554440
33554443 -> 33554444

等等。随着量级变大,整数的表示精度越来越低。在极端情况下,最大的整数值(340,282,346,638,528,859,811,704,183,484,516,925,440)和第二大整数值(340,282,326,356,119,256,160,033,759,537,265,639,424)相差20,282,409,603,651,670,423,947,251,286,016(2^104)。

表达如此高的数字的能力恰恰是以无法精确存储该数量级周围的许多数字为代价的。发生舍入。或者,像 SwiftInt这样的二进制整数对整数具有完美的精度(始终存储到正确的整数/单位),但为此付出的最大大小要小得多(只有2,147,483,647有符号Int32)。

最新更新