📢 #Gate广场征文活动第二期# 正式啓動!
分享你對 $ERA 項目的獨特觀點,推廣ERA上線活動, 700 $ERA 等你來贏!
💰 獎勵:
一等獎(1名): 100枚 $ERA
二等獎(5名): 每人 60 枚 $ERA
三等獎(10名): 每人 30 枚 $ERA
👉 參與方式:
1.在 Gate廣場發布你對 ERA 項目的獨到見解貼文
2.在貼文中添加標籤: #Gate广场征文活动第二期# ,貼文字數不低於300字
3.將你的文章或觀點同步到X,加上標籤:Gate Square 和 ERA
4.徵文內容涵蓋但不限於以下創作方向:
ERA 項目亮點:作爲區塊鏈基礎設施公司,ERA 擁有哪些核心優勢?
ERA 代幣經濟模型:如何保障代幣的長期價值及生態可持續發展?
參與並推廣 Gate x Caldera (ERA) 生態周活動。點擊查看活動詳情:https://www.gate.com/announcements/article/46169。
歡迎圍繞上述主題,或從其他獨特視角提出您的見解與建議。
⚠️ 活動要求:
原創內容,至少 300 字, 重復或抄襲內容將被淘汰。
不得使用 #Gate广场征文活动第二期# 和 #ERA# 以外的任何標籤。
每篇文章必須獲得 至少3個互動,否則無法獲得獎勵
鼓勵圖文並茂、深度分析,觀點獨到。
⏰ 活動時間:2025年7月20日 17
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 考慮舍入機制
智能合約設計時,通常採用"我要佔便宜,他人不得薅我羊毛"的原則。根據情況選擇向下或向上取整,極少採用四舍五入。