paint-brush
Como contornar o erro de divisão inteira em contratos inteligentespor@dansierrasam79
1,813 leituras
1,813 leituras

Como contornar o erro de divisão inteira em contratos inteligentes

por Daniel Chakraborty6m2023/02/20
Read on Terminal Reader

Muito longo; Para ler

Ao começar a aprender Python ou Java, você usará o tipo de dados float. No Solidity, você usaria números do tipo inteiro assinado ou não assinado. O resultado obtido não será o mesmo, pois o Solidity não suporta o tipo floatData.
featured image - Como contornar o erro de divisão inteira em contratos inteligentes
Daniel Chakraborty HackerNoon profile picture
0-item
1-item
2-item

Todos nós aprendemos sobre números de ponto flutuante na escola. Ao contrário dos números inteiros que não têm pontos decimais.


Não é preciso ser um gênio da matemática para saber que o número cinco é um número inteiro, enquanto 5,43 é um número de ponto flutuante. Claramente, estamos todos familiarizados com o ponto decimal, que é um claro ponto de diferenciação entre os dois.


Claro, não é nenhuma surpresa que floats sejam usados em linguagens de programação e até mesmo classificados como um tipo de dado primitivo distinto por causa de quão necessário é para a computação diária.

Usando números de ponto flutuante em linguagens de programação

Ao começar a aprender Python ou Java, você usará o tipo de dados float. Particularmente, quando você realiza a operação de divisão entre dois números de ponto flutuante.


Em Python, mesmo que você não precise declarar um número de ponto flutuante, a divisão de dois desses números pode resultar em um número do mesmo tipo de dados, conforme mostrado abaixo:


Programa Python para dividir dois números de ponto flutuante


Também podemos produzir o mesmo resultado em Java, mesmo que tenhamos que declarar explicitamente o tipo de dados primitivo 'float' para todas as variáveis usadas.


Programa Java para dividir dois números de ponto flutuante


Como se pode perceber, esse tipo de cálculo é necessário para uma série de aplicações, e é exatamente por isso que as operações com números de ponto flutuante estão disponíveis como um recurso em ambas as linguagens de programação.


Bem diferente, se você está aprendendo Solidity, você deve ter notado que ele não inclui o tipo de dados de número de ponto flutuante.

Como o Solidity realiza transações sem números de ponto flutuante

Em vez disso, se você escreveu qualquer código no Solidity, você usaria números do tipo inteiro assinado ou não assinado.


Então, se você quiser fazer o mesmo cálculo - cinco dividido por dois - conforme mostrado na seção anterior, veja como ficará, como parte de um contrato inteligente:


Erro de Divisão Inteira - Contrato Inteligente em Solidity


No entanto, o resultado obtido não será o mesmo, pois o Solidity não suporta o tipo de dados float. Pelo menos, não ainda.


função obterresultado


Especificamente, o Solidity arredondará o resultado para zero. O que, neste caso, e conforme mostrado acima, resultará em um valor de dois. Pense nisso como a operação de módulo em ambos os números.


Embora em circunstâncias normais isso não deva importar muito, há momentos em que o resultado pode levar a um erro de cálculo. É por isso que se recomenda evitar ou adiar ao máximo a operação de divisão.

Sua primeira olhada no erro de divisão inteira

Mesmo que a regra do BODMAS na escola exija que todos os alunos de matemática realizem o cálculo da divisão antes da multiplicação, isso não é recomendado se você tiver que realizar a divisão inteira no Solidity.


Vamos descobrir por que, com este exemplo simples, que realiza multiplicação e divisão com três números:


Multiplique e divida Três Números - Smart Contract in Solidity


Se você inserir os números um, três e cinco ao implantar o contrato inteligente, deverá obter o mesmo valor para as funções getResult e getResult2, certo?


Se você usar uma calculadora simples, deverá obter um valor flutuante de 1,666, que se traduz em um no Solidity, graças à ausência dos valores flutuantes.


Infelizmente, não é isso que acontece, quando você verifica os resultados das funções getResult e getResult2, conforme mostrado abaixo:


resultados getResult e getResult2


Se fizermos a divisão primeiro, obteremos um resultado final igual a zero. Ao contrário do valor esperado de um, quando você adia essa operação para o fim na função getResult.


Como você pode ver, mesmo que tenhamos calculado esse valor antecipando a ausência de valores flutuantes, ainda há um erro que pode causar perda de precisão. O que, por sua vez, pode se traduzir em uma perda econômica que pode ser facilmente contornada.


Então, como evitamos o erro de divisão inteira? Mais importante, como aumentamos a precisão de nossa computação? Vamos descobrir as três maneiras mais comuns de fazer isso.

