Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

f32 division/multiplication and .tan() platform behavior #75786

Closed
Blisto91 opened this issue Aug 21, 2020 · 8 comments
Closed

f32 division/multiplication and .tan() platform behavior #75786

Blisto91 opened this issue Aug 21, 2020 · 8 comments
Labels
A-floating-point Area: Floating point numbers and arithmetic

Comments

@Blisto91
Copy link

Blisto91 commented Aug 21, 2020

I know floats aren't exactly known for their precision and i might be missing something.
But i'm seeing some odd platform dependent behavior when i combine a f32 float division with .tan()

This code run on mac, linux and windows

let floaty: f32 = 1.22222; // 5 decimal points
println!("{:.32}", floaty);
println!("{:.32}", floaty / 2.0);
println!("{:.32}", (floaty / 2.0).tan());

Gives the following printout

// mac
1.22221994400024414062500000000000
0.61110997200012207031250000000000
0.70057231187820434570312500000000

// linux
1.22221994400024414062500000000000
0.61110997200012207031250000000000
0.70057231187820434570312500000000

// windows
1.22221994400024414062500000000000
0.61110997200012207031250000000000
0.70057231187820434570312500000000

All the outputs are the same as i guess is expected.

Now i add one more decimal

let floaty: f32 = 1.222222; // 6 decimal points
println!("{:.32}", floaty);
println!("{:.32}", floaty / 2.0);
println!("{:.32}", (floaty / 2.0).tan());

Which outputs

// mac & linux 
1.22222197055816650390625000000000
0.61111098527908325195312500000000
0.70057380199432373046875000000000

// windows
1.22222197055816650390625000000000
0.61111098527908325195312500000000
0.70057386159896850585937500000000

Now windows suddenly shows a different output on the last line.

I have testet this on my windows 10 pc, linux laptop (mint) and a github actions matrix of ubuntu, windows, mac, nightly, beta and stable.

Is this a bug or am i missing something?

@cuviper
Copy link
Member

cuviper commented Aug 21, 2020

This is similar to #73420 -- your Windows result looks like it has computed via f64.

I tried this on the playground (Linux):

fn main() {
    let floaty: f32 = 1.222222; // 6 decimal points
    println!("{:.32}", floaty);
    println!("{:.32}", floaty / 2.0);
    println!("{:.32}", (floaty / 2.0).tan());
    println!("{:.32}", ((floaty / 2.0) as f64).tan() as f32);
}
1.22222197055816650390625000000000
0.61111098527908325195312500000000
0.70057380199432373046875000000000
0.70057386159896850585937500000000

@Blisto91
Copy link
Author

Ah yea i see what you mean.
I was also messing around with f64 to see if i could make it act weird, but was without luck.
Didn't think to compare the values.

@Blisto91
Copy link
Author

Blisto91 commented Aug 21, 2020

Adding some more stuff i just found.
With multiplication ubuntu is the odd one out.

let floaty: f32 = 1.22222;  // 5 decimal points
println!("{:.32}", floaty);
println!("{:.32}", floaty * 2.0);
println!("{:.32}", (floaty * 2.0).tan()); 
// mac linux windows
1.22221994400024414062500000000000
2.44443988800048828125000000000000
-0.83743280172348022460937500000000
let floaty: f32 = 1.222222;  // 6 decimal points
println!("{:.32}", floaty);
println!("{:.32}", floaty * 2.0);
println!("{:.32}", (floaty * 2.0).tan()); 
// mac windows
1.22222197055816650390625000000000
2.44444394111633300781250000000000
-0.83742588758468627929687500000000

// linux
1.22222197055816650390625000000000
2.44444394111633300781250000000000
-0.83742594718933105468750000000000

@Blisto91 Blisto91 changed the title f32 division and .tan() platform behavior f32 division/multiplication and .tan() platform behavior Aug 21, 2020
@ecstatic-morse ecstatic-morse added the A-floating-point Area: Floating point numbers and arithmetic label Aug 23, 2020
@scottmcm
Copy link
Member

This is probably just because of the tan -- multiplication and division are required to be good to ½ULP, but IIRC the trig functions only need to be good to 1ULP, which means it's expected that there can be differences.

If you throw that last example into float toy, you'll see

0xBF56618B -0.8374259
0xBF56618C -0.83742594
         ^

A difference of 1ULP, as expected.

There are plenty of resources about floating point determinism related to real-time strategy games, see for example the things referenced in https://gamedev.stackexchange.com/a/174374

So I think there isn't actually anything to fix here, as unfortunate as that is. This is just why games tend to use their own trig approximations for anything that needs to be portable, rather than the platform ones.

@Blisto91
Copy link
Author

Blisto91 commented Aug 24, 2020

@scottmcm Thanks for the explanation! And thank you for the links.
Gonna bookmark them. :)

I was told that dimforge rapier is gonna have cross platform determinism so i was wondering.
But as you said they probably have their own implementations. 👍

If you say this is expected behavior then feel free to close it. I don't have enough knowledge on the subject to be able to chime in.

Edit:
Also gonna read up on posits because they sound interesting.

@RalfJung
Copy link
Member

Indeed, multiplication and division should be consistent across platforms. Can you confirm that this is the case here? If yes, we should remove their mention from the issue title.

tan, on the other hand, doesn't have a precise spec -- so basically, this is expected behavior. I guess if we want to improve the situation here, we'd want to have a pure-Rust fast and precise implementation of tan (and friends) and make rustc use that instead of the system library. :D

@Blisto91
Copy link
Author

Blisto91 commented Oct 1, 2020

Sorry for not keeping this up to date. Sleep has not been agreeing with me lately.

Will try and update this without the division/multiplication here soon when i have time

@Blisto91
Copy link
Author

Closing this for now as it doesn't focus on the actual problem without division/multiplication.
Might open a new issue if I ever have the time and motivation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-floating-point Area: Floating point numbers and arithmetic
Projects
None yet
Development

No branches or pull requests

5 participants