swift - 为什么 Int(Float(Int.max)) 给我一个错误?

标签 swift floating-point type-conversion

我观察到一些非常奇怪的事情。如果您在 Swift 中运行此代码:

Int(Float(Int.max))

它崩溃并显示错误消息:

fatal error: Float value cannot be converted to Int because the result would be greater than Int.max

这确实是违反直觉的,所以我将表达式扩展为 3 行,并尝试在 playground 中查看每一步发生的情况:

let a = Int.max
let b = Float(a)
let c = Int(b)

它崩溃并显示相同的消息。这次,我看到 a 是 9223372036854775807,b 是 9.223372e+18。很明显 ab 大了 36854775807。我也明白 float 是不准确的,所以我期望小于 Int.max,最后几位为 0。

我也用 Double 试过了,它也崩溃了。

然后我想,也许这就是 float 的行为方式,所以我在 Java 中测试了同样的事情:

long a = Long.MAX_VALUE;
float b = (float)a;
long c = (long)b;
System.out.println(c);

它打印出预期的 9223372036854775807!

swift 有什么问题?

最佳答案

DoubleFloat 的尾数中没有足够的位来准确表示 19 有效数字,因此您得到四舍五入的结果。

如果使用 String(format:) 打印 Float,您可以看到 Float 值的更准确表示:

let a = Int.max
print(a)                          // 9223372036854775807
let b = Float(a)
print(String(format: "%.1f", b))  // 9223372036854775808.0

所以Float表示的值比Int.max1


许多值将被转换为相同的 Float 值。现在的问题是,在产生不同的 DoubleFloat 值之前,您必须减少多少 Int.max

Double 开头:

var y = Int.max

while Double(y) == Double(Int.max) {
    y -= 1
}

print(Int.max - y)  // 512

因此对于 Double,最后的 512 Int 都转换为相同的 Double

Float 用于表示值的位数较少,因此有更多值都映射到相同的 Float。切换到 - 1000 以便它在合理的时间内运行:

var y = Int.max

while Float(y) == Float(Int.max) {
    y -= 1000
}

print(Int.max - y)  // 274877907000

因此,您对 Float 可以准确表示特定 Int 的期望是错误的。


跟进评论中的问题:

If float does not have enough bits to represent Int.max, how is it able to represent a number one larger than that?

float 由两部分表示:尾数和指数。尾数表示有效数字(二进制​​),指数表示 2 的幂。因此, float 可以通过尾数 1 和表示幂的指数来准确表示 2 的偶次幂。

甚至不是 2 的幂的数字可能有一个二进制模式,其中包含比尾数中可以表示的更多的数字。 Int.max(即 2^63 - 1)就是这种情况,因为在二进制中是 1111111111111111111111111111111111111111111111111111111111111(63 个 1)。 32 位的 Float 不能存储 63 位的尾数,因此必须对其进行舍入或截断。在 Int.max 的情况下,向上舍入 1 的结果是值 100000000000000000000000000000000000000000000000000000000000000。从左边开始,只有 1 个有效位要用尾数表示(后面的 0 是免费的),所以这个数是 1 的尾数和 64 的指数。

有关 Java 正在做什么的解释,请参阅@MartinR 的回答。

关于swift - 为什么 Int(Float(Int.max)) 给我一个错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43706635/

相关文章:

ios - 如果应用是通过触摸推送启动的,有没有办法等待应用的主页面完成加载后运行代码?

swift - 是否可以在结构复制期间排除某些属性(如类类型)被复制?

ios - 淡出 UIRefreshControl 或将其从透明 ScrollView 中隐藏

c - 我应该如何获得浮点值的小数部分?

从 32 位地址转换为 64 位整数会产生意外结果

ios - swift search Bar和navigation bar启动后隐藏

floating-point - 将浮点范围转换/量化为整数范围

javascript - 有没有办法在 Javascript 中 chop 科学记数法?

c# - .Net Standard 1.6 中的 TypeConverter 替代方案

c++ - 将自定义整数包装器转换为 boolean 值