Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange Swift numbers type casting

I've just noticed that Swift does some type casting over Int and Double. When I try to evaluate

(10 / 3.0) - (10 / 3)

0.333... is expected, but it's actually 0.0. Could someone explain this please?

like image 957
Eugene Auduchinok Avatar asked Mar 02 '15 15:03

Eugene Auduchinok


1 Answers

Yes, I also found this quite surprising. Double conforms to both FloatLiteralConvertible and IntegerLiteralConvertible (ExpressibleByFloatLiteral and ExpressibleByIntegerLiteral in Swift 3). Therefore a Double can be initialized with floating point literal

let a = 3.0

or with an integer literal:

let b : Double = 10

(The same is true for other floating point types like Float and CGFloat.)

Now it might be unexpected for all of us with an (Objective-)C background that both statements

let x : Double = 10/4     // x = 2.5 .  Really? Yes!
let y = 10/4 as Double    // Same here ...

assign the value 0.25 to the variable. From the context, the result of the division must be a Double and Swift does not implicitly convert types. Therefore / must be the floating point division operator

func /(lhs: Double, rhs: Double) -> Double

so the compiler creates both arguments as Doubles from the literals "10" and "4". (If 10/4 were treated as the division of two integers then the result would also be an integer, and that cannot be assigned to a Double.)

Note that this is different from

let z = Double(10/4)   // z = 2.0 . (I just thought that I understood it &%$!?)

which does an integer division and converts the result to Double. Double has an init(_ v: Int) constructor, and therefore 10/4 can be treated as the division of two integers here.

It really looks a bit strange if we summarize these results:

let x : Double = 10/4     // x = 2.5 
let y = 10/4 as Double    // y = 2.5
let z = Double(10/4)      // z = 2.0

Now we can apply these results to your expression

(10 / 3.0) - (10 / 3)

The first part (10 / 3.0) can only be a Double, therefore - must be the floating point subtraction operator

func -(lhs: Double, rhs: Double) -> Double

and thus (10 / 3) must also be a Double. Again, / must be the floating point division operator, so 10 and 3 are treated as Double constants.

Therefore the expression is equivalent to

(Double(10) / 3.0) - (Double(10) / Double(3))

and evaluates to 0.0. If you change the expression to

(10 / 3.0) - Double(10 / 3)

then the result is 0.333... because in this context, 10 / 3 is the division of two integer constants, as explained above.

like image 98
Martin R Avatar answered Oct 22 '22 01:10

Martin R