Aritmética en Solidity: Más de lo que parece

Aritmética en Solidity: Más de lo que parece

Cuando trabajamos en Solidity, la aritmética funciona un poco diferente a otros lenguajes de programación. Veamos cuales son las diferencias.

Operaciones Básicas

En Solidity, las operaciones básicas como suma, resta, multiplicación y el uso del módulo (%) se comportan de la forma esperada.

Ejemplos

uint256 suma = 10 + 5; // Resultado: 15
uint256 resta = 20 - 10 // Resultado: 10
uint256 multiplicacion = 5 * 10 // Resultado: 50
uint256 exponente = 5 ** 3; // Resultado: 125
uint256 modulo = 10 % 4; // Resultado: 2

¿Quieres probarlo? Aquí hay un contrato con estas operaciones para que lo ejecutes en Remix:

contract Arithmetic01 {
    function sumFunction() public pure returns (uint256) {
        return 10 + 5;
    }

    function substractionFunction() public pure returns (uint256) {
        return 20 - 5;
    }

    function multiplicationFunction() public pure returns (uint256) {
        return 5 * 10;
    }

    function divisionFunction() public pure returns (uint256) {
        return 50 / 2;
    }

    function exponentiationFunction() public pure returns (uint256) {
        return 5 ** 3;
    }

    function moduloFunction() public pure returns (uint256) {
        return 10 % 4;
    }
}

Aritmética de Enteros: Aquí no hay decimales

Una característica crucial de Solidity es que no tiene números de punto flotante (decimales). Esto significa que si intentas dividir 5 / 2, en las versiones recientes de Solidity el compilador te marcará un error:

uint256 division = 5 / 2;
// Error: TypeError: Return argument type rational_const 5 / 2 is not 
// implicitly convertible to expected type (type of first return variable) 
// uint256.

Si necesitas trabajar con porcentajes o fracciones, debes encontrar alternativas. Por ejemplo, para calcular el 15% de 200, no puedes simplemente hacer 200 * .15. En su lugar, puedes escalar el porcentaje y luego dividir:

uint256 porcentaje = (200 * 15) / 100; // porcentaje == 30

Otro ejemplo con decimales. ¿Cómo obtendrias el 7.5% de 200?:

uint256 porcentaje = (200 * 75) / 1000; // porcentaje == 15

Como trivia, esto es así porque la blockchain debe ser determinística, no puede permitir interpretaciones. Por ejemplo si divides 5 / 3 algunas máquinas dirán 1.666666, otras 1.6666667 y esto causaría problemas de consenso en los nodos.


Overflow y underflow

Overflow es cuando una variable trata de contener un número más grande del que puede guardar, y underflow cuando trata de contener un número más pequeño del que puede guardar. Por ejemplo si tenemos uint8 num = 5 sabemos que un uint no puede guardar un número menor a 0, que pasaría si a num le restamos 10? ¡Eso es underflow!

En versiones modernas de Solidity (>= 0.8.0), las operaciones que resultan en underflow u overflow solamente se revierten.

Por ejemplo:

function subtract(uint256 x, uint256 y) public pure returns (uint256) {
    return x - y; // Revertirá si por ejemplo x = 2, y = 5
}

Si x es 2 y y es 5, el programa no retornará -3. En lugar de eso, detendrá su ejecución (hará un revert).


Overflow/underflow controlado: Usando unchecked

Si realmente necesitas permitir overflow o underflow, puedes usar un bloque unchecked:

uint256 x = 2;
uint256 y = 5;

unchecked {
    uint256 z = x - y; // No hará revert
}

Esto no hará revert, y se puede usar en casos muy específicos para ahorrar gas. Como principiante, es bueno que sepas que existe, pero no estarás usandolo pronto.


La próxima vez que escribas un smart contract, recuerda estas reglas. ¡La seguridad y precisión son esenciales en blockchain! Sigamos explorando. 🚀