Rust智能合约开发:数值精算与精度控制技巧

Rust智能合约养成日记(7):数值精算

1. 浮点数运算的精度问题

Rust语言原生支持浮点数运算,但浮点数运算存在着无法避免的计算精度问题。在编写智能合约时,不推荐使用浮点数运算,尤其是在处理涉及重要经济/金融决策的比率或利率时。

Rust语言中的双精度浮点类型f64遵循IEEE 754标准,采用底数为2的科学计数法表达。某些小数如0.7无法用有限位长的浮点数准确表示,存在"舍入"现象。

在NEAR公链上分发0.7个NEAR代币给十位用户的测试中,浮点运算结果不精确:

rust let amount: f64 = 0.7;
let divisor: f64 = 10.0; let result_0 = amount / divisor;

amount的值为0.69999999999999995559,result_0的值为0.06999999999999999,而非预期的0.07。

为解决这个问题,可以使用定点数。在NEAR Protocol中,通常使用1 NEAR = 10^24 yoctoNEAR的方式表示:

rust let N: u128 = 1_000_000_000_000_000_000_000_000; let amount: u128 = 700_000_000_000_000_000_000_000; let divisor: u128 = 10; let result_0 = amount / divisor;

这样可以获得精确的运算结果:0.7 NEAR / 10 = 0.07 NEAR。

2. Rust整数计算精度的问题

2.1 运算顺序

同一算数优先级的乘法与除法,其前后顺序的变化可能直接影响计算结果。例如:

rust let a: u128 = 1_0000; let b: u128 = 10_0000; let c: u128 = 20;

// result_0 = a * c / b let result_0 = a.checked_mul(c).expect("ERR_MUL").checked_div(b).expect("ERR_DIV");

// result_1 = a / b * c
let result_1 = a.checked_div(b).expect("ERR_DIV").checked_mul(c).expect("ERR_MUL");

result_0和result_1的计算结果不同,因为对于整数除法而言,小于除数的精度会被舍弃。

2.2 过小的数量级

当涉及小数值时,整数运算可能导致精度损失:

rust let a: u128 = 10; let b: u128 = 3; let c: u128 = 4; let decimal: u128 = 100_0000;

// result_0 = (a / b) * c let result_0 = a.checked_div(b).expect("ERR_DIV").checked_mul(c).expect("ERR_MUL");

// result_1 = (a * decimal / b) * c / decimal;
let result_1 = a.checked_mul(decimal).expect("ERR_MUL") .checked_div(b).expect("ERR_DIV") .checked_mul(c).expect("ERR_MUL") .checked_div(decimal).expect("ERR_DIV");

result_0和result_1的运算结果不同,result_1更接近实际预期值。

3. 如何编写数值精算的Rust智能合约

3.1 调整运算的操作顺序

令整数乘法优先于整数的除法。

3.2 增加整数的数量级

使用更大的数量级,创造更大的分子。例如,将5.123 NEAR表示为51_230_000_000 yoctoNEAR。

3.3 积累运算精度的损失

记录累计的运算精度损失,在后续运算中补偿。例如:

rust fn distribute(amount: u128, offset: u128) -> u128 { let token_to_distribute = offset + amount; let per_user_share = token_to_distribute / USER_NUM; let recorded_offset = token_to_distribute - per_user_share * USER_NUM; recorded_offset }

3.4 使用Rust Crate库rust-decimal

该库适用于需要有效精度计算和没有舍入误差的小数金融计算。

3.5 考虑舍入机制

在智能合约设计中,舍入问题通常采用"我要占便宜,他人不得薅我羊毛"的原则。根据情况选择向下取整、向上取整或四舍五入。

TOKEN-10.1%
NUM-3.35%
此页面可能包含第三方内容,仅供参考(非陈述/保证),不应被视为 Gate 认可其观点表述,也不得被视为财务或专业建议。详见声明
  • 赞赏
  • 3
  • 分享
评论
0/400
熊市搬砖人vip
· 16小时前
浮点数这坑简直深似海
回复0
SelfSovereignStevevip
· 16小时前
浮点数太坑了 智能合约必炸 完全不敢用
回复0
德根赌徒vip
· 16小时前
玩Rust的兄弟注意了啊,精度这坑不小
回复0
交易,随时随地
qrCode
扫码下载 Gate APP
社群列表
简体中文
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Bahasa Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)