paint-brush
Comment contourner l'erreur de division entière dans les contrats intelligentspar@dansierrasam79
1,813 lectures
1,813 lectures

Comment contourner l'erreur de division entière dans les contrats intelligents

par Daniel Chakraborty6m2023/02/20
Read on Terminal Reader

Trop long; Pour lire

Lorsque vous commencerez à apprendre Python ou Java, vous utiliserez le type de données float. Dans Solidity, vous utiliseriez des nombres de type entier signé ou non signé. Le résultat que vous obtiendrez ne sera pas le même, puisque Solidity ne supporte pas le type floatData.
featured image - Comment contourner l'erreur de division entière dans les contrats intelligents
Daniel Chakraborty HackerNoon profile picture
0-item
1-item
2-item

Nous avons tous appris les nombres à virgule flottante à l'école. Contrairement aux nombres entiers qui n'ont pas de points décimaux.


Il n'est pas nécessaire d'être un expert en mathématiques pour savoir que le nombre cinq est un nombre entier alors que 5,43 est un nombre à virgule flottante. De toute évidence, nous connaissons tous le point décimal qui est un point de différenciation clair entre les deux.


Bien sûr, il n'est pas surprenant que les flottants soient utilisés dans les langages de programmation et soient même classés comme un type de données primitif distinct en raison de leur nécessité pour les calculs quotidiens.

Utilisation des nombres à virgule flottante dans les langages de programmation

Lorsque vous commencerez à apprendre Python ou Java, vous utiliserez le type de données float. En particulier, lorsque vous effectuez l'opération de division entre deux nombres à virgule flottante eux-mêmes.


En Python, même si vous n'avez pas à déclarer un nombre à virgule flottante, la division de deux de ces nombres peut entraîner un nombre du même type de données, comme indiqué ci-dessous :


Programme Python pour diviser deux nombres à virgule flottante


Nous pouvons également produire le même résultat en Java, même si nous devons déclarer explicitement le type de données primitif 'float' pour toutes les variables utilisées.


Programme Java pour diviser deux nombres à virgule flottante


Comme on peut le voir, ce type de calcul est nécessaire pour un certain nombre d'applications, et c'est précisément pourquoi les opérations avec des nombres à virgule flottante sont disponibles en tant que fonctionnalité dans ces deux langages de programmation.


Tout à fait différemment, si vous avez appris Solidity, vous avez dû remarquer qu'il n'inclut pas le type de données de nombre à virgule flottante.

Comment Solidity effectue des transactions sans nombres à virgule flottante

Au lieu de cela, si vous avez écrit du code dans Solidity, vous utiliserez des nombres de type entier signé ou non signé.


Donc, si vous souhaitez effectuer le même calcul - cinq divisé par deux - comme indiqué dans la section précédente, voici à quoi cela ressemblera, dans le cadre d'un contrat intelligent :


Erreur de division entière - Smart Contract in Solidity


Cependant, le résultat que vous obtiendrez ne sera pas le même, car Solidity ne prend pas en charge le type de données float. Du moins, pas encore.


fonction getResult


Plus précisément, Solidity arrondira le résultat vers zéro. Ce qui, dans ce cas, et comme indiqué ci-dessus, se traduira par une valeur de deux. Considérez cela comme l'opération modulo sur les deux nombres.


Alors que dans des circonstances normales, cela ne devrait pas avoir beaucoup d'importance, il y a des moments où le résultat peut conduire à une erreur de calcul. C'est pourquoi il est recommandé d'éviter ou de différer au maximum l'opération de division.

Votre premier regard sur l'erreur de division entière

Même si la règle BODMAS à l'école a exigé que tous les étudiants en mathématiques effectuent le calcul de la division avant la multiplication, cela n'est pas recommandé si vous devez effectuer une division entière dans Solidity.


Découvrons pourquoi, avec cet exemple simple, qui effectue une multiplication et une division avec trois nombres :


Multipliez et divisez trois nombres - Smart Contract in Solidity


Si vous entrez les chiffres un, trois et cinq lors du déploiement du contrat intelligent, vous devriez obtenir la même valeur pour les fonctions getResult et getResult2, n'est-ce pas ?


Si vous utilisez une simple calculatrice, vous devriez obtenir une valeur flottante de 1,666, ce qui se traduit par un dans Solidity, grâce à l'absence des valeurs flottantes.


Malheureusement, ce n'est pas ce qui se passe lorsque vous vérifiez les résultats des fonctions getResult et getResult2, comme indiqué ci-dessous :


getResult & getResult2 résultats


Si nous effectuons d'abord la division, nous obtenons un résultat final de zéro. Contrairement à la valeur attendue de un, lorsque vous reportez cette opération à la fin dans la fonction getResult.


Comme vous pouvez le constater, même si nous avons calculé cette valeur en anticipant l'absence de valeurs flottantes, il y a toujours une erreur qui survient et qui peut entraîner une perte de précision. Ce qui, à son tour, peut se traduire par une perte économique qui peut être facilement contournée.


Alors, comment éviter l'erreur de division entière ? Plus important encore, comment pouvons-nous augmenter la précision de nos calculs ? Découvrons les trois façons les plus courantes de le faire.

3 façons d'éviter l'erreur de division entière

