3
Welcome to Swift!  Type :help for assistance.
   1> 1 / 3.0
$R0: Double = 0.33333333333333331
   2> 1 % 3
$R1: Int = 1
   3> 1 % 3 / 3.0
$R2: Double = 0.33333333333333331

   4> import Foundation
   5> 1 / 3.0
$R3: Double = 0.33333333333333331
   6> 1 % 3
$R4: Int = 1
   7> 1 % 3 / 3.0
$R5: Int = 0    // this result changes after importing Foundation

Is this a bug or some kind of implicit conversion magic in Swift?

Edit

Another (simpler) way to reproduce this issue:

  1> 1.0 / 3
$R0: Double = 0.33333333333333331
  2> import Foundation
  3> 1.0 / 3
$R1: Int = 0
  4> Double(1.0) / 3    // this is a workaround
$R2: Double = 0.33333333333333331

I can reproduce this issue in an iOS app, not just from the REPL. I am using xcode6-beta5.

Community
  • 1
  • 1
Ethan
  • 18,584
  • 15
  • 51
  • 72
  • Interesting that I can't seem to replicate it outside the playground or REPL. Build a trivial Mac app, with or without Foundation imported, and you get the expected behaviour. – Matt Gibson Aug 08 '14 at 19:48
  • I can reproduce it in an iOS app. That's how I found this issue initially. My original code is `Int(arc4random()) % 100 / 100.0` which is always evaluated to 0. I'm the OP, not the other Ethan whose comments said he couldn't reproduce this issue. – Ethan Aug 08 '14 at 21:05
  • Are you running that code on a 32-bit target? Because you'll have some other problems with that. arc4random() returns 32-bit unsigned; on a 32-bit platform Int is 32-bit signed, so things will get messy. I'd use `Double(arc4random_uniform(100)) / 100.0`; that'll avoid [modulo bias](http://stackoverflow.com/questions/10984974/why-do-people-say-there-is-modulo-bias-when-using-a-random-number-generator), too. Also: Oddly, I can reproduce your problem with arc4random in the same project where `1 % 3 / 3.0` works fine. – Matt Gibson Aug 08 '14 at 22:47

3 Answers3

1

Without Foundation, these two expressions return different types:

1 % 3 / 3     // 0 : Int
1 % 3 / 3.0   // 0.33333333333 : Double

This agrees with the behaviour defined in the Swift book:

“If you combine integer and floating-point literals in an expression, a type of Double will be inferred from the context:”

With Foundation, the expressions both return an Integer:

1 % 3 / 3     // 0 : Int
1 % 3 / 3.0   // 0 : Int

Having investigated, I can't see anything obvious in Foundation that would cause this—there's no strange operators defined for % or / that would do this, and the precedence seems the same. Not only that, but I can't reproduce the behaviour outside a playground or the REPL. If you do the above in a simple console app, then you see the expected (0.333333333333333: Double) result even if you import Foundation.

As Zaph says, this is almost certainly a bug. I'd report it.

Matt Gibson
  • 37,886
  • 9
  • 99
  • 128
  • I files a Radar on this. – zaph Aug 08 '14 at 19:32
  • It certainly seems unexpected. Be nice to track down which bit of Foundation is doing it for the bug report, though. – Matt Gibson Aug 08 '14 at 19:36
  • 1
    If you track it down file a radar the reference me in a comment with the info/Radar# and I will update. – zaph Aug 08 '14 at 19:40
  • @Zaph Couldn't find it—in fact, I'm pretty sure my original guess, of a rogue operator, is not there to be found. If you build actual apps—OS X or iOS—you can't reproduce the problem by importing Foundation. I'm starting to suspect that the bug might be in the Playground/REPL evaluation/printing code, or somewhere like that. But I think it's time to give up poking and leave it to the experts. – Matt Gibson Aug 08 '14 at 19:59
  • ic. Well... in playground it doesn't seem to have this problem, and when I run it, I don't have the problem either. But yea, beta. – Ethan Aug 08 '14 at 20:10
  • @Ethan Odd. If I put `import Foundation; 1 % 3 / 3.0` into a new Playground, I get 0. If I delete the `import Foundation` I get `0.333333333333333`. – Matt Gibson Aug 08 '14 at 22:32
0

I played around in playground to try to replicate your problem but was unnable. I tried this...

let r7 = 1 % 3 / 3.0 //evaluates to 0.333333

import Foundation

let r8 = 1 % 3 / 3.0 //evaluates to 0.333333

I think possibly what you are seeing is a difference in assigning the RHS to an explicit type Double vs type Int variable on the LHS. So ...

let r5:Double = 1 % 3 / 3.0 //evaluates to 0.33333
let r6:Int = 1 % 3 / 3.0 //evaluates to 0

I find this mathematic expression to be slightly ambiguous also, to different readers. It may be smart to rewrite it as (1%3)/3.0 (if that is infact what you meant!! that's what the computer sees). Of course the result of 1%3 is the integer 1. The integer 1 divided by the Double 3.0 equals 0.33333. So I feel like your problem can be reduced to ...

let r5:Double = 0.3333333 //evaluates to 0.33333
let r6:Int = 0.3333333 //evaluates to 0

Which doesn't have much to do with arithmetic, just the differences in types Int and Double.

Nimantha
  • 6,405
  • 6
  • 28
  • 69
Ethan
  • 1,567
  • 11
  • 16
  • I can replicate it in a playground, but not by importing Foundation inline. My guess would be that importing Foundation anywhere in a playground imports it for the whole playground. – Matt Gibson Aug 08 '14 at 19:11
  • 1
    It looks like the OP is using Swift from the Terminal. It also looks like importing `Foundation` changed the way the expression was handles, in the first instance as floating point, in the second as integer. I can reproduce it in Terminal—exactly. – zaph Aug 08 '14 at 19:13
  • If that were true wouldn't I see r5 = 0, r6 = 0 ?? Please show ur code. – Ethan Aug 08 '14 at 19:13
  • @Ethan There is no code. Run Swift in the terminal: '/Applications/Xcode6-Beta5.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift' and make the entries in the question. My result: "7> 1 % 3 / 3.0" "$R5: Int = 0" – zaph Aug 08 '14 at 19:19
0

The answer is that Swift is broken, it is Beta after all. I filed a bug report with Apple, Radar: 17962491.

zaph
  • 111,848
  • 21
  • 189
  • 228