1

I am trying to round a number in swift, and I found a solution using this:

func roundTo(number: Double, precision: Int) -> Double {
    var power: Double = 1
    for _ in 1...precision {
        power *= 10
    }
    let rounded = Double(round(power * number)/power)
    return rounded
}

I have a model class, lets call it MyObject.

class: My Object {
    var preciseNumber: Double?
}

I am fetching a number for example:

var myNumber = 10,0123456789

I use my roundTo function to round it so I have 10,0123456 (7 numbers after the decimal point).

When I print a statement:

print("myNumber rounded: \(roundTo(myNumber, precision: 7))") //10,0123456 as a result. Great!

Then next I want to assing rounded myNumber to my class variable preciseNumber so:

let roundedNumber = roundTo(myNumber, precise: 7)
print("Rounded number is: \(roundedNumber)") // 10,01234567 as result
self.preciseNumber = roundedNumber
print("Precise number is now: \(self.preciseNumber)") // 10,01234599999997 as result

What might be causing this? I want to be as precise as possible.

rmaddy
  • 298,130
  • 40
  • 468
  • 517
Ancinek
  • 3,279
  • 3
  • 28
  • 70
  • What makes you think it *isn't* as precise as possible? (Look up "roundoff-error".) – Scott Hunter May 18 '16 at 18:02
  • Because I want to then compare this preciseNumber to another number which is for example 10,123456 and not 10,123459999. What I get is false instead of true – Ancinek May 18 '16 at 18:07
  • See http://stackoverflow.com/questions/588004/is-floating-point-math-broken and https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html. – 10,123456 *cannot* be represented exactly as a `Double`. – Martin R May 18 '16 at 18:10
  • Thanks guys for the hints. There is always something new to learn that I have not even heard of. I was trying to get use of the Google Maps Markers with their coordinates and it helped me a lot :) – Ancinek May 18 '16 at 18:17
  • Try `print(String(format:"%.15f", roundedNumber))` to see that none of your numbers is *exactly* 10.0123457. – Martin R May 18 '16 at 18:20

1 Answers1

1

So it sounds like your issue is being able to compare floating point numbers. The best way to do this is to instead find the degree of precision you need. So rather than just checking numOne == numTwo use something like abs(one - two) <= 0.000001

You can create a Swift operator to handle this for you pretty easily:

// `===` is just used as an example
func === (one: Double, two: Double) -> Bool {
    return abs(one - two) <= 0.000001
}

Then you can just check numOne === numTwo and it will use a better floating point equality check.


There is also a power function that will help simplify your rounding function:

let power = pow(10.0, precision)
Firo
  • 14,960
  • 3
  • 50
  • 73
  • 1
    It is much safer to use `pow` instead of `powf` in Swift. `pow` is overloaded for `Float`, `Double` and `CGFloat`. `powf` exists only for `Float`. – Sulthan May 18 '16 at 18:25