Étant donné qu'il existe un certain nombre d'approches pour contourner cette erreur, commençons par la solution la plus simple et examinons-en quelques autres avant de l'appeler un jour.


Méthode #1 : Utiliser un multiplicateur

Maintenant, en plus de placer l'opération de division en dernier, une façon de s'assurer que vous ne vous retrouvez pas avec des erreurs ou des valeurs imprécises est d'utiliser un multiplicateur. Dans l'exemple ci-dessous, nous utiliserons un multiplicateur de 100 avec les trois mêmes nombres utilisés précédemment.


Utiliser un multiplicateur - Smart Contract in Solidity


Maintenant, lorsque vous déployez le contrat avec le code suivant et appelez les deux fonctions, voici le résultat :

Utilisation d'un multiplicateur - valeurs getResult et getResult2


Étant donné que la sortie souhaitée est de 1,666 ou 166/100, nous pouvons voir que la valeur getResult2 nous fournit la précision nécessaire lorsque le multiplicateur fonctionne en conjonction avec les trois nombres. Bien sûr, si vous n'utilisez pas le multiplicateur comme dans la fonction getResult, vous obtiendrez 1.


Où 0,666 est tronqué du résultat, comme prévu par défaut lorsque vous utilisez Solidity. Donc, pour récupérer cette valeur, il suffit de diviser le résultat par le multiplicateur.


Comme vous le savez peut-être, Solidity se rapproche de zéro lorsqu'il s'agit d'arrondir dans le cas d'entiers signés et non signés, donc ce correctif fonctionne également dans le cas d'entiers signés, une fois que vous avez déployé et exécuté le code ci-dessous avec les arguments moins un , trois et cinq :


Utiliser un multiplicateur pour les entiers signés - Smart Contract in Solidity


En ce qui concerne les valeurs générées par les fonctions pour les entiers signés, les voici :


Utiliser un multiplicateur pour les entiers signés - Smart Contract in Solidity


De toute évidence, nous sommes également en mesure de maintenir la précision pour les entiers signés, en utilisant un multiplicateur. Cependant, il existe un moyen précis d'arrondir les entiers signés que nous examinerons ensuite.


Méthode #2 : Utilisez la division de plancher pour les entiers signés

Maintenant, si l'on regarde la droite numérique ci-dessous, le résultat de la division entière entre deux entiers non signés est arrondi plus près de zéro. Comme dans le cas de l'obtention de 1,666, Solidité l'arrondit à 1, qui est un nombre plus petit.


La ligne numérique


Cependant, lorsqu'il s'agit d'entiers signés, un résultat de -1,6666 sera arrondi à -1, qui est le plus grand des deux nombres. Ainsi, la division au sol doit être appliquée ici par opposition à la division arrondie à zéro qui est implémentée dans Solidity par défaut. Par souci de précision, bien sûr.


Exécution de la division d'étage pour les entiers signés


Si le type de données flottant était disponible, la valeur de -1,666 serait calculée. Alors que Solidity arrondirait cette valeur à -1, l'application de la division de plancher aux entiers signés la réduirait à -2.


Lorsque vous appelez les fonctions getResult et getResult2, nous obtenons la valeur comme indiqué ci-dessous pour les arguments moins un, trois et cinq :


getResult2 donne les bons résultats de division d'étage


Comme vous pouvez le constater, getResult calcule la valeur en utilisant l'approche arrondie vers zéro tandis que getResult2 l'arrondit au plus petit entier ici, en vertu de la division du plancher.


Méthode #3 : Utiliser la bibliothèque ABDKMath64x64

Maintenant, pour la dernière méthode, nous allons utiliser la bibliothèque ABDKMath64x64, qui convertit le résultat des opérations de division en nombres à virgule fixe.


Encore une fois, on dit que l'utilisation de cette bibliothèque améliore la précision par opposition à la méthode d'arrondi vers zéro qui est disponible par défaut dans Solidity. Afin de comprendre la sortie, comparons les résultats de l'ajout avec la fonction div, comme indiqué ci-dessous :


Utilisation de la bibliothèque ABDK


Lorsque vous ajoutez les arguments 1, 1 et 1 lors du déploiement du contrat intelligent, vous obtenez les valeurs, comme indiqué ci-dessous :

Utilisation de la bibliothèque ABDK - Sortie


Il ne faut pas s'étonner que la fonction add renvoie une valeur entière de deux, les trois arguments s'additionnant pour autant. Comme pour la fonction div, une valeur int 128 est renvoyée qui représente un nombre à virgule fixe signé de 64,64 bits et avec lequel vous pouvez effectuer les opérations habituelles sur les nombres.

Autres bibliothèques de division entière à considérer

Bien sûr, la bibliothèque ABDKMath64x64 n'est pas la seule à pouvoir être utilisée pour améliorer la précision en plus d'empêcher l'erreur de division entière.


Il y en a plusieurs autres avec quelques exemples comme Fixidity , DSMath et les bibliothèques BANKEX qui utilisent différents formats de nombres. Formats de nombre différents du format de nombre à virgule fixe 64,64 bits utilisé dans l'exemple ci-dessus. Ainsi, bien que ces bibliothèques puissent sembler utiles à explorer, n'oubliez pas que leurs formats de nombres ne fonctionneront avec aucune des autres bibliothèques disponibles.