0

I'm playing around in swift and trying to retrieve fractional digits from numbers using the remainder operator (modulo) and casting some values back and forth.

So here are some calculated results:

var doubleVal: Double = 6.2
var intVal: Int = 0

doubleVal = Int(doubleVal % Double(Int(doubleVal)) * 10)
println(doubleVal) // 6.2 % 6.0 => 0.2 * 10 = 2 -> expected result printed

val = 6.6

doubleVal = Int(doubleVal % Double(Int(doubleVal)) * 10)
println(doubleVal) // 6.6 % 6.0 => 0.6 * 10 = 5??? -> unexpected result printed

Also

var val: Double = 6.3
var intVal: Int = 0

intVal = Int(val % Double(Int(val)) * 10)
println(intVal) // 6.3 % 6.0 => 0.3 * 10 = 2??? -> unexpected result printed

var val: Double = 10.3
var intVal: Int = 0

intVal = Int(val % Double(Int(val)) * 10)
println(intVal) // 10.3 % 10.0 => 0.3 * 10 = 3 -> expected result printed

Why do the results differ so much from each other? Why does the calculation with 6.3 lead to the unexpected result of 2, while using 10.3 leads to the expected result of 3?

Edit:

I've read this answer and know about the floating point calculations. If you calculate (0.1 + 0.2) * 10 however you'll get 3. Floating point problems happen in "distant" digits. That's what I thought at least.

Let's break it into smaller steps:

var val = 10.6
println(val % Double(Int(val))) -> 0.6
println(val % Double(Int(val)) * 10) -> 6.0
println(Int(val % Double(Int(val)) * 10)) -> 5

I see no "hidden" digits in the "back" but I still get the wrong result. Here another example were I see a digit on the far right and get no error while casting:

var val = 10.3
println(val % Double(Int(val))) -> 0.300000000000001
println(val % Double(Int(val)) * 10) -> 3.00000000000001
println(Int(val % Double(Int(val)) * 10)) -> 3
Community
  • 1
  • 1
ezcoding
  • 2,974
  • 3
  • 23
  • 32
  • floating-point arithmetic is inexact. – The Paramagnetic Croissant Aug 06 '15 at 19:11
  • also http://floating-point-gui.de/ – The Paramagnetic Croissant Aug 06 '15 at 19:12
  • 1
    `val % Double(Int(val)) * 10` Are you sure that the `*10` isn't converting the double into an integer when it's done? resulting in 2.999999 which is 2 after truncating? Try adding a `round()` call – Coding Orange Aug 06 '15 at 19:14
  • I think that printing `val % Double(Int(val))` will show where things become unexpected. – Phillip Mills Aug 06 '15 at 19:16
  • `var val = 10.6; println(Int(val % round((Double(Int(val)))) * 10))` still is 5 – ezcoding Aug 06 '15 at 19:31
  • @ezcoding: It *is* the same problem (and a duplicate). Note that `println()` also *rounds* the output. Try `var val = 10.6 ; println(String(format:"%.15f", val % Double(Int(val)) * 10))` and you'll get 5.999999999999996, not 6.0. Or just `var val = 10.6 ; println(String(format:"%.16f", val))`, which prints 10.5999999999999996. – Martin R Aug 06 '15 at 19:59
  • @ezcoding: *"If you calculate (0.1 + 0.2) * 10 however you'll get 3"* – No. It just looks like it, again because println rounds the output. `println(String(format:"%.16f", (0.1 + 0.2) * 10))` prints 3.0000000000000004. `let x = (0.1 + 0.2) * 10 ; println(x == 3.0)` prints `false`. – Martin R Aug 06 '15 at 20:07

1 Answers1

0

In both cases, the result before converting to Int is "some number very close to 3.0". That number can be a little bit less, a little bit larger, and by pure coincidence be exactly equal to 3.0. Converting to Int drops everything after the decimal point, so if "some number very close to 3.0" happens to be 2.9999999999999999 then the result is 2; if it happens to be 3.000000000000001 then the result is 3.

gnasher729
  • 51,477
  • 5
  • 75
  • 98
  • Why doesn't it print the number very close to 3.0? See my edited answer where 3.000000000000001 is printed. 2.9999999999999999 however never. – ezcoding Aug 06 '15 at 19:27