Swe*_*per 5 floating-point type-conversion swift
我发现一些非常奇怪的东西 如果您在Swift中运行此代码:
Int(Float(Int.max))
Run Code Online (Sandbox Code Playgroud)
它与错误消息崩溃:
致命错误:浮点值无法转换为Int,因为结果将大于Int.max
这实际上是违反直觉的,所以我将表达式扩展为3行,并试图了解操场中每个步骤会发生什么:
let a = Int.max
let b = Float(a)
let c = Int(b)
Run Code Online (Sandbox Code Playgroud)
它崩溃了相同的消息.这一次,我看到的a是9223372036854775807,b是9.223372e + 18.很明显,a大于b36854775807.我也明白浮点数是不准确的,所以我期望小于Int.max,最后几位为0.
我也试过这个Double,它也崩溃了.
然后我想,也许这就是浮点数的行为,所以我在Java中测试了同样的东西:
long a = Long.MAX_VALUE;
float b = (float)a;
long c = (long)b;
System.out.println(c);
Run Code Online (Sandbox Code Playgroud)
它打印预期9223372036854775807!
swift出了什么问题?
a的尾数中没有足够的位Double或Float准确表示19有效数字,因此您得到一个舍入结果.
如果您打印Float使用,String(format:)您可以看到更准确的值的表示Float:
let a = Int.max
print(a) // 9223372036854775807
let b = Float(a)
print(String(format: "%.1f", b)) // 9223372036854775808.0
Run Code Online (Sandbox Code Playgroud)
所以由所表示的值Float是1大于Int.max.
许多值将转换为相同的Float值.问题是,Int.max在产生不同Double或Float价值之前,你需要减少多少.
从以下开始Double:
var y = Int.max
while Double(y) == Double(Int.max) {
y -= 1
}
print(Int.max - y) // 512
Run Code Online (Sandbox Code Playgroud)
所以Double,最后的512 Ints都转换为相同的Double.
Float具有较少的位来表示该值,因此有更多的值都映射到相同的值Float.切换到- 1000使其在合理的时间内运行:
var y = Int.max
while Float(y) == Float(Int.max) {
y -= 1000
}
print(Int.max - y) // 274877907000
Run Code Online (Sandbox Code Playgroud)
因此,您对a Float能够准确表示具体情况的期望Int是错误的.
跟进评论中的问题:
如果float没有足够的位来表示Int.max,那么它如何能够代表比这更大的数字呢?
浮点数表示为两部分:尾数和指数.尾数表示有效数字(二进制),指数表示2的幂.结果,浮点数可以通过使尾数为1并且指数表示幂来精确地表示2的偶数幂.
不是2的幂的数字可以具有二进制模式,其包含比在尾数中可以表示的更多的数字.这是Int.max(2 ^ 63 - 1)的情况,因为二进制是111111111111111111111111111111111111111111111111111111111111111(63 1).Float32位的A 不能存储63位的尾数,因此必须进行舍入或截断.在这种情况下Int.max,向上舍入为1会产生该值
1000000000000000000000000000000000000000000000000000000000000000.从左边开始,尾数只有一个有效位(尾随0的是免费的),所以这个数字是尾数1和指数64.
有关Java正在做什么的解释,请参阅@ MartinR的答案.
| 归档时间: |
|
| 查看次数: |
1751 次 |
| 最近记录: |