添加了Rust和Webassembly



给定我想求一个级数的前n项的和1,2,3在Rust 中具有以下功能

fn sum_sequence(x: u64) -> u64 
{
let mut s: u64 = 0;
for n in 1..=x
{
s = s + n;
}
return s;
}

我为x64体系结构编译它时

cargo build --release

并用CCD_ 1运行,结果为CCD_。

但是当我将这个函数编译到Webassembly(WASM)时

cargo build --target wasm32-unknown-unknown --release

并使用与以前相同的参数运行它,x=10000000000

wasmtime ./target/wasm32-unknown-unknown/release/sum_it.wasm --invoke sum_sequence 1000000000

结果为-5340232216128654848

与Rust编译到WASM相比,我没有想到Rust编译成x64的结果会有任何偏差。此外,从WASM文本文件(如下)中,我不明白为什么在使用WASM运行它时会得到负面结果。

WASM是如何显示不同的结果的?我该怎么做才能纠正WASM的计算?

(module
(type (;0;) (func (param i64) (result i64)))
(func $sum_sequence (type 0) (param i64) (result i64)
(local i64 i64 i32)
block  ;; label = @1
local.get 0
i64.eqz
i32.eqz
br_if 0 (;@1;)
i64.const 0
return
end
i64.const 1
local.set 1
i64.const 0
local.set 2
block  ;; label = @1
loop  ;; label = @2
local.get 1
local.get 2
i64.add
local.set 2
local.get 1
local.get 1
local.get 0
i64.lt_u
local.tee 3
i64.extend_i32_u
i64.add
local.tee 1
local.get 0
i64.gt_u
br_if 1 (;@1;)
local.get 3
br_if 0 (;@2;)
end
end
local.get 2)
(table (;0;) 1 1 funcref)
(memory (;0;) 16)
(global (;0;) (mut i32) (i32.const 1048576))
(global (;1;) i32 (i32.const 1048576))
(global (;2;) i32 (i32.const 1048576))
(export "memory" (memory 0))
(export "sum" (func $sum))
(export "__data_end" (global 1))
(export "__heap_base" (global 2)))

这似乎是因为wasm不支持本机u64作为类型,只支持有符号的变体(尤其是i64),这就是为什么它使用i64作为算术运算的类型。由于这会溢出一个64位整数(正确的输出是n * (n+1) / 250000000005000000000,由于溢出,您会得到一个负值,然后打印到控制台。这是由于wasm中缺乏类型支持。

仅供参考,x=100000000000,我从现在开始使用它,因为它在计算上要快得多,并且对我们的目的是正确的。

结果50000000005000000000需要内存中约65.4位才能在内存中准确表示,这就是为什么x8_64和wasm的包装行为,只是包装的类型不同。

使用NumPy,我们可以清楚地确认这一点:

>>> import numpy as np
>>> a = np.uint64(10000000000)
>>> b = np.uint64(10000000001)
>>> (a >> np.uint64(1)) * b
13106511857580896768
>>> import numpy as np
>>> a = np.int64(10000000000)
>>> b = np.int64(10000000001)
>>> (a >> np.int64(1)) * b
-5340232216128654848

您得到的值是由于无符号和有符号(二的补码)整数溢出造成的。(注意:我使用右移位来模拟除以2,我可能也可以使用//运算符)。

编辑:此外,Herohtar在评论中提出了一个很好的观点:如果在调试模式下运行,它显然会溢出,对'attempt to add with overflow'感到恐慌。

相关内容

  • 没有找到相关文章

最新更新