📢 Gate廣場專屬 #WXTM创作大赛# 正式開啓!
聚焦 CandyDrop 第59期 —— MinoTari (WXTM),總獎池 70,000 枚 WXTM 等你贏!
🎯 關於 MinoTari (WXTM)
Tari 是一個以數字資產爲核心的區塊鏈協議,由 Rust 構建,致力於爲創作者提供設計全新數字體驗的平台。
通過 Tari,數字稀缺資產(如收藏品、遊戲資產等)將成爲創作者拓展商業價值的新方式。
🎨 活動時間:
2025年8月7日 17:00 - 8月12日 24:00(UTC+8)
📌 參與方式:
在 Gate廣場發布與 WXTM 或相關活動(充值 / 交易 / CandyDrop)相關的原創內容
內容不少於 100 字,形式不限(觀點分析、教程分享、圖文創意等)
添加標籤: #WXTM创作大赛# 和 #WXTM#
附本人活動截圖(如充值記錄、交易頁面或 CandyDrop 報名圖)
🏆 獎勵設置(共計 70,000 枚 WXTM):
一等獎(1名):20,000 枚 WXTM
二等獎(3名):10,000 枚 WXTM
三等獎(10名):2,000 枚 WXTM
📋 評選標準:
內容質量(主題相關、邏輯清晰、有深度)
用戶互動熱度(點讚、評論)
附帶參與截圖者優先
📄 活動說明:
內容必須原創,禁止抄襲和小號刷量行爲
獲獎用戶需完成 Gate廣場實名
Rust智能合約中的精準數值計算:整數vs浮點數
Rust智能合約養成日記(7):數值精算
往期回顧:
1. 浮點數運算的精度問題
不同於常見的智能合約編程語言Solidity,Rust語言原生支持浮點數運算。然而,浮點數運算存在着無法避免的計算精度問題。因此,在編寫智能合約時,並不推薦使用浮點數運算(尤其是在處理涉及到重要經濟/金融決策的比率或利率時)。
目前主流計算機語言表示浮點數大多遵循IEEE 754標準,Rust語言也不例外。如下是Rust語言中有關雙精度浮點類型f64的說明與計算機內部二進制數據保存形式:
浮點數採用了底數爲2的科學計數法來表達。例如可以用有限位數的二進制數0.1101來表示小數0.8125,具體的轉化方式如下:
然而對於另一個小數0.7來說,其實際轉化爲浮點數的過程中將存在如下問題:
即小數0.7將表示爲0.101100110011001100.....(無限循環),無法用有限位長的浮點數來準確表示,並存在"舍入(Rounding)"現象。
假設在NEAR公鏈上,需要分發0.7個NEAR代幣給十位用戶,具體每位用戶分得的NEAR代幣數量將計算保存於result_0變量中。
執行該測試用例的輸出結果如下:
可見在上述浮點運算中,amount的值並非準確地表示了0.7,而是一個極爲近似的值0.69999999999999995559。進一步的,對於諸如amount/divisor的單一除法運算,其運算結果也將變爲不精確的0.06999999999999999,並非預期的0.07。由此可見浮點數運算的不確定性。
對此,我們不得不考慮在智能合約中使用其它類型的數值表示方法,如定點數。
在實際的智能合約編寫中,通常會使用一個具有固定分母的分數來表示某一數值,例如分數"x/N",其中"N"是常數,"x"可以變化。
若"N"取值爲"1,000,000,000,000,000,000",也就是"10^18",此時小數可被表示爲整數,像這樣:
在NEAR Protocol中,該N常見的取值爲"10^24",即10^24個yoctoNEAR等價於1個NEAR代幣。
基於此,我們可以將本小節的單元測試修改爲如下方式進行計算:
以此可獲得數值精算的運算結果: 0.7 NEAR / 10 = 0.07 NEAR
2. Rust整數計算精度的問題
從上文第1小節的描述中可以發現,使用整數運算可解決某些運算場景中浮點數運算精度丟失問題。
但這並非意味着使用整數計算的結果完全是準確可靠的。本小節將介紹影響整數計算精度的部分原因。
2.1 運算順序
同一算數優先級的乘法與除法,其前後順序的變化可能直接影響到計算結果,導致整數計算精度的問題。
例如存在如下運算:
執行單元測試的結果如下:
我們可以發現result_0 = a * c / b及result_1 = (a / b)* c盡管它們的計算公式相同,但是運算結果卻不同。
分析具體的原因爲:對於整數除法而言,小於除數的精度會被舍棄。因此在計算result_1的過程中,首先計算的(a / b)會率先失去計算精度,變爲0;而在計算result_0時,會首先算得a * c的結果20_0000,該結果將大於除數b,因此避免了精度丟失的問題,可得到正確的計算結果。
2.2 過小的數量級
該單元測試的具體結果如下:
可見運算過程等價的result_0和result_1運算結果並不相同,且result_1 = 13更加地接近於實際預期的計算值:13.3333....
3. 如何編寫數值精算的Rust智能合約
保證正確的精度在智能合約中十分重要。盡管Rust語言中也存在整數運算結果精度丟失的問題,但我們可以採取如下一些防護手段來提高精度,達到令人滿意的效果。
3.1 調整運算的操作順序
3.2 增加整數的數量級
比如對於一個NEAR token來說,如果定義其上文所描述的N = 10,則意味着:若需要表示5.123的NEAR價值,則實際運算所採用的整數數值將表示爲5.123* 10^10 = 51_230_000_000。該值繼續參與後續的整數運算,可提高運算精度。
3.3 積累運算精度的損失
對於確實無法避免的整數計算精度問題,項目方可以考慮記錄累計的運算精度的損失。
假設如下使用fn distribute(amount: u128, offset: u128) -> u128爲USER_NUM位用戶分發代幣的場景。
在該測試用例中,系統每次將給3位用戶分發10個Token。但是,由於整數運算精度的問題,第一輪中計算per_user_share時,獲得的整數運算結果爲10 / 3 = 3,即第一輪distribute用戶將平均獲得3個token,總計9個token被分發。
此時可以發現,系統中還剩下1個token未能分發給用戶。爲此可以考慮將該剩餘的token臨時保存在系統全局的變量offset中。等待下次系統再次調用distribute給用戶分發token時,該值將被取出,並嘗試和本輪分發的token金額一起分發給用戶。
如下爲模擬的代幣分發過程: