Martin R 的回答显示了正确的方法,但我仍在写这篇文章,以了解“幕后”发生了什么。
Double 的有限精度意味着只有在Int64.max 和Int64.min 的量级上,Double 表示只能用于每个4,096 整数。结果,有一组整数,它们是有效的,并且在Int64 的范围内,在(有损)转换为 Double 之后,最终舍入到一个不再可以表示为Int64 的大小。为了考虑这些值,我们需要确保我们只接受Double(Self.min).nextUp ... Double(Self.max).nextDown,而不是Double(Self.min)... Double(Self.max)
Int.min -9,223,372,036,854,775,808
Float(Int.min) -9,223,372,036,854,780,000 lower than Int.min by 4096, thus not representable by Int
Float(Int.min).nextUp -9,223,371,487,098,960,000 greater than Int.min by 549,755,820,032, thus representable by Int
Int.max +9,223,372,036,854,775,807
Float(Int.max) +9,223,372,036,854,780,000 greater than Int.max by 4096, thus not representable by Int
Float(Int.max).nextDown +9,223,371,487,098,960,000 lower than Int.max by 549,755,820,032, thus representable by Int
这就是实际的样子
import Foundation
extension FixedWidthInteger {
static var representableDoubles: ClosedRange<Double> {
return Double(Self.min).nextUp ... Double(Self.max).nextDown
}
init?(safelyFromDouble d: Double) {
guard Self.representableDoubles.contains(d) else { return nil }
self.init(d)
}
}
func formatDecimal(_ d: Double) -> String{
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.positivePrefix = "+"
return numberFormatter.string(from: NSNumber(value: d))!
}
let testCases: [Double] = [
Double.nan,
-Double.nan,
Double.signalingNaN,
-Double.signalingNaN,
Double.infinity,
Double(Int.max),
Double(Int.max).nextDown,
+1,
+0.6,
+0.5,
+0.4,
+0,
-0,
-0.4,
-0.5,
-0.6,
-1,
-1.5,
Double(Int.min).nextUp,
Double(Int.min),
-Double.infinity,
]
for d in testCases {
print("Double: \(formatDecimal(d)), as Int: \(Int(safelyFromDouble: d)as Any)")
}
哪个打印:
Double: NaN, as Int: nil
Double: NaN, as Int: nil
Double: NaN, as Int: nil
Double: NaN, as Int: nil
Double: +∞, as Int: nil
Double: +9,223,372,036,854,780,000, as Int: nil
Double: +9,223,372,036,854,770,000, as Int: Optional(9223372036854774784)
Double: +1, as Int: Optional(1)
Double: +0.6, as Int: Optional(0)
Double: +0.5, as Int: Optional(0)
Double: +0.4, as Int: Optional(0)
Double: +0, as Int: Optional(0)
Double: +0, as Int: Optional(0)
Double: -0.4, as Int: Optional(0)
Double: -0.5, as Int: Optional(0)
Double: -0.6, as Int: Optional(0)
Double: -1, as Int: Optional(-1)
Double: -1.5, as Int: Optional(-1)
Double: -9,223,372,036,854,770,000, as Int: Optional(-9223372036854774784)
Double: -9,223,372,036,854,780,000, as Int: nil
Double: -∞, as Int: nil