以下JavaScript函数始终按预期工作:
function getvalue(a, b, c) {
Math.floor((a / b) % c)
}
当我在Rust中编写这个并通过wasm_bindgen
在JS中使用它时,每隔一段时间,似乎随机地,我会得到一个与上面函数返回的值不同的结果:
pub fn get_value(a: f32, b: f32, c: f32) -> i32 {
((a / b) % c).floor() as i32
}
一些例子:
a = 33339077
b = 53.32715671989507
c = 3.5454545454545454
// JS -> 3, Rust -> 2
a = 33340860
b = 53.32715671989507
c = 3.5454545454545454
// JS -> 0, Rust -> 1
我在这里遗漏了什么,以及如何使Rust函数返回与JS函数相同的值?
3条答案
按热度按时间czq61nw11#
JavaScript使用双精度浮点数,但Rust函数使用单精度。如果你切换到
f64
,你会得到同样的结果:给出:
Playground
tvz2xvvm2#
f32
的最大安全整数是16777215
。大于此值的整数不能精确存储。看看这个rust代码:最接近
33339077
的值是33337076
,所以a
实际上是33339076,而不是33339077。你可能注意到
(33339076/b)%c
是2.98713
,而(33339077/b)%c==3.0068869
(即使使用更精确的算术)。当地板一个出来2和其他3。要修复您的问题,请在整个代码中使用
f64
,而不是f32
。请注意,在任何时候将a
存储为f32
都会引入不准确性,在调用函数之前转换为f64
将为时已晚,数据已经丢失。lrpiutwd3#
你的JS函数
不定义
a
、b
或c
。表达式(a/b) % c
产生undefined。但这并不重要,因为
getvalue()
并不返回值--默认情况下,它返回undefined。您的Rust函数
假设
f32
是单精度IEEE浮点数,i32
是32位int。. . .好吧,它也不返回值。但更多(和大多数?)重要的是,JS中的所有数值都是IEEE双精度浮点数。
参见Goldberg的论文“每个计算机科学家都应该知道的浮点运算”
https://pages.cs.wisc.edu/~david/courses/cs552/S12/handouts/goldberg-floating-point.pdf
https://www.itu.dk/~sestoft/bachelor/IEEE754_article.pdf
https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
参见What Every Programmer Should Know About Floating-Point Arithmetic,or, Why don’t my numbers add up?