Rust dili yerel olarak ondalık sayı işlemlerini destekler, ancak ondalık sayı işlemlerinde kaçınılmaz hesaplama hassasiyeti sorunları vardır. Akıllı sözleşmeler yazarken, özellikle önemli ekonomik/finansal kararlarla ilgili oranlar veya faiz oranları işlenirken ondalık sayı işlemleri kullanılması önerilmez.
Rust dilindeki çift hassasiyetli kayan nokta türü f64, IEEE 754 standardını takip eder ve taban 2 bilimsel gösterim kullanır. Bazı ondalık sayılar, örneğin 0.7, sınırlı uzunluktaki kayan nokta sayılarıyla doğru bir şekilde ifade edilemez ve "yuvarlama" olayı vardır.
NEAR blok zincirinde on kullanıcıya 0.7 NEAR token dağıtma testinde, ondalık hesaplama sonuçları kesin değil:
pas
let amount: f64 = 0.7;
let divisor: f64 = 10.0;
let result_0 = amount / divisor;
amount'ın değeri 0.69999999999999995559, result_0'ın değeri ise 0.06999999999999999, beklenen 0.07 değil.
Bu sorunu çözmek için, sabit nokta kullanabilirsiniz. NEAR Protocol'de genellikle 1 NEAR = 10^24 yoctoNEAR şeklinde ifade edilir:
pas
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;
Bu şekilde kesin bir hesaplama sonucu elde edilebilir: 0.7 NEAR / 10 = 0.07 NEAR.
2. Rust tam sayı hesaplama hassasiyeti sorunu
2.1 İşlem Sırası
Aynı aritmetik önceliğe sahip çarpma ve bölmenin, önceden ve sonradan sırasının değişmesi hesaplama sonucunu doğrudan etkileyebilir. Örneğin:
pas
let a: u128 = 1_0000;
let b: u128 = 10_0000;
let c: u128 = 20;
// result_0 = a * c / b
let result_0 = a.checked_mul(c).expect("ERR_MUL").checked_div(b).expect("ERR_DIV");
// result_1 = a / b * c
let result_1 = a.checked_div(b).expect("ERR_DIV").checked_mul(c).expect("ERR_MUL");
result_0 ve result_1'in hesaplama sonuçları farklıdır, çünkü tam sayı bölme için, paydanın altında kalan hassasiyet atılacaktır.
2.2 çok küçük bir büyüklük
Küçük değerler söz konusu olduğunda, tam sayı işlemleri hassasiyet kaybına neden olabilir:
pas
let a: u128 = 10;
let b: u128 = 3;
let c: u128 = 4;
let decimal: u128 = 100_0000;
// result_0 = (a / b) * c
let result_0 = a.checked_div(b).expect("ERR_DIV").checked_mul(c).expect("ERR_MUL");
// result_1 = (a * ondalık / b) * c / ondalık;
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");
result_0 ve result_1'in hesaplama sonuçları farklıdır, result_1 gerçek beklenen değere daha yakındır.
3. Sayısal Actuarial Rust akıllı sözleşmeler nasıl yazılır
3.1 İşlem sırasını ayarlama
Tam sayı çarpımının tam sayı bölmeden önce gelmesini sağlar.
3.2 tam sayının büyüklüğünü artırmak
Daha büyük bir ölçek kullanarak, daha büyük moleküller yaratın. Örneğin, 5.123 NEAR'ı 51_230_000_000 yoctoNEAR olarak gösterin.
3.3 Birikim işlemleri doğruluğunun kaybı
Kayıtlı toplam hesaplama hassasiyet kaybını, sonraki işlemlerde telafi etme. Örneğin:
pas
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;
kaydedilen_ofset
}
( 3.4 Rust Crate kütüphanesi rust-decimal kullanımı
Bu kütüphane, etkili hassasiyet hesaplaması ve yuvarlama hatası olmayan ondalık finansal hesaplamalar için uygundur.
) 3.5 Yuvarlama mekanizmasını dikkate alın
Akıllı sözleşmeler tasarımında, yuvarlama problemi genellikle "Ben kar elde etmeliyim, başkaları benim kazancımı almamalı" ilkesine dayanır. Duruma göre aşağı yuvarlama, yukarı yuvarlama veya en yakın tam sayıya yuvarlama seçilir.
This page may contain third-party content, which is provided for information purposes only (not representations/warranties) and should not be considered as an endorsement of its views by Gate, nor as financial or professional advice. See Disclaimer for details.
6 Likes
Reward
6
3
Share
Comment
0/400
BearMarketBuilder
· 18h ago
Kayan nokta bu çukur deniz gibi derin.
View OriginalReply0
SelfSovereignSteve
· 18h ago
Kayan nokta sayıları çok sorunlu, akıllı sözleşmeler kesinlikle patlayacak, tamamen kullanmaya cesaret edemiyorum.
View OriginalReply0
DegenGambler
· 18h ago
Rust ile uğraşan kardeşler dikkat etsin, hassasiyet bu çukur küçük değil.
Rust akıllı sözleşmeler geliştirme: Sayısal hesaplama ve hassasiyet kontrolü teknikleri
Rust akıllı sözleşmeler yetiştirme günlüğü (7): Sayısal hesaplama
1. Kesirli sayıların hesaplama hassasiyeti sorunu
Rust dili yerel olarak ondalık sayı işlemlerini destekler, ancak ondalık sayı işlemlerinde kaçınılmaz hesaplama hassasiyeti sorunları vardır. Akıllı sözleşmeler yazarken, özellikle önemli ekonomik/finansal kararlarla ilgili oranlar veya faiz oranları işlenirken ondalık sayı işlemleri kullanılması önerilmez.
Rust dilindeki çift hassasiyetli kayan nokta türü f64, IEEE 754 standardını takip eder ve taban 2 bilimsel gösterim kullanır. Bazı ondalık sayılar, örneğin 0.7, sınırlı uzunluktaki kayan nokta sayılarıyla doğru bir şekilde ifade edilemez ve "yuvarlama" olayı vardır.
NEAR blok zincirinde on kullanıcıya 0.7 NEAR token dağıtma testinde, ondalık hesaplama sonuçları kesin değil:
pas let amount: f64 = 0.7;
let divisor: f64 = 10.0; let result_0 = amount / divisor;
amount'ın değeri 0.69999999999999995559, result_0'ın değeri ise 0.06999999999999999, beklenen 0.07 değil.
Bu sorunu çözmek için, sabit nokta kullanabilirsiniz. NEAR Protocol'de genellikle 1 NEAR = 10^24 yoctoNEAR şeklinde ifade edilir:
pas 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;
Bu şekilde kesin bir hesaplama sonucu elde edilebilir: 0.7 NEAR / 10 = 0.07 NEAR.
2. Rust tam sayı hesaplama hassasiyeti sorunu
2.1 İşlem Sırası
Aynı aritmetik önceliğe sahip çarpma ve bölmenin, önceden ve sonradan sırasının değişmesi hesaplama sonucunu doğrudan etkileyebilir. Örneğin:
pas let a: u128 = 1_0000; let b: u128 = 10_0000; let c: u128 = 20;
// result_0 = a * c / b let result_0 = a.checked_mul(c).expect("ERR_MUL").checked_div(b).expect("ERR_DIV");
// result_1 = a / b * c
let result_1 = a.checked_div(b).expect("ERR_DIV").checked_mul(c).expect("ERR_MUL");
result_0 ve result_1'in hesaplama sonuçları farklıdır, çünkü tam sayı bölme için, paydanın altında kalan hassasiyet atılacaktır.
2.2 çok küçük bir büyüklük
Küçük değerler söz konusu olduğunda, tam sayı işlemleri hassasiyet kaybına neden olabilir:
pas let a: u128 = 10; let b: u128 = 3; let c: u128 = 4; let decimal: u128 = 100_0000;
// result_0 = (a / b) * c let result_0 = a.checked_div(b).expect("ERR_DIV").checked_mul(c).expect("ERR_MUL");
// result_1 = (a * ondalık / b) * c / ondalık; 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");
result_0 ve result_1'in hesaplama sonuçları farklıdır, result_1 gerçek beklenen değere daha yakındır.
3. Sayısal Actuarial Rust akıllı sözleşmeler nasıl yazılır
3.1 İşlem sırasını ayarlama
Tam sayı çarpımının tam sayı bölmeden önce gelmesini sağlar.
3.2 tam sayının büyüklüğünü artırmak
Daha büyük bir ölçek kullanarak, daha büyük moleküller yaratın. Örneğin, 5.123 NEAR'ı 51_230_000_000 yoctoNEAR olarak gösterin.
3.3 Birikim işlemleri doğruluğunun kaybı
Kayıtlı toplam hesaplama hassasiyet kaybını, sonraki işlemlerde telafi etme. Örneğin:
pas 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; kaydedilen_ofset }
( 3.4 Rust Crate kütüphanesi rust-decimal kullanımı
Bu kütüphane, etkili hassasiyet hesaplaması ve yuvarlama hatası olmayan ondalık finansal hesaplamalar için uygundur.
) 3.5 Yuvarlama mekanizmasını dikkate alın
Akıllı sözleşmeler tasarımında, yuvarlama problemi genellikle "Ben kar elde etmeliyim, başkaları benim kazancımı almamalı" ilkesine dayanır. Duruma göre aşağı yuvarlama, yukarı yuvarlama veya en yakın tam sayıya yuvarlama seçilir.
![]###https://img-cdn.gateio.im/webp-social/moments-6e8b4081214a69423fc7ae022d05c728.webp###