Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 为什么Int(Float(Int.max))给我一个错误?_Swift_Floating Point_Type Conversion - Fatal编程技术网

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

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

我观察到一些非常奇怪的东西。如果在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
大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位长)。