-3

I'm new to swift (using swift 2.2) and I'm seeing an issue where 200.23 - 200 is shown to be equal to 0.2299999999999898. I know that computers can't represent irrational numbers accurately, but I don't understand why a rational number is also not being represented correctly. This is affecting the output numbers generated by my program, leading to issues.

Here's a sample playground code (a very simple version of part of my actual code) showing this behavior:

var number:Double = 200.23                //Number I'm testing

var left: Double = floor(number) // Extracting integer part
var right: Double = number-left // Extracting fraction part

In the above code I'm defining a number and then extracting its whole and fractional parts. The fractional part should be 0.23, however it's shown as 0.2299999999999898 in swift's playground.

Similarly, if I change the original number from 200.23 to 100.23, then the fractional part is shown to be 0.230000000000004

How can I solve this issue ?

EDIT:

I've been asked about the context of this problem. I'm designing a statistics app that uses numbers a lot and actually has a small builtin calculator too. So if I user tries to calculate 200.23 - 0.23 and sees anything other than 0.23, he's gonna be surprised!

Ahmad
  • 12,886
  • 30
  • 93
  • 146
  • 1
    As I've stated above, I already know of the floating point issue. But how can I work around it ? Surely all the software written today somehow manage to deal with this issue. – Ahmad Jul 12 '16 at 03:40
  • 2
    "I know that computers can't represent irrational numbers accurately, but I don't understand why a rational number is also not being represented correctly." That's not true: computers can't represent *all* rational numbers accurately. And decimal notation (humans) can't notate irrational numbers properly either. –  Jul 12 '16 at 03:41
  • Just use integers, 1.23 means 123, 836.92 means 83692 – Kametrixom Jul 12 '16 at 03:42
  • You "work around it" by comparing within limits. E.g., `if (right > 0.23-EPS && right < 0.23+EPS)` or similar (where `EPS` is something like your double floating point precision; could be `1e-7`, or perhaps `1e-15`). –  Jul 12 '16 at 03:42
  • So does that mean I'm supposed to accept this issue with Swift ? Java manages to solve similar issues partially using `BigDecimal`. I'm wondering if Swift has something similar. – Ahmad Jul 12 '16 at 03:42
  • Your question would make more sense if you state what the context is; what is the actual, underlying problem you're trying to solve? –  Jul 12 '16 at 03:44
  • 1
    Please edit question instead of adding comments. It is very unclear at this point what you are looking for (and what considered "known" from the post's point of view). – Alexei Levenkov Jul 12 '16 at 03:45
  • (Side note: if you do know what is going on why you call it "rounding error" when there is no rounding at all?) – Alexei Levenkov Jul 12 '16 at 03:46
  • Dude calm down, I only replied here because others posted their comments here too. I'll move my edit to the post, even though I don't think it will help with this problem. – Ahmad Jul 12 '16 at 03:46
  • The problem with a computer's representation of numbers is not just with irrational vs. rational, but with the internal (most likely binary) representation and the decimal representation you're viewing. – ThomasW Jul 12 '16 at 04:15
  • *"How can I solve this issue?"* What issue do you want to solve, and what do you consider to be an acceptable solution? You seem to be aware that IEEE-754 floating-point numbers cannot represent every real number, including some simple ones (when written in base 10). However, it's not clear what solution you're seeking. Is you question "How can I do base-10 floating point math?" Is it "Can I use arbitrary precision arithmetic in Swift?" Is it something else? – Cornstalks Jul 12 '16 at 04:15
  • 1
    See also [What's the correct number type for financial variables in Swift?](http://stackoverflow.com/questions/36059688/whats-the-correct-number-type-for-financial-variables-in-swift). – Martin R Jul 12 '16 at 04:17
  • 3
    If you want decimal arithmetic, use [`NSDecimalNumber`](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSDecimalNumber_Class/). – rob mayoff Jul 12 '16 at 04:18
  • let value = String(format:"%.2f",right) let dValue = Double.init(value) – Christian Abella Jul 12 '16 at 04:22

1 Answers1

0

To round the values stored in the variable right just use the round() function. To specify the precision just do this

var number:Double = 200.23                

var left: Double = floor(number) 
var right: Double = number-left 

let roundedValue = round(right*100)/100 // Answer will be 0.23
ebby94
  • 3,131
  • 2
  • 23
  • 31
  • 1
    rounding offers an approximation solution which unfortunately doesn't work for me because rounding can sometimes lead to incorrect answers (when testing extreme cases), and also requires me to dynamically figure out what approximation I need for a given calculation, which has its own burden. Thanks for suggesting an answer though. – Ahmad Jul 12 '16 at 06:56