3 maneiras de evitar o erro de divisão inteira

Dado que há várias abordagens para contornar esse erro, vamos começar com a correção mais simples e examinar mais algumas antes de encerrar o dia.


Método #1: Use um multiplicador

Agora, além de colocar a operação de divisão por último, uma maneira de garantir que você não acabe com erros ou valores imprecisos é usar um multiplicador. No exemplo abaixo, usaremos um multiplicador de 100 junto com os mesmos três números usados anteriormente.


Usando um multiplicador - Smart Contract in Solidity


Agora, quando você implanta o contrato com o código a seguir e chama as duas funções, esta é a saída:

Usando um multiplicador - valores getResult e getResult2


Como a saída desejada é 1,666 ou 166/100, podemos ver que o valor getResult2 nos fornece a precisão necessária quando o multiplicador trabalha em conjunto com os três números. Obviamente, se você não usar o multiplicador como na função getResult, obterá 1.


Onde 0,666 é truncado do resultado, como esperado por padrão quando você usa o Solidity. Então, para recuperar esse valor, basta dividir o resultado pelo multiplicador.


Como você deve saber, o Solidity se move em direção a zero quando se trata de arredondar no caso de inteiros assinados e não assinados, então essa correção também funciona no caso de inteiros assinados, uma vez que você implanta e executa o código abaixo com os argumentos menos um , três e cinco:


Usando um multiplicador para números inteiros assinados - Smart Contract in Solidity


Quando se trata dos valores gerados pelas funções para números inteiros com sinal, aqui estão eles:


Usando um multiplicador para números inteiros assinados - Smart Contract in Solidity


Claramente, também podemos manter a precisão para números inteiros com sinal, usando um multiplicador. Embora haja uma maneira precisa de arredondar inteiros com sinal que veremos a seguir.


Método nº 2: Use a divisão de piso para números inteiros com sinal

Agora, se olharmos para a linha numérica abaixo, o resultado da divisão inteira entre dois inteiros sem sinal é arredondado para mais próximo de zero. Como no caso de obter 1,666, o Solidity arredonda para 1, que é um número menor.


a linha numérica


No entanto, quando se trata de números inteiros com sinal, um resultado de -1,6666 será arredondado para -1, que é o maior dos dois números. Portanto, a divisão do piso deve ser aplicada aqui, em oposição à divisão arredondada para zero que é implementada no Solidity por padrão. Por uma questão de precisão, é claro.


Executando divisão de piso para inteiros assinados


Se o tipo de dados float estivesse disponível, o valor de -1,666 seria calculado. Enquanto o Solidity arredondaria para -1, a aplicação da divisão de piso a números inteiros com sinal reduzirá para -2.


Quando você chama as funções getResult e getResult2, obtemos o valor mostrado abaixo para os argumentos menos um, três e cinco:


getResult2 fornece os resultados corretos da divisão do piso


Como você pode ver, getResult calcula o valor usando a abordagem de arredondamento para zero, enquanto getResult2 arredonda para o menor inteiro aqui, em virtude da divisão do piso.


Método #3: Use a biblioteca ABDKMath64x64

Agora, para o método final, usaremos a biblioteca ABDKMath64x64, que converte o resultado das operações de divisão em números de ponto fixo.


Mais uma vez, diz-se que o uso dessa biblioteca melhora a precisão em oposição ao método de arredondamento para zero que está disponível por padrão no Solidity. Para entender a saída, vamos comparar os resultados da adição com a função div, conforme mostrado abaixo:


Usando a biblioteca ABDK


Ao adicionar os argumentos 1, 1 e 1 ao implantar o contrato inteligente, você obtém os valores, conforme mostrado abaixo:

Usando a biblioteca ABDK - Saída


Não deve ser surpresa que a função add retorne um valor inteiro de dois, com os três argumentos somando tanto. Quanto à função div, é retornado um valor int 128 que representa um número de ponto fixo de 64,64 bits com sinal e com o qual você pode executar as operações numéricas usuais.

Outras bibliotecas de divisão de inteiros a serem consideradas

Obviamente, a biblioteca ABDKMath64x64 não é a única que pode ser usada para melhorar a precisão, além de evitar o erro de divisão inteira.


Existem vários outros com alguns exemplos sendo Fixidity , DSMath e as bibliotecas BANKEX que usam formatos numéricos diferentes. Formatos numéricos diferentes do formato numérico de ponto fixo de 64,64 bits usado no exemplo acima. Portanto, embora essas bibliotecas possam parecer úteis para explorar, lembre-se de que seus formatos numéricos não funcionarão com nenhuma das outras bibliotecas disponíveis.