Reputation: 4589
I am trying to accurately represent floating point numbers in Swift. Let's say that we have a number let doubleNumber = 16.756
. The problem with this is that the actual number is something like 16.7560009
. More over, on different phone it is 16.7559991
for example, because of processor inequalities. Fixed point arithmetic should be the answer to this kind of problems, but I have no idea how to tackle it in Swift. To be honest, nor in other languages. So how do I create fixed point representations of floating point numbers in Swift?
The reason I am asking is that when simulating physics accurately across devices the tiny differences in the value of floating point number can cause completely different physics simulations.
Upvotes: 1
Views: 1682
Reputation: 17544
funny experiment
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
*/
i recommend for everybody who need to perform floating point calculations What Every Computer Scientist Should Know About Floating-Point Arithmetic
one example how proper algorithm can reduce an error
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
Upvotes: -1
Reputation: 52538
The numbers that you gave indicate that you are using Float, and not Double. Float only has about 6 digits precision, Double has about 15. And remember that CGFloat is either Float or Double, so don't use that.
Swift uses IEEE 754 standard floating point arithmetic. There shouldn't be any difference between different processors as long as you use Double consistently.
Now here comes a very crucial point: If slight differences between floating point arithmetic on different processors produce completely different simulations, then neither simulation has anything to do with reality and is therefore completely useless. Or they both show one of many possible outcomes, and then again it makes no difference which one you show.
Upvotes: 5