【问题标题】:fixed point representation of floating point numbers in SwiftSwift 中浮点数的定点表示
【发布时间】:2023-03-11 12:53:02
【问题描述】:

我试图在 Swift 中准确地表示浮点数。假设我们有一个号码let doubleNumber = 16.756。问题在于实际数字类似于16.7560009。此外,在不同的手机上它是16.7559991,例如,因为处理器的不平等。定点算术应该是这类问题的答案,但我不知道如何在 Swift 中解决它。老实说,其他语言也不行。那么如何在 Swift 中创建浮点数的定点表示呢?

我问的原因是,在跨设备准确模拟物理时,浮点数值的微小差异可能导致完全不同的物理模拟。

【问题讨论】:

  • 你真正想要达到什么目的?您要解决的问题是什么?需要准确表示 1.0 / 3.0 吗?
  • 我编辑了我的问题。
  • “我正在尝试在 Swift 中准确地表示浮点数。” – Float 和 Double 类型已经这样做了。您是否将浮点数与实数混淆了?
  • @user207421 不是重复的。这是在问“我如何快速进行定点算术”,而浮点数只是背景故事。

标签: swift fixed-point


【解决方案1】:

您提供的数字表明您使用的是 Float,而不是 Double。 Float 只有大约 6 位精度,Double 大约有 15 位。记住 CGFloat 是 Fl​​oat 或 Double,所以不要使用它。

Swift 使用 IEEE 754 标准浮点运算。只要您始终使用 Double ,不同处理器之间就不应该有任何区别。

现在有一个非常关键的点:如果不同处理器上的浮点运算之间的细微差别会产生完全不同的模拟,那么这两种模拟都与现实无关,因此完全没用。或者它们都显示了许多可能的结果之一,然后再一次,你显示哪个没有区别。

【讨论】:

  • 由于随着时间的推移(例如每帧的计算,四舍五入/截断),一开始的细微差别会不会在模拟中产生非常不同的结果?
【解决方案2】:

有趣的实验

import Foundation

let f1: Float = 0x1p-149
f1.isZero                       // false
let f0: Float = 0x1p-150
f0.isZero                       // true   
Float(f1 / 2) == Float(f1 / 3)  // true ??? what ??? f1 is zero?

let d1 = 0x1p-1074
d1.isZero                       // false
let d0 = 0x1p-1075
d0.isZero                       // true
d1 / 2 == d1 / 3                // true

print("value of Float next to 0 is \(f1) or as Double \(Double(f1))")
print("value of Double next to 0 is \(d1)")

/*

value of Float next to 0 is 1.4013e-45 or as Double 1.40129846432482e-45
value of Double next to 0 is 4.94065645841247e-324

*/

我推荐给所有需要进行浮点计算的人 What Every Computer Scientist Should Know About Floating-Point Arithmetic

正确的算法如何减少错误的一个例子

import Foundation

var arr: [Float] = []
for i in 0...100 {
    arr.append(Float(random()))
}

let sum1 = arr.reduce(0.0) { $0 + $1 }

var sum2 = arr[0]
var c:Float = 0.0
for j in 1..<arr.count {
    let y: Float = arr[j] - c
    let t: Float = sum2 + y
    c = t - sum2 - y
    sum2 = t
}
print(sum1, sum2, "and the 'small' difference is:", sum2 - sum1)
// 1.18466e+11 1.18466e+11 and the 'small' difference is: 8192.0

// what do you thing, which one is more precise ?
// sum1 or sum2 ????

// lets try the same with naive Double approach
let sum3 = arr.map{ Double($0) }.reduce(0.0) { $0 + $1 }
print(Double(sum1)-sum3)    // -11268.0
print(Double(sum2)-sum3)    // -3076.0

【讨论】:

  • 你能补充一些为什么这应该有效的细节吗?纯代码答案不是很有用,可能会被删除。
  • @Cristik 这不是如何执行定点算术的答案。这个 sn-ps 可以回答为什么我的迭代从未停止或类似的问题。看看行 d1 / 2 == d1 / 3 是真的,即使 d1(如你在打印输出中看到的)不是零
  • 在这种情况下,请更新答案并添加有关实验结果的解释,在当前形式下,您的答案对提问者没有太大帮助。
  • @Cristik 第二个例子是否更好地解释了为什么正确的算法如此重要?在代码中正确使用时,即使浮点数的精度也足够好。我的示例中的两种算法都是这样做的。第一个是简单的 sum1,第二个是更精确的 sum2。看看那里的区别!即使我在这里收到很多反对票,但需要执行准确计算的人可以看到我的示例很有价值。物理计算是关于分析可能的错误,而不是关于固定浮点计算
  • 我认为您的答案的原始修订版是造成否决票的原因 - “有趣的实验”后跟一些代码。您通过 cmets 添加的解释很有价值,您也应该将它们添加到答案中。人们并不总是阅读 cmets。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-11
  • 2015-08-10
  • 2016-05-17
  • 2020-09-03
相关资源
最近更新 更多