paint-brush
Cómo evitar el error de división de enteros en los contratos inteligentespor@dansierrasam79
1,813 lecturas
1,813 lecturas

Cómo evitar el error de división de enteros en los contratos inteligentes

por Daniel Chakraborty6m2023/02/20
Read on Terminal Reader

Demasiado Largo; Para Leer

Cuando comience a aprender Python o Java, utilizará el tipo de datos flotante. En Solidity, estaría usando números del tipo entero con o sin signo. El resultado que obtengas no será el mismo, ya que Solidity no soporta el tipo floatData.
featured image - Cómo evitar el error de división de enteros en los contratos inteligentes
Daniel Chakraborty HackerNoon profile picture
0-item
1-item
2-item

Todos hemos aprendido acerca de los números de punto flotante en la escuela. A diferencia de los números enteros que no tienen puntos decimales.


No es necesario ser un genio de las matemáticas para saber que el número cinco es un número entero, mientras que 5,43 es un número de punto flotante. Claramente, todos estamos familiarizados con el punto decimal que es un claro punto de diferenciación entre los dos.


Por supuesto, no sorprende que los flotantes se usen en los lenguajes de programación e incluso se clasifiquen como un tipo de datos primitivo distinto debido a lo necesario que es para el cálculo diario.

Uso de números de coma flotante en lenguajes de programación

Cuando comience a aprender Python o Java, utilizará el tipo de datos flotante. Particularmente, cuando realizas la operación de división entre dos números de punto flotante.


En Python, incluso si no tiene que declarar un número de punto flotante, dividir dos de estos números puede dar como resultado un número del mismo tipo de datos, como se muestra a continuación:


Programa de Python para dividir dos números de punto flotante


También podemos producir el mismo resultado en Java, incluso si tenemos que declarar explícitamente el tipo de datos primitivo 'flotante' para todas las variables utilizadas.


Programa Java para dividir dos números de punto flotante


Como se puede ver, este tipo de cálculo es necesario para una serie de aplicaciones, y es precisamente por eso que las operaciones con números de coma flotante están disponibles como característica en ambos lenguajes de programación.


De manera muy diferente, si ha estado aprendiendo Solidity, debería haber notado que no incluye el tipo de datos de número de punto flotante.

Cómo Solidity realiza transacciones sin números de coma flotante

En cambio, si ha escrito algún código en Solidity, estaría usando números del tipo entero con signo o sin signo.


Entonces, si desea realizar el mismo cálculo, cinco dividido por dos, como se muestra en la sección anterior, así es como se verá, como parte de un contrato inteligente:


Error de división de enteros: contrato inteligente en Solidity


Sin embargo, el resultado que obtengas no será el mismo, ya que Solidity no soporta el tipo de datos float. Al menos, no todavía.


función obtenerResultado


Específicamente, Solidity redondeará el resultado hacia cero. Lo cual, en este caso, y como se muestra arriba, dará como resultado un valor de dos. Piense en esto como la operación de módulo en ambos números.


Si bien en circunstancias normales, esto no debería importar mucho, hay momentos en que el resultado puede conducir a un error en el cálculo. Por lo que se recomienda evitar o postergar en lo posible la operación de división.

Su primer vistazo al error de división de enteros

Incluso si la regla BODMAS en la escuela requiere que todos los estudiantes de matemáticas realicen el cálculo de la división antes de la multiplicación, esto no se recomienda si tiene que realizar la división de enteros en Solidity.


Descubramos por qué, con este sencillo ejemplo, se realizan multiplicaciones y divisiones con tres números:


Multiplica y divide tres números: contrato inteligente en Solidity


Si ingresa los números uno, tres y cinco al implementar el contrato inteligente, debería obtener el mismo valor para las funciones getResult y getResult2, ¿verdad?


Si usa una calculadora simple, debería obtener un valor flotante de 1,666, que se traduce en uno en Solidez, gracias a la ausencia de valores flotantes.


Desafortunadamente, esto no es lo que sucede cuando verifica los resultados de las funciones getResult y getResult2, como se muestra a continuación:


resultados getResult y getResult2


Si realizamos la división primero, obtenemos un resultado final de cero. A diferencia del valor esperado de uno, cuando pospone esa operación hasta el final en la función getResult.


Como puede ver, incluso si hemos calculado este valor anticipando la ausencia de valores flotantes, todavía surge un error que puede causar una pérdida de precisión. Lo que, a su vez, puede traducirse en una pérdida económica que puede evitarse fácilmente.


Entonces, ¿cómo evitamos el error de división de enteros? Más importante aún, ¿cómo aumentamos la precisión de nuestro cálculo? Veamos las tres formas más comunes de hacer esto.

