Techniques et considérations de calcul numérique dans les smart contracts Rust

Rust smart contracts养成日记(7):数值精算

Cet article explorera les problèmes de calcul numérique dans la programmation de smart contracts en Rust, notamment les problèmes de précision des opérations sur les nombres à virgule flottante, les problèmes de précision des calculs entiers, ainsi que la manière d'écrire des smart contracts Rust pour le calcul numérique.

1. Problèmes de précision des calculs en 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 de la rédaction de smart contracts, il est déconseillé d'utiliser des opérations sur les nombres à virgule flottante, en particulier lors du traitement de ratios ou de taux d'intérêt impliquant des décisions économiques/financières importantes.

Le type de flottant à double précision f64 dans le langage Rust suit la norme IEEE 754 et utilise la notation scientifique à base de 2 pour être exprimé. Cependant, certains décimales ( comme 0.7) ne peuvent pas être représentées avec précision par des nombres à virgule flottante de longueur finie, ce qui entraîne un phénomène de "rond".

Prenons l'exemple de la distribution de 0,7 NEAR tokens à dix utilisateurs sur la blockchain NEAR, le résultat de calcul réel peut présenter des inexactitudes :

rouille #[test] fn precision_test_float() { let amount: f64 = 0.7;
let divisor: f64 = 10.0;
let result_0 = amount / divisor;
println!("La valeur du montant : {:.20}", amount); assert_eq!(result_0, 0.07, ""); }

Le résultat de l'exécution montre que la valeur de amount n'est pas exactement 0.7, mais plutôt une valeur très proche de 0.69999999999999995559. De plus, le résultat de l'opération de division devient également imprécis à 0.06999999999999999, au lieu de l'attendu 0.07.

Pour résoudre ce problème, on peut envisager d'utiliser des nombres à virgule fixe. Dans le protocole NEAR, on utilise généralement 10^24 comme dénominateur, c'est-à-dire que 10^24 yoctoNEAR équivaut à 1 jeton NEAR.

Le code de test modifié est le suivant :

rouille #[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, ""); }

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 des opérations sur les entiers puisse résoudre certains problèmes de perte de précision des nombres à virgule flottante dans certains scénarios, les résultats des calculs sur les entiers ne sont pas non plus complètement précis et fiables. Certaines des raisons qui affectent la précision des calculs sur les entiers incluent :

2.1 ordre des opérations

La multiplication et la division ayant la même priorité arithmétique, le changement de leur ordre peut directement affecter le résultat du calcul. Par exemple:

rouille #[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,"");

}

Les résultats des tests montrent que les résultats de calcul de result_0 et result_1 sont différents. Cela est dû au fait que pour la division entière, la précision inférieure au diviseur sera perdue. Lors du calcul de result_1, (a / b) perdra d'abord sa précision de calcul et deviendra 0 ; tandis que lors du calcul de result_0, le calcul de a * c en premier peut éviter la perte de précision.

2.2 une échelle trop petite

Lorsque des calculs de petite échelle sont impliqués, des problèmes de précision peuvent également survenir :

rouille #[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");

println!("{}:{}", result_0, result_1);
assert_eq!(result_0, result_1, "");

}

Les résultats des tests montrent que les résultats de result_0 et result_1 sont différents, et que result_1 = 13 est plus proche de la valeur de calcul attendue de 13.3333....

3. Comment rédiger des smart contracts Rust pour l'évaluation numérique

Pour améliorer la précision, les mesures de protection suivantes peuvent être prises :

3.1 Ajuster l'ordre des opérations

Faire en sorte que la multiplication des entiers soit prioritaire par rapport à la division des entiers.

3.2 augmenter l'ordre de grandeur des entiers

Utilisez une plus grande échelle pour créer des molécules plus grandes. Par exemple, 5.123 NEAR peut être exprimé comme 5.123 * 10^10 = 51_230_000_000.

3.3 perte de précision dans les calculs accumulés

Pour les problèmes de précision des calculs entiers inévitables, il peut être envisagé d'enregistrer la perte de précision cumulée des opérations. Par exemple :

rouille const USER_NUM: u128 = 3;

u128 { let token_to_distribute = offset + amount; let per_user_share = token_to_distribute / USER_NUM; println!("per_user_share {}", per_user_share); let recorded_offset = token_to_distribute - per_user_share * USER_NUM; recorded_offset }

#( fn record_offset_test)[test] { let mut offset: u128 = 0; pour i dans 1..7 { println!("Round {}", i); offset = distribute(to_yocto)"10"(, offset(; println!)"Offset {}\n", offset); } }

Cette méthode permet d'accumuler et de redistribuer les jetons non distribués en raison de la perte de précision.

( 3.4 Utilisation de 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". Selon ce principe, si arrondir à l'entier inférieur est avantageux pour le contrat, alors on arrondit vers le bas ; si arrondir à l'entier supérieur est avantageux pour le contrat, alors on arrondit vers le haut ; l'arrondi au plus proche est rarement adopté car il est difficile de déterminer à qui cela est favorable.

En adoptant ces méthodes, il est possible d'implémenter des calculs numériques plus précis dans des smart contracts Rust, améliorant ainsi la fiabilité et l'équité du contrat.

![]###https://img-cdn.gateio.im/webp-social/moments-6e8b4081214a69423fc7ae022d05c728.webp###

Voir l'original
Cette page peut inclure du contenu de tiers fourni à des fins d'information uniquement. Gate ne garantit ni l'exactitude ni la validité de ces contenus, n’endosse pas les opinions exprimées, et ne fournit aucun conseil financier ou professionnel à travers ces informations. Voir la section Avertissement pour plus de détails.
  • Récompense
  • 8
  • Partager
Commentaire
0/400
ZeroRushCaptainvip
· 07-17 09:17
Ah, ça recommence encore avec ce truc. La dernière fois, c'était un problème de précision qui a entraîné un retour de bâton avec le contrat de Position de verrouillée, j'ai perdu jusqu'à manger de la terre.
Voir l'originalRépondre0
BlockchainFriesvip
· 07-16 10:52
Les flottants, c'est vraiment une arnaque, celui qui les utilise est malchanceux.
Voir l'originalRépondre0
MoonBoi42vip
· 07-15 08:48
Quelle précision des nombres à virgule flottante peut rivaliser avec celle des nombres à virgule fixe~
Voir l'originalRépondre0
OnchainDetectivevip
· 07-14 09:54
Il est évident que l'erreur de précision est justement le point de vulnérabilité que certains bridges cross-chain exploitent, ce qui donne des frissons.
Voir l'originalRépondre0
HashRateHermitvip
· 07-14 09:54
Le problème de précision m'a vraiment tué.
Voir l'originalRépondre0
GateUser-e87b21eevip
· 07-14 09:47
Encore une histoire de points décimaux et de flottants, ça me rend fou.
Voir l'originalRépondre0
BearMarketSurvivorvip
· 07-14 09:45
La précision, ce trou dans lequel personne ne peut échapper, cette personne sait.
Voir l'originalRépondre0
AirdropLickervip
· 07-14 09:35
Le arrondi des nombres à virgule flottante est trop compliqué, j'y ai déjà été piégé.
Voir l'originalRépondre0
  • Épingler
Trader les cryptos partout et à tout moment
qrCode
Scan pour télécharger Gate app
Communauté
Français (Afrique)
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Bahasa Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)