📢 Gate广场 #NERO发帖挑战# 秀观点赢大奖活动火热开启!
Gate NERO生态周来袭!发帖秀出NERO项目洞察和活动实用攻略,瓜分30,000NERO!
💰️ 15位优质发帖用户 * 2,000枚NERO每人
如何参与:
1️⃣ 调研NERO项目
对NERO的基本面、社区治理、发展目标、代币经济模型等方面进行研究,分享你对项目的深度研究。
2️⃣ 参与并分享真实体验
参与NERO生态周相关活动,并晒出你的参与截图、收益图或实用教程。可以是收益展示、简明易懂的新手攻略、小窍门,也可以是行情点位分析,内容详实优先。
3️⃣ 鼓励带新互动
如果你的帖子吸引到他人参与活动,或者有好友评论“已参与/已交易”,将大幅提升你的获奖概率!
NERO热门活动(帖文需附以下活动链接):
NERO Chain (NERO) 生态周:Gate 已上线 NERO 现货交易,为回馈平台用户,HODLer Airdrop、Launchpool、CandyDrop、余币宝已上线 NERO,邀您体验。参与攻略见公告:https://www.gate.com/announcements/article/46284
高质量帖子Tips:
教程越详细、图片越直观、互动量越高,获奖几率越大!
市场见解独到、真实参与经历、有带新互动者,评选将优先考虑。
帖子需原创,字数不少于250字,且需获得至少3条有效互动
Rust智能合约中数值运算精度问题及优化方案
Rust智能合约养成日记(7)浮点数与整数运算精度问题
本文将讨论Rust智能合约中的浮点数和整数运算精度问题,以及如何编写数值精算的智能合约。
1. 浮点数运算的精度问题
Rust语言原生支持浮点数运算,但浮点数运算存在无法避免的计算精度问题。在编写智能合约时,不推荐使用浮点数运算,尤其是处理重要经济/金融决策的比率或利率时。
Rust语言中浮点数采用IEEE 754标准,使用底数为2的科学计数法表示。某些小数(如0.7)无法用有限位长的浮点数准确表示,会存在"舍入"现象。
例如,在NEAR公链上分发0.7个NEAR代币给10位用户时:
rust #[test] fn precision_test_float() { let amount: f64 = 0.7;
let divisor: f64 = 10.0;
let result_0 = amount / divisor;
assert_eq!(result_0, 0.07, ""); }
执行结果显示,amount的值并非准确的0.7,而是近似值0.69999999999999995559。除法运算结果也不精确,为0.06999999999999999而非预期的0.07。
为解决此问题,可考虑使用定点数。在NEAR Protocol中,通常使用1 NEAR = 10^24 yoctoNEAR的表示方式:
rust #[test] fn precision_test_integer() { 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; assert_eq!(result_0, 70_000_000_000_000_000_000_000, ""); }
这样可获得数值精算的运算结果: 0.7 NEAR / 10 = 0.07 NEAR。
2. Rust整数计算精度的问题
2.1 运算顺序
同一算数优先级的乘法与除法,其前后顺序变化可能直接影响计算结果:
rust #[test] fn precision_test_div_before_mul() { let a: u128 = 1_0000; let b: u128 = 10_0000; let c: u128 = 20;
}
执行结果显示result_0和result_1不相等。原因是整数除法会舍弃小于除数的精度。计算result_1时,(a / b)会先失去精度变为0;而计算result_0时,先计算a * c可避免精度丢失。
2.2 过小的数量级
数量级过小也会导致精度问题:
rust #[test] fn precision_test_decimals() { let a: u128 = 10; let b: u128 = 3; let c: u128 = 4; let decimal: u128 = 100_0000;
}
结果显示result_0=12,result_1=13,后者更接近预期值13.3333。
3. 如何编写数值精算的Rust智能合约
为提高精度,可采取以下防护措施:
3.1 调整运算的操作顺序
令整数乘法优先于整数的除法。
3.2 增加整数的数量级
使用更大的数量级,创造更大的分子。例如将5.123 NEAR表示为5.123 * 10^10 = 51_230_000_000。
3.3 积累运算精度的损失
记录累计的运算精度损失:
rust const USER_NUM: u128 = 3;
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 }
#[test] fn record_offset_test() { let mut offset: u128 = 0; for i in 1..7 { offset = distribute(to_yocto("10"), offset); } }
这样可以将未能分发的token暂存,下次分发时一并发放。
3.4 使用 Rust Crate库rust-decimal
该库适用于需要有效精度计算和没有舍入误差的小数金融计算。
3.5 考虑舍入机制
智能合约设计时,通常采用"我要占便宜,他人不得薅我羊毛"的原则。根据情况选择向下或向上取整,极少采用四舍五入。