Dans la programmation des smart contracts, la question de la précision des calculs numériques est particulièrement importante. Cet article explorera les problèmes courants d'exactitude numérique dans les smart contracts Rust et leurs solutions.
1. Problème de précision des opérations sur les nombres à virgule flottante
Le langage Rust prend en charge nativement les opérations sur les nombres à virgule flottante, mais ces opérations présentent des problèmes de précision de calcul inévitables. Lors du traitement de ratios ou de taux d'intérêt impliquant des décisions économiques/financières importantes, il n'est pas recommandé d'utiliser des opérations sur les nombres à virgule flottante.
Le type de point flottant double f64 dans le langage Rust suit la norme IEEE 754 et utilise la notation scientifique avec une base de 2. Certains décimales ( comme 0.7) ne peuvent pas être représentées avec précision avec un nombre à virgule flottante de longueur finie, ce qui entraîne un phénomène de "ronde".
Par exemple, lors de la distribution de 0,7 NEAR aux 10 utilisateurs sur la chaîne de blocs NEAR :
rouille
let amount: f64 = 0.7;
let divisor: f64 = 10.0;
let result_0 = amount / divisor;
La valeur réelle de amount est 0.69999999999999995559, le résultat de result_0 est 0.06999999999999999, au lieu de l'attendu 0.07.
Pour résoudre ce problème, il est possible d'envisager l'utilisation de la représentation des nombres à virgule fixe. Dans le protocole NEAR, on utilise généralement 10^24 comme dénominateur, c'est-à-dire 1 NEAR = 10^24 yoctoNEAR. La méthode de calcul modifiée est la suivante :
rouille
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;
Cela permet d'obtenir un résultat de calcul précis : 0,7 NEAR / 10 = 0,07 NEAR.
2. Problème de précision des calculs d'entiers en Rust
Bien que l'utilisation de calculs entiers puisse résoudre certains problèmes de précision des nombres à virgule flottante, il existe encore des facteurs qui affectent la précision des calculs.
2.1 Ordre des opérations
La multiplication et la division ayant la même priorité arithmétique, leur ordre peut directement influencer le résultat du calcul. Par exemple :
rouille
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");
Le résultat de result_0 et result_1 est différent, car la division entière abandonne la précision inférieure au diviseur.
2.2 trop petite magnitude
Lorsqu'il s'agit de calculs à des ordres de grandeur plus petits, cela peut également entraîner des problèmes de précision :
rouille
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");
Le résultat de result_0 et result_1 est différent, et result_1 est plus proche de la valeur attendue réelle.
3. Comment écrire des smart contracts Rust pour l'évaluation numérique
Pour améliorer la précision des calculs numériques dans les smart contracts Rust, les mesures suivantes peuvent être prises :
3.1 Ajuster l'ordre des opérations
Faire en sorte que la multiplication des entiers ait la priorité sur la division des entiers.
3.2 augmenter l'ordre de grandeur des entiers
Utiliser des ordres de grandeur plus élevés pour créer de plus grandes molécules et améliorer la précision des calculs.
3.3 perte de précision des opérations d'accumulation
Pour les problèmes de précision de calcul entier inévitables, il peut être envisagé d'enregistrer la perte de précision cumulative. Par exemple :
rouille
const USER_NUM: u128 = 3;
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
}
Cette méthode peut compenser progressivement la perte de précision au cours de plusieurs distributions.
( 3.4 Utiliser la bibliothèque Rust Crate rust-decimal
Cette bibliothèque est adaptée aux calculs financiers décimaux nécessitant une précision efficace et sans erreur d'arrondi.
) 3.5 Considérer le mécanisme d'arrondi
Lors de la conception de smart contracts, les problèmes d'arrondi suivent généralement le principe "Je veux en profiter, les autres ne doivent pas me tondre". Choisissez de tronquer vers le bas, vers le haut ou d'arrondir en fonction de la situation.
En adoptant ces méthodes, il est possible d'améliorer considérablement la précision et la fiabilité des calculs numériques dans les smart contracts Rust.
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.
7 J'aime
Récompense
7
3
Partager
Commentaire
0/400
MaticHoleFiller
· Il y a 17h
Coincé toute la journée sur des problèmes de précision, je perds douloureusement tout mon travail.
Voir l'originalRépondre0
StablecoinAnxiety
· Il y a 17h
Ça devient un peu compliqué avec à la fois des algorithmes et de la finance~
Voir l'originalRépondre0
GhostAddressMiner
· Il y a 18h
Un autre exemple typique de transfert de responsabilité pour un problème de précision, en cachette, on ne sait pas combien de fonds ont été encaissés, les données off-chain ne mentent pas.
Rust smart contracts : guide de prévention des pièges et meilleures pratiques
Rust smart contracts dans le calcul numérique
Dans la programmation des smart contracts, la question de la précision des calculs numériques est particulièrement importante. Cet article explorera les problèmes courants d'exactitude numérique dans les smart contracts Rust et leurs solutions.
1. Problème de précision des opérations sur les nombres à virgule flottante
Le langage Rust prend en charge nativement les opérations sur les nombres à virgule flottante, mais ces opérations présentent des problèmes de précision de calcul inévitables. Lors du traitement de ratios ou de taux d'intérêt impliquant des décisions économiques/financières importantes, il n'est pas recommandé d'utiliser des opérations sur les nombres à virgule flottante.
Le type de point flottant double f64 dans le langage Rust suit la norme IEEE 754 et utilise la notation scientifique avec une base de 2. Certains décimales ( comme 0.7) ne peuvent pas être représentées avec précision avec un nombre à virgule flottante de longueur finie, ce qui entraîne un phénomène de "ronde".
Par exemple, lors de la distribution de 0,7 NEAR aux 10 utilisateurs sur la chaîne de blocs NEAR :
rouille let amount: f64 = 0.7;
let divisor: f64 = 10.0;
let result_0 = amount / divisor;
La valeur réelle de amount est 0.69999999999999995559, le résultat de result_0 est 0.06999999999999999, au lieu de l'attendu 0.07.
Pour résoudre ce problème, il est possible d'envisager l'utilisation de la représentation des nombres à virgule fixe. Dans le protocole NEAR, on utilise généralement 10^24 comme dénominateur, c'est-à-dire 1 NEAR = 10^24 yoctoNEAR. La méthode de calcul modifiée est la suivante :
rouille 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;
Cela permet d'obtenir un résultat de calcul précis : 0,7 NEAR / 10 = 0,07 NEAR.
2. Problème de précision des calculs d'entiers en Rust
Bien que l'utilisation de calculs entiers puisse résoudre certains problèmes de précision des nombres à virgule flottante, il existe encore des facteurs qui affectent la précision des calculs.
2.1 Ordre des opérations
La multiplication et la division ayant la même priorité arithmétique, leur ordre peut directement influencer le résultat du calcul. Par exemple :
rouille 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");
Le résultat de result_0 et result_1 est différent, car la division entière abandonne la précision inférieure au diviseur.
2.2 trop petite magnitude
Lorsqu'il s'agit de calculs à des ordres de grandeur plus petits, cela peut également entraîner des problèmes de précision :
rouille 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");
Le résultat de result_0 et result_1 est différent, et result_1 est plus proche de la valeur attendue réelle.
3. Comment écrire des smart contracts Rust pour l'évaluation numérique
Pour améliorer la précision des calculs numériques dans les smart contracts Rust, les mesures suivantes peuvent être prises :
3.1 Ajuster l'ordre des opérations
Faire en sorte que la multiplication des entiers ait la priorité sur la division des entiers.
3.2 augmenter l'ordre de grandeur des entiers
Utiliser des ordres de grandeur plus élevés pour créer de plus grandes molécules et améliorer la précision des calculs.
3.3 perte de précision des opérations d'accumulation
Pour les problèmes de précision de calcul entier inévitables, il peut être envisagé d'enregistrer la perte de précision cumulative. Par exemple :
rouille const USER_NUM: u128 = 3;
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 }
Cette méthode peut compenser progressivement la perte de précision au cours de plusieurs distributions.
( 3.4 Utiliser la bibliothèque Rust Crate rust-decimal
Cette bibliothèque est adaptée aux calculs financiers décimaux nécessitant une précision efficace et sans erreur d'arrondi.
) 3.5 Considérer le mécanisme d'arrondi
Lors de la conception de smart contracts, les problèmes d'arrondi suivent généralement le principe "Je veux en profiter, les autres ne doivent pas me tondre". Choisissez de tronquer vers le bas, vers le haut ou d'arrondir en fonction de la situation.
En adoptant ces méthodes, il est possible d'améliorer considérablement la précision et la fiabilité des calculs numériques dans les smart contracts Rust.
![]###https://img-cdn.gateio.im/webp-social/moments-6e8b4081214a69423fc7ae022d05c728.webp###