< 返回版块

Freddie Mercury 发表于 2021-07-13 11:42

今天在写wasm时,遇到一个f32四舍五入精度不对的问题。

示例代码见下:

// rustc 1.50.0 (cb75ad5db 2021-02-10)
fn main() {
    println!("{:.2}",0.0050_f32); // 0.00
    println!("{:.2}",0.0051_f32); // 0.01
    println!("{:.2}",0.0050_f64); // 0.01
    println!("{:.2}",0.0051_f64); // 0.01
}

发现wasm函数出来的结果,当传入值类型为f32,值是0.005时,保留两位小数,居然是0.00。 只有当值大于0.005时,譬如0.0051时,才会正常进位变成0.01。而f64就没有这种问题。

之所以采用wasm去实现一些计算,初衷也是为了规避js浮点数精度不对的问题,没想到在Rust上也踩到了坑。 起初怀疑是浏览器的问题,在Playground试了一把,还是一样的情况。 然后本地又做了测试,没料到依然同样的错误。

瞅了下标准库的f32和fmt,也没有找到相关的资料。 坛子里有大佬能帮忙分析下么,或是给个资料链接也好。

评论区

写评论
erihsu 2021-07-13 22:23

参考ieee754对浮点数的标准定义

作者 Freddie Mercury 2021-07-13 18:42

的确是这个原因。惭愧,感觉对不起大学老师。

又去看了下f32的Display Trait实现,确实std做了很多处理。

放大精度后,显示的就是这几个值。

--
👇
daleione: 这块和语言没关系吧。这个属于float的计算问题。 float 不能准确表示 0.0050,存在一定的差值。 float64 里面, 0.0050 二进制表示: 0.005000000000000000104083408558608425664715468883514404296875
float32 里面,0.0050 二进制表示: 0.004999999888241291046142578125
所以,这里四舍五入,float32 变成 0.00 了

你在任何语言里,应该都会得到同样的答案。

daleione 2021-07-13 15:59

这块和语言没关系吧。这个属于float的计算问题。 float 不能准确表示 0.0050,存在一定的差值。 float64 里面, 0.0050 二进制表示: 0.005000000000000000104083408558608425664715468883514404296875
float32 里面,0.0050 二进制表示: 0.004999999888241291046142578125
所以,这里四舍五入,float32 变成 0.00 了

你在任何语言里,应该都会得到同样的答案。

东君 2021-07-13 12:15

mark

曙光磁铁 2021-07-13 11:50

给你捞了个第一行的汇编

        lea     rax, [rip + .L__unnamed_1]
        mov     qword ptr [rsp + 136], rax
        mov     rdi, qword ptr [rsp + 136]
        mov     rsi, qword ptr [rip + core::fmt::float::<impl core::fmt::Display for f32>::fmt@GOTPCREL]
        call    qword ptr [rip + core::fmt::ArgumentV1::new@GOTPCREL]
        mov     qword ptr [rsp + 56], rax
        mov     qword ptr [rsp + 64], rdx
        mov     rax, qword ptr [rsp + 64]
        mov     rcx, qword ptr [rsp + 56]
        mov     qword ptr [rsp + 120], rcx
        mov     qword ptr [rsp + 128], rax
        lea     rcx, [rsp + 120]
        lea     rdi, [rsp + 72]
        lea     rsi, [rip + .L__unnamed_2]
        mov     edx, 2
        mov     r8d, 1
        lea     r9, [rip + .L__unnamed_3]
        mov     qword ptr [rsp], 1
        call    core::fmt::Arguments::new_v1_formatted
        lea     rdi, [rsp + 72]
        call    qword ptr [rip + std::io::stdio::_print@GOTPCREL]
1 共 5 条评论, 1 页