Rust Smart Contractにおける数値精度問題と最適化解

robot
概要作成中

Rustスマートコントラクト開発日記 (7) 浮動小数点数と整数演算精度問題

この記事では、Rustスマートコントラクトにおける浮動小数点数と整数の演算精度の問題、および数値精算のスマートコントラクトの作成方法について議論します。

1. 浮動小数点演算の精度問題

Rust言語は浮動小数点演算をネイティブでサポートしていますが、浮動小数点演算には避けられない計算精度の問題があります。スマートコントラクトを作成する際には、浮動小数点演算の使用は推奨されません。特に重要な経済/金融の意思決定に関わる比率や金利を扱う場合には注意が必要です。

Rust言語では、浮動小数点数はIEEE 754標準を採用しており、底数2の科学的表記法で表されます。特定の小数(のように、0.7)は有限の長さの浮動小数点数で正確に表現できず、"丸め"現象が発生します。

例えば、NEARブロックチェーン上で10人のユーザーに0.7NEARトークンを配布する場合:

さび #[test] fn precision_test_float() { 量を仮定します:f64 = 0.7;
除数をしましょう:f64 = 10.0;
let result_0 = amount / divisor;
assert_eq!(result_0, 0.07, ""); }

実行結果は、amountの値が正確な0.7ではなく、近似値の0.69999999999999995559であることを示しています。除算の結果も正確ではなく、期待される0.07ではなく0.06999999999999999です。

この問題を解決するために、固定小数点数を使用することを検討できます。NEAR Protocol では、通常、1 NEAR = 10^24 yoctoNEAR の表現方法が使用されます:

さび #[test] fn precision_test_integer() { N: u128 = 1_000_000_000_000_000_000_000_000_000_000_000;
量を仮定します: U128 = 700_000_000_000_000_000_000_000_000; 除数をしましょう:u128 = 10;
let result_0 = amount / divisor; assert_eq!(result_0, 70_000_000_000_000_000_000_000_000, ""); }

これにより、数値計算の結果を得ることができます: 0.7 NEAR / 10 = 0.07 NEAR。

!

2. Rustの整数計算の精度に関する問題

2.1 操作の順序

同じ算数の優先順位の乗算と除算では、その前後の順序の変更が計算結果に直接影響を与える可能性があります:

さび #[test] fn precision_test_div_before_mul() { Aを仮定します:U128 = 1_0000; Bを仮定します:U128 = 10_0000; Cを仮定します:U128 = 20;

let result_0 = a.checked_mul(c).expect("ERR_MUL")
                .checked_div(b).expect("ERR_DIV");

let result_1 = a.checked_div(b).expect("ERR_DIV")
                .checked_mul(c).expect("ERR_MUL");

assert_eq!(result_0,result_1,");

}

実行結果はresult_0とresult_1が等しくないことを示しています。原因は整数の除算が除数未満の精度を切り捨てるためです。result_1を計算する際、(a / b)は最初に精度を失って0になります。一方、result_0を計算する際は、a * cを先に計算することで精度の損失を回避できます。

2.2 小さすぎる数量

数量が小さすぎると精度の問題が生じることがあります:

さび #[test] fn precision_test_decimals() { Aを仮定します:U128 = 10; Bを仮定します:u128 = 3; C:u128 = 4とします。 小数で仮定します:u128 = 100_0000;

let result_0 = a.checked_div(b).expect("ERR_DIV")
                .checked_mul(c).expect("ERR_MUL");

let result_1 = a.checked_mul(decimal).expect("ERR_MUL")
                .checked_div(b).expect("ERR_DIV")
                .checked_mul(c).expect("ERR_MUL")
                .checked_div(decimal).expect("ERR_DIV");

assert_eq!(result_0, result_1, "");

}

結果は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 運用精度の累積損失

運用精度の累積損失を記録します。

さび 定数 USER_NUM: u128 = 3;

fn distribute(amount: u128, オフセット: u128) -> u128 { token_to_distribute = オフセット + 金額とします。 per_user_share = token_to_distribute / USER_NUMとします。 recorded_offset = token_to_distribute - per_user_share * USER_NUM; recorded_offset }

#[test] fn record_offset_test() { mutオフセットをしましょう:u128 = 0; for i in 1..7 { オフセット = distribute(to_yocto("10"), offset); } }

これにより、配布されなかったトークンを一時保管し、次回の配布時に一緒に配布することができます。

3.4 では、Rust Crate ライブラリ rust-decimal を使用します

このライブラリは、正確な精度計算と丸め誤差のない小数金融計算が必要な場合に適しています。

3.5 丸め機構を考慮する

スマートコントラクト設計時、通常は「私は得をしたい、他人が私の羊毛を刈ってはいけない」という原則を採用します。状況に応じて切り捨てまたは切り上げを選択し、四捨五入を使用することは非常に少ないです。

!

原文表示
このページには第三者のコンテンツが含まれている場合があり、情報提供のみを目的としております(表明・保証をするものではありません)。Gateによる見解の支持や、金融・専門的な助言とみなされるべきものではありません。詳細については免責事項をご覧ください。
  • 報酬
  • 8
  • 共有
コメント
0/400
SandwichHuntervip
· 07-16 18:07
rustの小さな鶏がまた地面に寝転んでいる
原文表示返信0
WhaleStalkervip
· 07-16 17:00
コードバグは本当に厄介ですね...
原文表示返信0
GhostInTheChainvip
· 07-15 16:28
rustはまだ小数を埋めなければならない...簡単ではない
原文表示返信0
BoredWatchervip
· 07-13 18:40
rustライブラリは契約を書くことができますか?
原文表示返信0
GasFeeNightmarevip
· 07-13 18:35
運算精度は私のガス費のように煩わしい...
原文表示返信0
EyeOfTheTokenStormvip
· 07-13 18:34
精度損失率は利益と損失の比率に直接影響しますが、まだ浮動小数点数を使っている人は誰ですか?ギャンブラーはもうラグプルしてしまったでしょう。
原文表示返信0
TokenEconomistvip
· 07-13 18:32
実際、精度の損失 = f(注文の操作、スケールファクター) ... rust-decimalライブラリ万歳
原文表示返信0
just_another_walletvip
· 07-13 18:25
浮動小数点数は本当にひどいですね...
原文表示返信0
いつでもどこでも暗号資産取引
qrCode
スキャンしてGateアプリをダウンロード
コミュニティ
日本語
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Bahasa Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)