Buku Harian Pengembangan smart contract Rust (7): Perhitungan Nilai
1. Masalah Presisi dalam Operasi Bilangan Desimal
Bahasa Rust secara native mendukung operasi bilangan floating-point, tetapi operasi bilangan floating-point memiliki masalah presisi perhitungan yang tidak dapat dihindari. Saat menulis smart contract, tidak disarankan untuk menggunakan operasi bilangan floating-point, terutama saat menangani rasio atau suku bunga yang melibatkan keputusan ekonomi/keuangan yang penting.
Tipe floating point presisi ganda f64 dalam bahasa Rust mengikuti standar IEEE 754, menggunakan notasi ilmiah dengan basis 2. Beberapa desimal seperti 0.7 tidak dapat diwakili secara akurat dengan floating point berukuran terbatas, yang menyebabkan fenomena "pembulatan".
Dalam pengujian distribusi 0,7 token NEAR kepada sepuluh pengguna di blockchain NEAR, hasil perhitungan floating point tidak akurat:
karat
let amount: f64 = 0.7;
let divisor: f64 = 10.0;
let result_0 = amount / divisor;
nilai amount adalah 0.69999999999999995559, nilai result_0 adalah 0.06999999999999999, bukan 0.07 seperti yang diharapkan.
Untuk mengatasi masalah ini, dapat digunakan bilangan tetap. Dalam NEAR Protocol, biasanya menggunakan cara 1 NEAR = 10^24 yoctoNEAR untuk menyatakannya:
karat
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;
Dengan cara ini, Anda dapat memperoleh hasil perhitungan yang akurat: 0,7 NEAR / 10 = 0,07 NEAR.
2. Masalah Presisi Perhitungan Integer Rust
2.1 Urutan Operasi
Urutan perubahan dari perkalian dan pembagian dengan prioritas aritmatika yang sama dapat langsung mempengaruhi hasil perhitungan. Contohnya:
karat
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");
Hasil dari result_0 dan result_1 berbeda, karena untuk pembagian bilangan bulat, presisi yang lebih kecil dari pembagi akan diabaikan.
2.2 skala yang terlalu kecil
Ketika berurusan dengan nilai desimal, operasi bilangan bulat dapat mengakibatkan kehilangan presisi:
karat
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 * decimal / b) * c / decimal;
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");
Hasil dari result_0 dan result_1 berbeda, result_1 lebih mendekati nilai yang diharapkan.
3. Cara Menulis Kontrak Pintar Rust untuk Aktuaria Numerik
3.1 Menyesuaikan urutan operasi perhitungan
Memprioritaskan perkalian bilangan bulat dibandingkan dengan pembagian bilangan bulat.
3.2 Meningkatkan urutan angka bulat
Gunakan skala yang lebih besar untuk menciptakan molekul yang lebih besar. Misalnya, mewakili 5.123 NEAR sebagai 51_230_000_000 yoctoNEAR.
3.3 Kehilangan presisi akumulasi operasi
Mencatat kehilangan presisi perhitungan yang terakumulasi, dan mengompensasinya dalam perhitungan selanjutnya. Contoh:
karat
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;
recorded_offset
}
( 3.4 Menggunakan pustaka Rust Crate rust-decimal
Perpustakaan ini cocok untuk perhitungan keuangan desimal yang memerlukan akurasi yang efektif dan tidak memiliki kesalahan pembulatan.
) 3.5 Pertimbangkan mekanisme pembulatan
Dalam desain smart contract, masalah pembulatan biasanya mengikuti prinsip "Saya ingin mendapatkan keuntungan, orang lain tidak boleh memanfaatkan saya". Pilih untuk membulatkan ke bawah, membulatkan ke atas, atau pembulatan biasa sesuai situasi.
Halaman ini mungkin berisi konten pihak ketiga, yang disediakan untuk tujuan informasi saja (bukan pernyataan/jaminan) dan tidak boleh dianggap sebagai dukungan terhadap pandangannya oleh Gate, atau sebagai nasihat keuangan atau profesional. Lihat Penafian untuk detailnya.
6 Suka
Hadiah
6
3
Bagikan
Komentar
0/400
BearMarketBuilder
· 08-05 07:58
Lubang float ini benar-benar dalam seperti laut
Lihat AsliBalas0
SelfSovereignSteve
· 08-05 07:53
Floating point number terlalu bermasalah, smart contract pasti meledak, sama sekali tidak berani menggunakannya.
Lihat AsliBalas0
DegenGambler
· 08-05 07:49
Para saudara yang bermain Rust, perhatikan, lubang presisi ini tidak kecil.
Pengembangan smart contract Rust: Teknik perhitungan numerik dan kontrol presisi
Buku Harian Pengembangan smart contract Rust (7): Perhitungan Nilai
1. Masalah Presisi dalam Operasi Bilangan Desimal
Bahasa Rust secara native mendukung operasi bilangan floating-point, tetapi operasi bilangan floating-point memiliki masalah presisi perhitungan yang tidak dapat dihindari. Saat menulis smart contract, tidak disarankan untuk menggunakan operasi bilangan floating-point, terutama saat menangani rasio atau suku bunga yang melibatkan keputusan ekonomi/keuangan yang penting.
Tipe floating point presisi ganda f64 dalam bahasa Rust mengikuti standar IEEE 754, menggunakan notasi ilmiah dengan basis 2. Beberapa desimal seperti 0.7 tidak dapat diwakili secara akurat dengan floating point berukuran terbatas, yang menyebabkan fenomena "pembulatan".
Dalam pengujian distribusi 0,7 token NEAR kepada sepuluh pengguna di blockchain NEAR, hasil perhitungan floating point tidak akurat:
karat let amount: f64 = 0.7;
let divisor: f64 = 10.0; let result_0 = amount / divisor;
nilai amount adalah 0.69999999999999995559, nilai result_0 adalah 0.06999999999999999, bukan 0.07 seperti yang diharapkan.
Untuk mengatasi masalah ini, dapat digunakan bilangan tetap. Dalam NEAR Protocol, biasanya menggunakan cara 1 NEAR = 10^24 yoctoNEAR untuk menyatakannya:
karat 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;
Dengan cara ini, Anda dapat memperoleh hasil perhitungan yang akurat: 0,7 NEAR / 10 = 0,07 NEAR.
2. Masalah Presisi Perhitungan Integer Rust
2.1 Urutan Operasi
Urutan perubahan dari perkalian dan pembagian dengan prioritas aritmatika yang sama dapat langsung mempengaruhi hasil perhitungan. Contohnya:
karat 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");
Hasil dari result_0 dan result_1 berbeda, karena untuk pembagian bilangan bulat, presisi yang lebih kecil dari pembagi akan diabaikan.
2.2 skala yang terlalu kecil
Ketika berurusan dengan nilai desimal, operasi bilangan bulat dapat mengakibatkan kehilangan presisi:
karat 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 * decimal / b) * c / decimal; 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");
Hasil dari result_0 dan result_1 berbeda, result_1 lebih mendekati nilai yang diharapkan.
3. Cara Menulis Kontrak Pintar Rust untuk Aktuaria Numerik
3.1 Menyesuaikan urutan operasi perhitungan
Memprioritaskan perkalian bilangan bulat dibandingkan dengan pembagian bilangan bulat.
3.2 Meningkatkan urutan angka bulat
Gunakan skala yang lebih besar untuk menciptakan molekul yang lebih besar. Misalnya, mewakili 5.123 NEAR sebagai 51_230_000_000 yoctoNEAR.
3.3 Kehilangan presisi akumulasi operasi
Mencatat kehilangan presisi perhitungan yang terakumulasi, dan mengompensasinya dalam perhitungan selanjutnya. Contoh:
karat 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; recorded_offset }
( 3.4 Menggunakan pustaka Rust Crate rust-decimal
Perpustakaan ini cocok untuk perhitungan keuangan desimal yang memerlukan akurasi yang efektif dan tidak memiliki kesalahan pembulatan.
) 3.5 Pertimbangkan mekanisme pembulatan
Dalam desain smart contract, masalah pembulatan biasanya mengikuti prinsip "Saya ingin mendapatkan keuntungan, orang lain tidak boleh memanfaatkan saya". Pilih untuk membulatkan ke bawah, membulatkan ke atas, atau pembulatan biasa sesuai situasi.
![]###https://img-cdn.gateio.im/webp-social/moments-6e8b4081214a69423fc7ae022d05c728.webp###