Розробка смартконтрактів на 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; Нехай кількість: U128 = 700_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; Нехай С: U128 = 20;

result_0 = а * с / б let result_0 = a.checked_mul(c).expect("ERR_MUL").checked_ div019283746574839201b(.expect)"ERR_DIV"(;

result_1 = а / б * с
нехай result_1 = a.checked_div)b(.expect)"ERR_DIV"(.checked_ MUL019283746574839201c).expect("ERR_MUL");

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

( 2.2 занадто малий порядок величини

Коли йдеться про дробові значення, цілісні операції можуть призвести до втрати точності:

іржа Нехай А: U128 = 10; нехай b: u128 = 3; Нехай c: u128 = 4; Нехай десятковий дріб: u128 = 100_0000;

result_0 = )a / b### * с let result_0 = a.checked_div(b).expect("ERR_DIV").checked_ MUL019283746574839201c(.expect)"ERR_MUL"(;

// result_1 = )a * десятковий / b( * c / десятковий; 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"(;

результат_0 і результат_1 мають різні результати, результат_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###

TOKEN4.03%
NUM0.66%
Переглянути оригінал
Ця сторінка може містити контент третіх осіб, який надається виключно в інформаційних цілях (не в якості запевнень/гарантій) і не повинен розглядатися як схвалення його поглядів компанією Gate, а також як фінансова або професійна консультація. Див. Застереження для отримання детальної інформації.
  • Нагородити
  • 3
  • Поділіться
Прокоментувати
0/400
BearMarketBuildervip
· 08-05 07:58
Ця яма з плаваючими числами глибока, як море.
Переглянути оригіналвідповісти на0
SelfSovereignStevevip
· 08-05 07:53
Плаваюча кома занадто підводить, смартконтракти обов'язково будуть зламані, зовсім не наважуюсь їх використовувати.
Переглянути оригіналвідповісти на0
DegenGamblervip
· 08-05 07:49
Гей, браття, які грають у Rust, зверніть увагу, ця яма з точністю не маленька.
Переглянути оригіналвідповісти на0
  • Закріпити