🎉 #Gate Alpha 第三届积分狂欢节 & ES Launchpool# 聯合推廣任務上線!
本次活動總獎池:1,250 枚 ES
任務目標:推廣 Eclipse($ES)Launchpool 和 Alpha 第11期 $ES 專場
📄 詳情參考:
Launchpool 公告:https://www.gate.com/zh/announcements/article/46134
Alpha 第11期公告:https://www.gate.com/zh/announcements/article/46137
🧩【任務內容】
請圍繞 Launchpool 和 Alpha 第11期 活動進行內容創作,並曬出參與截圖。
📸【參與方式】
1️⃣ 帶上Tag #Gate Alpha 第三届积分狂欢节 & ES Launchpool# 發帖
2️⃣ 曬出以下任一截圖:
Launchpool 質押截圖(BTC / ETH / ES)
Alpha 交易頁面截圖(交易 ES)
3️⃣ 發布圖文內容,可參考以下方向(≥60字):
簡介 ES/Eclipse 項目亮點、代幣機制等基本信息
分享你對 ES 項目的觀點、前景判斷、挖礦體驗等
分析 Launchpool 挖礦 或 Alpha 積分玩法的策略和收益對比
🎁【獎勵說明】
評選內容質量最優的 10 位 Launchpool/Gate
Rust智能合約開發:攻克數值計算精度難題
Rust智能合約開發中的數值計算精度問題
1. 浮點數運算的精度問題
Rust語言原生支持浮點數運算,但浮點數運算存在無法避免的計算精度問題。在編寫智能合約時,不推薦使用浮點數運算,尤其是處理重要經濟/金融決策的比率或利率時。
Rust語言中雙精度浮點類型f64遵循IEEE 754標準,採用底數爲2的科學計數法表達。某些小數無法用有限位長的浮點數準確表示,存在"舍入"現象。
例如,在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;
println!("The value of amount: {:.20}", amount); assert_eq!(result_0, 0.07, ""); }
輸出結果顯示amount的值爲0.69999999999999995559,不是準確的0.7。除法運算結果也變爲不精確的0.06999999999999999,而非預期的0.07。
爲解決這個問題,可以考慮使用定點數。在NEAR Protocol中,常用10^24個yoctoNEAR表示1個NEAR代幣。修改後的測試代碼:
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; println!("per_user_share {}", per_user_share); 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 { println!("Round {}", i); offset = distribute(to_yocto("10"), offset); println!("Offset {}\n", offset); } }
這種方法可以將每次分發剩餘的token累積起來,在下次分發時一並發放,最終達到足額發放的目的。
3.4 使用Rust Crate庫rust-decimal
該庫適用於需要有效精度計算和沒有舍入誤差的小數金融計算。
3.5 考慮舍入機制
在智能合約設計中,舍入問題通常採用"我要佔便宜,他人不得薅我羊毛"的原則。根據情況選擇向下取整或向上取整,極少採用四舍五入。