Swift 为什么Int(Float(Int.max))给我一个错误?
我观察到一些非常奇怪的东西。如果在Swift中运行此代码:Swift 为什么Int(Float(Int.max))给我一个错误?,swift,floating-point,type-conversion,Swift,Floating Point,Type Conversion,我观察到一些非常奇怪的东西。如果在Swift中运行此代码: Int(Float(Int.max)) 它会崩溃,并显示错误消息: 致命错误:无法将浮点值转换为Int,因为结果将大于Int.max 这真的是违反直觉的,所以我将表达式扩展为3行,并尝试查看操场中每一步发生的情况: let a = Int.max let b = Float(a) let c = Int(b) 它与相同的消息崩溃。这次,我看到a是9223372036854775807,b是9.223372e+18。显然,a比b大36
Int(Float(Int.max))
它会崩溃,并显示错误消息:
致命错误:无法将浮点值转换为Int,因为结果将大于Int.max
这真的是违反直觉的,所以我将表达式扩展为3行,并尝试查看操场中每一步发生的情况:
let a = Int.max
let b = Float(a)
let c = Int(b)
它与相同的消息崩溃。这次,我看到a
是9223372036854775807,b
是9.223372e+18。显然,a
比b
大36854775807。我也知道浮点是不准确的,所以我希望小于Int.max
,最后几位是0
我还尝试了双倍,它也崩溃了
然后我想,也许这就是浮点数的行为,所以我在Java中测试了同样的东西:
long a = Long.MAX_VALUE;
float b = (float)a;
long c = (long)b;
System.out.println(c);
它打印预期的9223372036854775807
swift有什么问题?转换“过大”浮点时,swift和Java的行为不同
将数字转换为整数。Java截断任何浮点值
大于Long.MAX_值=2^63-1
:
long c = (long)(1.0E+30f);
System.out.println(c);
// 9223372036854775807
Swift期望该值在Int
范围内,并中止
在运行时异常情况下,否则:
/// Creates a new instance by rounding the given floating-point value toward
/// zero.
///
/// - Parameter other: A floating-point value. When `other` is rounded toward
/// zero, the result must be within the range `Int.min...Int.max`.
public init(_ value: Float)
例如:
let c = Int(Float(1.0E30))
print(c)
// fatal error: Float value cannot be converted to Int because the result would be greater than Int.max
您的值Float(Int.max)
也是如此,它是
最接近Int.max的浮点表示值
若要大于Int.max
,Double
或Float
的尾数中没有足够的位来准确表示19
有效位,因此您将得到一个四舍五入的结果
如果使用字符串(格式:)
打印浮点值
,则可以看到更精确的浮点值表示形式
:
let a = Int.max
print(a) // 9223372036854775807
let b = Float(a)
print(String(format: "%.1f", b)) // 9223372036854775808.0
因此,由Float
表示的值1
大于Int.max
许多值将转换为相同的Float
值。问题是,在产生不同的Double
或Float
值之前,您需要减少多少Int.max
以双倍开头
:
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
是错误的
评论中的后续问题:
如果float没有足够的位来表示Int.max,那么它是如何表示的呢 能代表一个比这更大的数字吗 浮点数表示为两部分:尾数和指数。尾数表示有效数字(二进制),指数表示2的幂。因此,浮点数可以通过尾数为1并带有表示幂的指数来精确表示偶数幂2 不是2的偶数幂的数字可能有一个二进制模式,其中包含的数字比尾数中所能表示的数字还要多。这是
Int.max
(2^63-1)的情况,因为在二进制中,它是111111111111111111111111111
(63 1)。32位的浮点
不能存储63位的尾数,因此必须对其进行舍入或截断。在Int.max
的情况下,四舍五入1得到值
10000000000000000000000000000000000000000000000000
。从左边开始,尾数只表示1个有效位(尾随的0
是免费的),因此这个数字是1
的尾数和64的指数
请参阅@MartinR的答案以了解Java所做的解释。Java只是在Double/Float-to-long转换中截断,例如(long)(1.0E100)
也计算为9223372036854775807。如果Float没有足够的位来表示Int.max
,它如何能够表示大于该值的数字1?@Sweeper,这是一个很好的问题。我将更新我的答案。@Sweeper它可以简单地用1的尾数和63的指数来存储它–因此1*2^63。但是,2^63-1(Int64.max
)的位模式是63个重复1s,因此需要四舍五入才能存储(因为Float
只有32位长)。