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

f64 Multiplication errors #90003

Closed
wandercn opened this issue Oct 18, 2021 · 9 comments
Closed

f64 Multiplication errors #90003

wandercn opened this issue Oct 18, 2021 · 9 comments
Labels
C-bug Category: This is a bug.

Comments

@wandercn
Copy link

wandercn commented Oct 18, 2021

I tried this code:

#![allow(unused)]
fn main() {
    let a: i64 = -25252734735360000_i64 * 365 + (-25252734735360000_f64 * 0.2425_f64) as i64;
    let b: i64 = (-25252734735360000_f64 * 365.2425_f64) as i64;
    println!("a = {}", a);
    println!("b = {}", b);
    assert_eq!(a, b);
}

I expected to see this happen:
a == b , and the value is equal to -9223371966579724800

Instead, this happened:
a !=b
a = -9223371966579724800
b = -9223371966579725312

Meta

rustc --version --verbose:

rustc 1.55.0 (c8dfcfe04 2021-09-06)
binary: rustc
commit-hash: c8dfcfe046a7680554bf4eb612bad840e7631c4b
commit-date: 2021-09-06
host: x86_64-apple-darwin
release: 1.55.0
LLVM version: 12.0.1
<version>
Backtrace

<backtrace>
   Compiling gostdmain v0.1.0 (/Users/apple/workspace/src/learnRust/gostdmain)
    Finished dev [unoptimized + debuginfo] target(s) in 0.90s
     Running `/Users/apple/workspace/src/learnRust/gostdmain/target/debug/gostdmain`
a = -9223371966579724800
b = -9223371966579725312
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `-9223371966579724800`,
 right: `-9223371966579725312`', src/main.rs:16:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

@wandercn wandercn added the C-bug Category: This is a bug. label Oct 18, 2021
@wandercn
Copy link
Author

wandercn commented Oct 18, 2021

Same problem :

#![allow(unused)]
fn main() {
    let a: f64 = (-25252734735360000_f64 * 365_f64)  + ( -25252734735360000_f64 * 0.2425_f64) ;
    let b: f64 = -25252734735360000_f64 * 365.2425_f64;
    println!("a = {}", a);
    println!("b = {}", b);
    assert_eq!(a, b);
}

output:
Compiling gostdmain v0.1.0 (/Users/apple/workspace/src/learnRust/gostdmain) Finished dev [unoptimized + debuginfo] target(s) in 1.19s Running/Users/apple/workspace/src/learnRust/gostdmain/target/debug/gostdmaina = -9223371966579724000 b = -9223371966579725000 thread 'main' panicked at 'assertion failed:(left == right)left:-9223371966579724000.0, right: -9223371966579725000.0', src/main.rs:16:5 note: run with RUST_BACKTRACE=1environment variable to display a backtrace

@wandercn wandercn changed the title F64 Multiplication errors f64 Multiplication errors Oct 18, 2021
wandercn pushed a commit to wandercn/gostd that referenced this issue Oct 18, 2021
是rust f64 的运算跟go有很大的差异,我给rust提交了一个bug。rust-lang/rust#90003
@a1phyr
Copy link
Contributor

a1phyr commented Oct 18, 2021

These are IEEE floating-point errors unrelated to Rust. You would get the same error with any other language.

@wandercn
Copy link
Author

I don't have this bug in golang. I think it is necessary to optimize rust in order to make it easier to use

package main

import "fmt"

func main() {
var a int64 = -25252734735360000 * 365 - int64(25252734735360000 * 0.2425)
var b int64 = -25252734735360000 * 365.2425 
fmt.Println(a==b)
}

output:
true

@leonardo-m
Copy link

In Python 3 it's the same as in Rust:

>>> a = -25252734735360000 * 365 - int(25252734735360000 * 0.2425)
>>> b = int(-25252734735360000 * 365.2425)
>>> a
-9223371966579724800
>>> b
-9223371966579725312

I think there's nothing to optimize in Rust here, nor to make it simpler to use.

@Urgau
Copy link
Member

Urgau commented Oct 18, 2021

It seems that no programming languages agree on what in the correct result however it seems that most programming language produce the same result for the two expression. Godbolt

@mbartlett21
Copy link
Contributor

I don't have this bug in golang.

This is because constants and number literals in Go have infinite precision[1] until you store them somewhere. If you instead store your numbers in variables and then refer to those in your multiplication, you will get the same results as Rust.

[1]: SO

@maslabgamer
Copy link

I get the same mismatch in a C/C++ build:

#include <iomanip>
#include <iostream>
#include <cassert>

using namespace std;

int main() {
    double a = -25252734735360000.00 * 365.00 + (-25252734735360000.00 * 0.2425);
    double b = -25252734735360000.00 * 365.2425;

    cout << setprecision(32);
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;

    assert(a == b);

    return 0;
}

prints

a = -9223371966579724288
b = -9223371966579725312
Assertion failed: a == b, file G:\projects\cplusplus_scratchpad\main.cpp, line 15

This looks to me like floating point arithmetic issues, not a rustc issue.

@jkarns275
Copy link

jkarns275 commented Oct 21, 2021

This is the expected behavior. Numbers greater than 1 are not uniformly distributed when using doubles, and the distance between numbers that can be properly represented increases with larger numbers. The number 25252734735360000 is beyond the point where only even numbers can be represented, so some significant rounding errors should be expected.

If you need arbitrary precision you should consider using a library for it, e.g. https://docs.rs/rug/0.6.0/rug/

@scottmcm
Copy link
Member

Since this seems to be normal floating-point behaviour, I'm going to close this -- it doesn't seem like there's anything to change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests

8 participants