Разработка смарт-контрактов на Rust: методы численного расчета и контроля точности

Rust смарт-контракты养成日记(7):数值精算

1. Проблема точности операций с плавающей точкой

Язык Rust изначально поддерживает операции с плавающей точкой, но операции с плавающей точкой сталкиваются с неизбежными проблемами точности вычислений. При написании смарт-контрактов не рекомендуется использовать операции с плавающей точкой, особенно при обработке коэффициентов или процентных ставок, связанных с важными экономическими/финансовыми решениями.

Двойной точности тип с плавающей запятой f64 в языке Rust соответствует стандарту IEEE 754 и используется научная нотация с основанием 2. Некоторые десятичные дроби, такие как 0.7, не могут быть точно представлены конечной длиной числа с плавающей запятой, что приводит к явлению "округления".

В тестировании распределения 0.7 токенов NEAR десяти пользователям на блокчейне NEAR результат вычислений с плавающей точкой не точен:

ржавчина Пусть сумма: f64 = 0.7;
пусть делитель: f64 = 10.0; пусть result_0 = сумма / делитель;

значение amount равно 0.69999999999999995559, значение result_0 равно 0.06999999999999999, а не ожидаемое 0.07.

Чтобы решить эту проблему, можно использовать фиксированную точку. В NEAR Protocol обычно используется представление 1 NEAR = 10^24 yoctoNEAR:

ржавчина пусть N: u128 = 1_000_000_000_000_000_000_000_000; let amount: u128 = 700_000_000_000_000_000_000_000; пусть делитель: u128 = 10; пусть result_0 = сумма / делитель;

Таким образом, можно получить точный результат вычисления: 0.7 NEAR / 10 = 0.07 NEAR.

!

2. Проблема точности вычислений с целыми числами в Rust

2.1 Порядок операций

При одинаковом уровне приоритета арифметики, изменение порядка выполнения умножения и деления может непосредственно влиять на результат вычислений. Например:

ржавчина пусть a: u128 = 1_0000; пусть b: u128 = 10_0000; пусть c: u128 = 20;

result_0 = а * c / b Пусть result_0 = a.checked_mul(c).expect("ERR_MUL").checked_ div(b).expect0192837374656574839201"ERR_DIV"(;

result_1 = а / б * к
Пусть result_1 = a.checked_div)b(.expect)"ERR_DIV"(.checked_ мул)c(.expect0192837374656574839201"ERR_MUL");

результаты result_0 и result_1 различаются, потому что для целочисленного деления точность, меньшая делителя, будет отброшена.

( 2.2 слишком маленький порядок величины

При работе с малыми значениями целочисленные операции могут привести к потере точности:

ржавчина пусть a: u128 = 10; пусть b: u128 = 3; пусть c: u128 = 4; пусть десятичная: u128 = 100_0000;

result_0 = )a / b### * c Пусть result_0 = a.checked_div(b).expect("ERR_DIV").checked_ мул(c).expect0192837374656574839201"ERR_MUL"(;

// result_1 = )a * десятичное / b( * c / десятичное;
Пусть 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"(;

результаты result_0 и result_1 различаются, результат result_1 ближе к фактическому ожидаемому значению.

! [])https://img-cdn.gateio.im/webp-social/moments-1933a4a2dd723a847f0059d31d1780d1.webp(

3. Как написать Rust смарт-контракты для числовой актуарной оценки

) 3.1 Изменение порядка операций

Установите приоритет умножения целых чисел над делением целых чисел.

( 3.2 Увеличение порядков целых чисел

Используйте больший порядок, чтобы создать большие молекулы. Например, представьте 5.123 NEAR как 51_230_000_000 yoctoNEAR.

) 3.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; записанный_сдвиг }

3.4 Использование библиотеки Rust Crate rust-decimal

Библиотека подходит для финансовых расчетов с десятичными числами, требующими точных вычислений и отсутствия ошибок округления.

( 3.5 Учитывайте механизм округления

В дизайне смарт-контрактов проблема округления обычно решается по принципу "Я хочу получить выгоду, другие не должны меня обманывать". В зависимости от ситуации выбирается округление вниз, округление вверх или округление до ближайшего целого.

! [])https://img-cdn.gateio.im/webp-social/moments-6e8b4081214a69423fc7ae022d05c728.webp###

TOKEN3.98%
NUM0.97%
Посмотреть Оригинал
На этой странице может содержаться сторонний контент, который предоставляется исключительно в информационных целях (не в качестве заявлений/гарантий) и не должен рассматриваться как поддержка взглядов компании Gate или как финансовый или профессиональный совет. Подробности смотрите в разделе «Отказ от ответственности» .
  • Награда
  • 3
  • Поделиться
комментарий
0/400
BearMarketBuildervip
· 08-05 07:58
Эта яма с плавающей точкой просто глубока, как море.
Посмотреть ОригиналОтветить0
SelfSovereignStevevip
· 08-05 07:53
Число с плавающей запятой слишком проблемное, смарт-контракты обязательно провалятся, совершенно не осмеливаюсь использовать.
Посмотреть ОригиналОтветить0
DegenGamblervip
· 08-05 07:49
Игроки Rust, обратите внимание, эта проблема с точностью не маленькая.
Посмотреть ОригиналОтветить0
  • Закрепить