Isuru
Isuru

Reputation: 31283

Same expression returns different values in Objective-C and Swift

I have this expression. It's in Objective-C.

CGFloat x1 = self.frame.size.width / 2 + ((self.frame.size.width - self.borderWidth * 2 - self.graduationOffset) / 2) * cos((6 * i) * (M_PI / 180) - (M_PI / 2));

Here are the values for each variable/property. They are all of type CGFloat.

self.frame.size.width = 200

self.borderWidth = 3

self.graduationOffset = 10

This whole expression is in a loop that executes 60 times. The value of i starts from 0 and goes up to 60. In the code example above, it was 0.

The value of x1 is 100.

I converted this expression to Swift like this.

let x1 = Double(frame.size.width / 2 + ((frame.size.width - borderWidth * 2 - graduationOffset) / 2)) * cos(Double((6 * i)) * (M_PI / 180) - (M_PI / 2))

Passing the same values for the variables. the result I get is 1.17566092718146e-14.

I tried to break it down and inspect the values separately to figure this out. But that caused only more confusion. Because I got 0 as the final result!

CGFloat a = self.frame.size.width / 2 + ((self.frame.size.width - self.borderWidth * 2 - self.graduationOffset) / 2);
NSLog(@"%f", a); // 192.000000
CGFloat b = cos((6 * i) * (M_PI / 180) - (M_PI / 2));
NSLog(@"%f", b); // 0.000000
CGFloat c = a * b;
NSLog(@"%f", c); // 0.000000

I tried the same in Swift and got different results.

let a = Double(frame.size.width / 2 + ((frame.size.width - borderWidth * 2 - graduationOffset) / 2))
print(a) // 192.0
let b = cos(Double((6 * i)) * (M_PI / 180) - (M_PI / 2))
print(b) // 6.12323399573677e-17
let c = a * b
print(c) // 1.17566092718146e-14

I've been going at this all day but can't figure out all this. I guess the way expressions are evaluated is different between Objective-C and Swift? I'd really appreciate any help.

Upvotes: 0

Views: 114

Answers (1)

Sulthan
Sulthan

Reputation: 130092

Let's split your Obj-C code into 3 parts:

CGFloat x1 = frameWidth / 2 + ((frameWidth - borderWidth * 2 - graduationOffset) / 2) * cos((6 * i) * (M_PI / 180) - (M_PI / 2));

CGFloat part1 = frameWidth / 2;
CGFloat part2 = ((frameWidth - borderWidth * 2 - graduationOffset) / 2);
CGFloat part3 = cos((6 * i) * (M_PI / 180) - (M_PI / 2));

Your Obj-C version is then doing result = part1 + (part2 * part3) (I am sure you know that * has precedence over +) while your additional Double(...) cast in the Swift version converts the expression into result = (part1 + part2) * part3. Since part3 is 0 for i = 0, the result is clear.

Upvotes: 2

Related Questions