Rust akıllı sözleşmeler yetiştirme günlüğü (7) Ondalık ve tam sayı işlemleri hassasiyet sorunu
Bu yazıda Rust akıllı sözleşmelerindeki ondalık ve tam sayı işlemlerinin hassasiyet sorunları ile sayısal aktüerya akıllı sözleşmelerinin nasıl yazılacağı tartışılacaktır.
1. Kesirli sayıların hesaplama hassasiyeti sorunu
Rust dilinin yerel olarak ondalıklı sayı hesaplamalarını desteklemesine rağmen, ondalıklı sayı hesaplamalarının kaçınılmaz hesaplama hassasiyeti sorunları vardır. Akıllı sözleşmeler yazarken, özellikle önemli ekonomik/finansal kararların oranları veya faiz oranları ile ilgili hesaplamalarda ondalıklı sayı hesaplamalarının kullanılmasını önerilmez.
Rust dilinde kayan noktalı sayılar IEEE 754 standardını kullanır ve 2 tabanlı bilimsel notasyon ile temsil edilir. Bazı ondalık sayılar ( gibi 0.7), sınırlı uzunluktaki kayan nokta sayılarıyla kesin olarak temsil edilemez ve "yuvarlama" olayı yaşanabilir.
Örneğin, NEAR blok zincirinde 10 kullanıcıya 0.7 NEAR token dağıtıldığında:
pas
#[test]
fn precision_test_float() {
let amount: f64 = 0.7;
let divisor: f64 = 10.0;
let result_0 = amount / divisor;
assert_eq!(result_0, 0.07, "");
}
İşlem sonuçları, amount'un değerinin tam olarak 0.7 olmadığını, bunun yerine yaklaşık değerinin 0.69999999999999995559 olduğunu gösteriyor. Bölme işleminin sonucu da kesin değil, beklenen 0.07 yerine 0.06999999999999999.
Bu sorunu çözmek için, sabit noktalı sayılar kullanmayı düşünebilirsiniz. NEAR Protokolü'nde genellikle 1 NEAR = 10^24 yoctoNEAR şeklinde ifade edilir:
pas
#[test]
fn precision_test_integer() {
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;
assert_eq!(result_0, 70_000_000_000_000_000_000_000, "");
}
Bu şekilde sayısal hesaplamanın sonucu elde edilebilir: 0.7 NEAR / 10 = 0.07 NEAR.
2. Rust tamsayı hesaplama hassasiyeti sorunu
2.1 İşlem Sırası
Aynı aritmetik önceliğe sahip çarpma ve bölme işlemlerinin sırası, hesaplama sonucunu doğrudan etkileyebilir:
pas
#[test]
fn precision_test_div_before_mul() {
let a: u128 = 1_0000;
let b: u128 = 10_0000;
let 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,"");
}
İşlem sonucu, result_0 ve result_1'in eşit olmadığını gösteriyor. Bunun nedeni, tam sayı bölmesinin paydanın altındaki hassasiyeti atmasıdır. result_1'i hesaplarken, (a / b) önce hassasiyet kaybına uğrayarak 0'a dönüşür; oysa result_0'ı hesaplarken, a * c'nin hesaplanması hassasiyet kaybını önler.
2.2 çok küçük bir ölçek
Küçük ölçekler de hassasiyet sorunlarına yol açabilir:
pas
#[test]
fn precision_test_decimals() {
let a: u128 = 10;
let b: u128 = 3;
let c: u128 = 4;
let decimal: 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, "");
}
Sonuçlar gösteriyor ki result_0=12, result_1=13, ikincisi beklenen değer 13.3333'e daha yakın.
3. Sayısal Aktüerya için Rust akıllı sözleşmeler nasıl yazılır
Kesinliği artırmak için şu koruma önlemleri alınabilir:
3.1 İşlem sırasını ayarlama
Tam sayı çarpımının tam sayı bölümü öncelikli olması.
3.2 Tam sayıların büyüklüğünü artırma
Daha büyük bir ölçek kullanarak, daha büyük moleküller yaratın. Örneğin, 5.123 NEAR'ı 5.123 * 10^10 = 51_230_000_000 olarak gösterin.
3.3 Hesaplama hassasiyeti kaybı
Hesaplama hassasiyeti kaybının toplamını kaydet:
pas
const USER_NUM: u128 = 3;
u128 {
let dağıtılacak_token = offset + miktar;
let per_user_share = token_to_distribute / USER_NUM;
let recorded_offset = token_to_distribute - per_user_share * USER_NUM;
kaydedilmiş_offset
}
#(
fn record_offset_test)[test] {
let mut offset: u128 = 0;
i için 1..7 {
offset = distribute(to_yocto)"10"(, offset(;
}
}
Bu şekilde dağıtılmayan token'lar geçici olarak saklanabilir ve bir sonraki dağıtımda birlikte verilebilir.
) 3.4 Rust Crate kütüphanesi rust-decimal kullanımı
Bu kütüphane, etkili hassasiyet hesaplamaları ve yuvarlama hatası olmayan ondalık finansal hesaplamalar için uygundur.
) 3.5 Yuvarlama mekanizmasını dikkate alınız
Akıllı sözleşmeler tasarlandığında genellikle "Ben avantaj sağlamak istiyorum, başkaları benim yararım üzerinden kazanç elde edemez" ilkesi benimsenir. Duruma göre aşağı veya yukarı yuvarlama seçilir, nadiren en yakın tam sayıya yuvarlama yapılır.
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.
12 Likes
Reward
12
8
Share
Comment
0/400
SandwichHunter
· 07-16 18:07
rust küçük tavuk yine yere uzandı
View OriginalReply0
WhaleStalker
· 07-16 17:00
Kod hatası gerçekten can sıkıcı...
View OriginalReply0
GhostInTheChain
· 07-15 16:28
rust hala ondalık sayı girmesi gerekiyor... kolay değil
View OriginalReply0
BoredWatcher
· 07-13 18:40
rust kütüphanesi sözleşme yazabilir mi?
View OriginalReply0
GasFeeNightmare
· 07-13 18:35
Hesaplama hassasiyeti, benim gas ücretim gibi sinir bozucu...
View OriginalReply0
EyeOfTheTokenStorm
· 07-13 18:34
Hassasiyet kaybı oranı doğrudan kar-zarar oranını etkiler, kim hala ondalık sayılarla nicelik yapıyor? Kumarbazlar çoktan Rug Pull yaptı değil mi?
Rust akıllı sözleşmelerde sayısal işlem hassasiyeti sorunları ve optimizasyon çözümleri
Rust akıllı sözleşmeler yetiştirme günlüğü (7) Ondalık ve tam sayı işlemleri hassasiyet sorunu
Bu yazıda Rust akıllı sözleşmelerindeki ondalık ve tam sayı işlemlerinin hassasiyet sorunları ile sayısal aktüerya akıllı sözleşmelerinin nasıl yazılacağı tartışılacaktır.
1. Kesirli sayıların hesaplama hassasiyeti sorunu
Rust dilinin yerel olarak ondalıklı sayı hesaplamalarını desteklemesine rağmen, ondalıklı sayı hesaplamalarının kaçınılmaz hesaplama hassasiyeti sorunları vardır. Akıllı sözleşmeler yazarken, özellikle önemli ekonomik/finansal kararların oranları veya faiz oranları ile ilgili hesaplamalarda ondalıklı sayı hesaplamalarının kullanılmasını önerilmez.
Rust dilinde kayan noktalı sayılar IEEE 754 standardını kullanır ve 2 tabanlı bilimsel notasyon ile temsil edilir. Bazı ondalık sayılar ( gibi 0.7), sınırlı uzunluktaki kayan nokta sayılarıyla kesin olarak temsil edilemez ve "yuvarlama" olayı yaşanabilir.
Örneğin, NEAR blok zincirinde 10 kullanıcıya 0.7 NEAR token dağıtıldığında:
pas #[test] fn precision_test_float() { let amount: f64 = 0.7;
let divisor: f64 = 10.0;
let result_0 = amount / divisor;
assert_eq!(result_0, 0.07, ""); }
İşlem sonuçları, amount'un değerinin tam olarak 0.7 olmadığını, bunun yerine yaklaşık değerinin 0.69999999999999995559 olduğunu gösteriyor. Bölme işleminin sonucu da kesin değil, beklenen 0.07 yerine 0.06999999999999999.
Bu sorunu çözmek için, sabit noktalı sayılar kullanmayı düşünebilirsiniz. NEAR Protokolü'nde genellikle 1 NEAR = 10^24 yoctoNEAR şeklinde ifade edilir:
pas #[test] fn precision_test_integer() { 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; assert_eq!(result_0, 70_000_000_000_000_000_000_000, ""); }
Bu şekilde sayısal hesaplamanın sonucu elde edilebilir: 0.7 NEAR / 10 = 0.07 NEAR.
2. Rust tamsayı hesaplama hassasiyeti sorunu
2.1 İşlem Sırası
Aynı aritmetik önceliğe sahip çarpma ve bölme işlemlerinin sırası, hesaplama sonucunu doğrudan etkileyebilir:
pas #[test] fn precision_test_div_before_mul() { let a: u128 = 1_0000; let b: u128 = 10_0000; let c: u128 = 20;
}
İşlem sonucu, result_0 ve result_1'in eşit olmadığını gösteriyor. Bunun nedeni, tam sayı bölmesinin paydanın altındaki hassasiyeti atmasıdır. result_1'i hesaplarken, (a / b) önce hassasiyet kaybına uğrayarak 0'a dönüşür; oysa result_0'ı hesaplarken, a * c'nin hesaplanması hassasiyet kaybını önler.
2.2 çok küçük bir ölçek
Küçük ölçekler de hassasiyet sorunlarına yol açabilir:
pas #[test] fn precision_test_decimals() { let a: u128 = 10; let b: u128 = 3; let c: u128 = 4; let decimal: u128 = 100_0000;
}
Sonuçlar gösteriyor ki result_0=12, result_1=13, ikincisi beklenen değer 13.3333'e daha yakın.
3. Sayısal Aktüerya için Rust akıllı sözleşmeler nasıl yazılır
Kesinliği artırmak için şu koruma önlemleri alınabilir:
3.1 İşlem sırasını ayarlama
Tam sayı çarpımının tam sayı bölümü öncelikli olması.
3.2 Tam sayıların büyüklüğünü artırma
Daha büyük bir ölçek kullanarak, daha büyük moleküller yaratın. Örneğin, 5.123 NEAR'ı 5.123 * 10^10 = 51_230_000_000 olarak gösterin.
3.3 Hesaplama hassasiyeti kaybı
Hesaplama hassasiyeti kaybının toplamını kaydet:
pas const USER_NUM: u128 = 3;
u128 { let dağıtılacak_token = offset + miktar; let per_user_share = token_to_distribute / USER_NUM; let recorded_offset = token_to_distribute - per_user_share * USER_NUM; kaydedilmiş_offset }
#( fn record_offset_test)[test] { let mut offset: u128 = 0; i için 1..7 { offset = distribute(to_yocto)"10"(, offset(; } }
Bu şekilde dağıtılmayan token'lar geçici olarak saklanabilir ve bir sonraki dağıtımda birlikte verilebilir.
) 3.4 Rust Crate kütüphanesi rust-decimal kullanımı
Bu kütüphane, etkili hassasiyet hesaplamaları ve yuvarlama hatası olmayan ondalık finansal hesaplamalar için uygundur.
) 3.5 Yuvarlama mekanizmasını dikkate alınız
Akıllı sözleşmeler tasarlandığında genellikle "Ben avantaj sağlamak istiyorum, başkaları benim yararım üzerinden kazanç elde edemez" ilkesi benimsenir. Duruma göre aşağı veya yukarı yuvarlama seçilir, nadiren en yakın tam sayıya yuvarlama yapılır.
![]###https://img-cdn.gateio.im/webp-social/moments-6e8b4081214a69423fc7ae022d05c728.webp###