📢 Gate廣場 #MBG任务挑战# 發帖贏大獎活動火熱開啓!
想要瓜分1,000枚MBG?現在就來參與,展示你的洞察與實操,成爲MBG推廣達人!
💰️ 本期將評選出20位優質發帖用戶,每人可輕鬆獲得50枚MBG!
如何參與:
1️⃣ 調研MBG項目
對MBG的基本面、社區治理、發展目標、代幣經濟模型等方面進行研究,分享你對項目的深度研究。
2️⃣ 參與並分享真實體驗
參與MBG相關活動(包括CandyDrop、Launchpool或現貨交易),並曬出你的參與截圖、收益圖或實用教程。可以是收益展示、簡明易懂的新手攻略、小竅門,也可以是現貨行情點位分析,內容詳實優先。
3️⃣ 鼓勵帶新互動
如果你的帖子吸引到他人參與活動,或者有好友評論“已參與/已交易”,將大幅提升你的獲獎概率!
MBG熱門活動(帖文需附下列活動連結):
Gate第287期Launchpool:MBG — 質押ETH、MBG即可免費瓜分112,500 MBG,每小時領取獎勵!參與攻略見公告:https://www.gate.com/announcements/article/46230
Gate CandyDrop第55期:CandyDrop x MBG — 通過首次交易、交易MBG、邀請好友註冊交易即可分187,500 MBG!參與攻略見公告:https://www.gate.com/announcements
Rust智能合約整數計算精度問題及解決方案
Rust智能合約養成日記(7):整數計算精度問題
往期回顧:
1. 浮點數運算的精度問題
與Solidity不同,Rust原生支持浮點數運算。但浮點數運算存在不可避免的精度問題,因此不推薦在智能合約中使用,尤其是處理重要經濟/金融決策的比率或利率時。
Rust遵循IEEE 754標準表示浮點數。f64雙精度浮點類型在計算機內部採用二進制科學計數法表示。
一些小數可以用有限位數的二進制精確表示,如0.8125可表示爲0.1101。但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;
println!("The value of amount: {:.20}", amount); assert_eq!(result_0, 0.07); }
運行結果顯示amount實際值爲0.69999999999999995559,result_0爲0.06999999999999999,不等於預期的0.07。
爲解決這個問題,可以使用定點數。在NEAR中,通常用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 = 2, result_1 = 0。
原因是整數除法會舍棄小於除數的精度。計算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 增加整數的數量級
使用更大的數量級,創造更大的分子。如定義1 NEAR = 10^24 yoctoNEAR。
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(10_000_000_000_000_000_000_000_000, offset); } }
3.4 使用Rust Crate庫rust-decimal
該庫適用於需要高精度且無舍入誤差的小數金融計算。
3.5 考慮舍入機制
智能合約設計中,舍入通常遵循"對我有利"原則:向下取整對我有利則向下,向上取整對我有利則向上,很少採用四舍五入。