3 formas de evitar el error de división de enteros

Dado que hay una serie de enfoques para eludir este error, comencemos con la solución más simple y veamos un par más antes de dar por terminado el día.


Método #1: Usa un multiplicador

Ahora, además de colocar la operación de división en último lugar, una forma de asegurarse de no terminar con errores o valores imprecisos es usar un multiplicador. En el siguiente ejemplo, usaremos un multiplicador de 100 junto con los mismos tres números usados anteriormente.


Usando un multiplicador - Smart Contract en Solidity


Ahora, cuando implementa el contrato con el siguiente código y llama a ambas funciones, este es el resultado:

Usando un multiplicador - valores getResult y getResult2


Dado que la salida deseada es 1,666 o 166/100, podemos ver que el valor getResult2 nos proporciona la precisión necesaria cuando el multiplicador funciona junto con los tres números. Eso sí, si no usas el multiplicador como en la función getResult, obtendrás 1.


Donde 0.666 se trunca del resultado, como se esperaba de manera predeterminada cuando usa Solidity. Entonces, para recuperar este valor, todo lo que tienes que hacer es dividir el resultado por el multiplicador.


Como sabrá, Solidity se mueve hacia cero cuando se trata de redondear en el caso de enteros con y sin signo, por lo que esta solución también funciona en el caso de enteros con signo, una vez que implementa y ejecuta el código a continuación con los argumentos menos uno , tres y cinco:


Usando un multiplicador para enteros con signo - Smart Contract en Solidity


Cuando se trata de los valores generados por las funciones para enteros con signo, aquí están:


Usando un multiplicador para enteros con signo - Smart Contract en Solidity


Claramente, también podemos mantener la precisión para los enteros con signo, usando un multiplicador. Aunque hay una forma precisa de redondear los enteros con signo que veremos a continuación.


Método n.º 2: use la división de piso para enteros con signo

Ahora, si uno mira la línea numérica a continuación, el resultado de realizar la división de enteros entre dos enteros sin signo se redondea más cerca de cero. Como en el caso de obtener 1,666, Solidez lo redondea a 1, que es un número menor.


la recta numérica


Sin embargo, cuando se trata de números enteros con signo, un resultado de -1,6666 se redondeará a -1, que es el mayor de los dos números. Por lo tanto, la división de piso debe aplicarse aquí en lugar de la división redondeada a cero que se implementa en Solidity de manera predeterminada. En aras de la precisión, por supuesto.


Realización de división de piso para enteros con signo


Si el tipo de datos flotante estuviera disponible, se calcularía el valor de -1.666. Si bien Solidity redondearía esto a -1, aplicar la división de piso a los enteros con signo lo reducirá a -2.


Cuando llama a las funciones getResult y getResult2, obtenemos el valor como se muestra a continuación para los argumentos menos uno, tres y cinco:


getResult2 da los resultados de división de piso correctos


Como puede ver, getResult calcula el valor utilizando el método de redondeo hacia cero, mientras que getResult2 lo redondea al entero más pequeño aquí, en virtud de la división del suelo.


Método #3: Use la biblioteca ABDKMath64x64

Ahora, para el método final, usaremos la biblioteca ABDKMath64x64, que convierte el resultado de las operaciones de división en números de punto fijo.


Una vez más, se dice que el uso de esta biblioteca mejora la precisión en comparación con el método de redondeo hacia cero que está disponible de forma predeterminada en Solidity. Para comprender el resultado, comparemos los resultados de la suma con la función div, como se muestra a continuación:


Uso de la biblioteca ABDK


Cuando agrega los argumentos 1, 1 y 1 al implementar el contrato inteligente, obtiene los valores, como se muestra a continuación:

Uso de la biblioteca ABDK - Salida


No debería sorprender que la función de suma devuelva un valor entero de dos, con los tres argumentos sumando tanto. En cuanto a la función div, se devuelve un valor int 128 que representa un número de punto fijo de 64,64 bits con signo y con el que puede realizar las operaciones numéricas habituales.

Otras bibliotecas de divisiones enteras a tener en cuenta

Por supuesto, la biblioteca ABDKMath64x64 no es la única que se puede usar para mejorar la precisión además de evitar el error de división de enteros.


Hay varios otros, con algunos ejemplos de Fixidity , DSMath y las bibliotecas BANKEX que usan diferentes formatos de números. Formatos de número que son diferentes del formato de número de punto fijo de 64,64 bits utilizado en el ejemplo anterior. Por lo tanto, si bien estas bibliotecas pueden parecer útiles para explorar, recuerde que sus formatos de número no funcionarán con ninguna de las otras bibliotecas disponibles.