Rounding error in `__mulsf3`
tgross35 opened this issue · 6 comments
This is a problem in Rust's compiler-builtins, but also the LLVM library (which is demonstrated here). The correct answer should be 0.0.
extern "C" {
fn __mulsf3(a: f32, b: f32) -> f32;
}
fn main() {
let a = 7.83651e-39f32;
let b = 2.7310085e-8f32;
let res_asm = a * b ;
let res_mulsf3 = unsafe { __mulsf3(a, b) };
println!("asm {} {:#010x}", res_asm, res_asm.to_bits());
println!("mulsf3 {} {:#010x}", res_mulsf3, res_mulsf3.to_bits());
}asm 0 0x00000000
mulsf3 0.000000000000000000000000000000000000000000001 0x00000001
Hm, I can't reproduce this in C
Also a problem with f64: f64 mul(1.488018149503636e-307, -2.8933234101276373e-18): crate: -5e-324, asm: -0.0
res_asm doesn't actually use asm, it's const-evaluated by rustc. However inline assembly also produces a result of 0: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=89eb0e7d4c02667b77234004c5f313ec
It definitely seems like a library problem, IEEE734 should produce an exact result for multiply assuming round-to-nearest.
This is probably related to the rounding issue that I thought was limited to f128 llvm/llvm-project#91840
multf3 too, on x86, I am surprised this didn't come up on fuzzing since it seems like the system functions do the right thing here.
#![feature(f128)]
use rustc_apfloat::ieee::Quad;
use rustc_apfloat::Float;
extern "C" {
fn __multf3(a: f128, b: f128) -> f128;
}
#[test]
fn foo() {
let a = f128::from_bits(0x03a00000000000000000000000005400);
let b = f128::from_bits(0x3c2caaaaaaaaaa00000000002aa80002);
let aq = Quad::from_bits(a.to_bits());
let bq = Quad::from_bits(b.to_bits());
let res_llvm = a * b;
let res_crate = compiler_builtins::float::mul::__multf3(a, b);
let res_sys = unsafe { __multf3(a, b) };
println!("llvm {:?}", res_llvm);
println!("crate {:?}", res_crate);
println!("sys {:?}", res_sys);
println!("ap {:#034x}", (aq * bq).value.to_bits());
assert_eq!(res_llvm.to_bits(), res_crate.to_bits());
assert_eq!(res_llvm.to_bits(), res_sys.to_bits());
}llvm 0x00000000000000001aaaaaaaaaa00000
crate 0x00000000000000001aaaaaaaaaa00001
sys 0x00000000000000001aaaaaaaaaa00000
ap 0x00000000000000001aaaaaaaaaa00000
thread 'foo' panicked at testcrate/tests/break.rs:23:5:
assertion `left == right` failed
left: 1921535841010712576
right: 192153584101071257
Note that on -gnu targets, the system version of __mulsf3 and other builtins comes from libgcc, not LLVM's compiler-rt.