Ir al contenido principal

Operadores aritméticos

Introducción

Los operadores aritméticos son fundamentales en cualquier lenguaje de programación, ya que nos permiten realizar cálculos matemáticos con los valores numéricos de nuestras aplicaciones. En JavaScript, estos operadores no solo funcionan con números, sino que también pueden interactuar con otros tipos de datos a través de la conversión automática de tipos que vimos en el artículo anterior.

En este artículo exploraremos los distintos operadores aritméticos disponibles en JavaScript, desde los básicos como suma y resta, hasta otros más específicos como el operador de módulo o exponenciación. Aprenderemos cómo utilizarlos correctamente y qué tener en cuenta para evitar comportamientos inesperados.

Operadores básicos

JavaScript proporciona los operadores matemáticos fundamentales que nos permiten realizar operaciones aritméticas comunes.

Suma (+)

El operador de suma permite sumar dos valores:

let a = 5;
let b = 3;
let suma = a + b;
console.log(suma); // 8

let precioBase = 100;
let iva = 21;
let precioTotal = precioBase + iva;
console.log(precioTotal); // 121

Es importante recordar que el operador + también sirve para concatenar strings. Si alguno de los operandos es un string, JavaScript convertirá el otro a string y realizará una concatenación en lugar de una suma:

let numero = 5;
let texto = "10";
let resultado = numero + texto;
console.log(resultado); // "510" (concatenación)

// Para sumar los valores, debemos convertir el string a número
let numeroTexto = "10";
let resultadoSuma = numero + Number(numeroTexto);
console.log(resultadoSuma); // 15 (suma numérica)

Resta (-)

El operador de resta permite restar el segundo valor del primero:

let a = 10;
let b = 4;
let resta = a - b;
console.log(resta); // 6

let presupuesto = 1000;
let gasto = 750;
let restante = presupuesto - gasto;
console.log(restante); // 250

A diferencia del operador de suma, el operador de resta siempre intenta convertir los valores a números:

let numero = 20;
let texto = "5";
let resultado = numero - texto;
console.log(resultado); // 15 (resto numérico)

// Incluso con strings que no representan números se realiza la conversión 
let textoNoNumerico = "abc";
let resultadoRaro = numero - textoNoNumerico;
console.log(resultadoRaro); // NaN (Not a Number)

Multiplicación (*)

El operador de multiplicación permite multiplicar dos valores:

let a = 6;
let b = 7;
let multiplicacion = a * b;
console.log(multiplicacion); // 42

let cantidad = 5;
let precioUnitario = 12.5;
let precioTotal = cantidad * precioUnitario;
console.log(precioTotal); // 62.5

Al igual que la resta, la multiplicación intenta convertir los valores a números:

let numero = 5;
let texto = "10";
let resultado = numero * texto;
console.log(resultado); // 50 (multiplicación numérica)

División (/)

El operador de división permite dividir el primer valor entre el segundo:

let a = 20;
let b = 4;
let division = a / b;
console.log(division); // 5

let precioTotal = 150;
let cantidadProductos = 6;
let precioUnitario = precioTotal / cantidadProductos;
console.log(precioUnitario); // 25

JavaScript realiza divisiones con decimales por defecto, a diferencia de otros lenguajes que pueden truncar el resultado en divisiones enteras:

let a = 10;
let b = 3;
let division = a / b;
console.log(division); // 3.3333333333333335
Casos especiales en la división

En JavaScript, la división presenta casos especiales que debemos tener en cuenta:

// División por cero
console.log(10 / 0); // Infinity
console.log(-10 / 0); // -Infinity

// Cero dividido por cero
console.log(0 / 0); // NaN

Módulo (resto de la división) (%)

El operador módulo devuelve el resto de la división entera entre dos valores:

let a = 10;
let b = 3;
let modulo = a % b;
console.log(modulo); // 1 (10 dividido por 3 es 3 con resto 1)

let c = 14;
let d = 4;
let modulo2 = c % d;
console.log(modulo2); // 2 (14 dividido por 4 es 3 con resto 2)

El operador módulo es muy útil para:

  1. Comprobar si un número es par o impar:

    let numero = 15;
    let esPar = numero % 2 === 0;
    console.log(esPar); // false (15 es impar)
    
    let otroNumero = 24;
    console.log(otroNumero % 2 === 0); // true (24 es par)
    
  2. Obtener el último dígito de un número:

    let numero = 1234;
    let ultimoDigito = numero % 10;
    console.log(ultimoDigito); // 4
    
  3. Ciclar a través de un rango de valores:

    // Para obtener valores entre 0 y 5 (útil en índices cíclicos)
    for (let i = 0; i < 10; i++) {
        let valorCiclico = i % 6;
        console.log(`El valor ${i} % 6 = ${valorCiclico}`);
    }
    

Exponenciación (**)

El operador de exponenciación (introducido en ES2016/ES7) permite elevar un número a la potencia de otro:

let base = 2;
let exponente = 3;
let resultado = base ** exponente;
console.log(resultado); // 8 (2 elevado a 3 = 2*2*2 = 8)

let cuadrado = 5 ** 2;
console.log(cuadrado); // 25 (5 al cuadrado)

let cubo = 3 ** 3;
console.log(cubo); // 27 (3 al cubo)

// También funciona con exponentes decimales
let raizCuadrada = 16 ** 0.5;
console.log(raizCuadrada); // 4 (raíz cuadrada de 16)

Antes de ES2016, para calcular potencias se utilizaba el método Math.pow():

let antiguaForma = Math.pow(2, 3);
console.log(antiguaForma); // 8

El operador ** es más legible y se recomienda su uso en código moderno.

Incremento (++) y decremento (--)

JavaScript ofrece operadores de incremento y decremento que aumentan o disminuyen el valor de una variable en una unidad.

Operador de incremento (++)

let contador = 5;
contador++; // Equivale a: contador = contador + 1;
console.log(contador); // 6

let indice = 10;
indice++;
console.log(indice); // 11

Operador de decremento (--)

let contador = 5;
contador--; // Equivale a: contador = contador - 1;
console.log(contador); // 4

let indice = 10;
indice--;
console.log(indice); // 9

Posición del operador: prefijo vs. sufijo

Estos operadores se pueden utilizar en dos formas:

  1. Prefijo: El operador va antes de la variable (++variable o --variable)
  2. Sufijo: El operador va después de la variable (variable++ o variable--)

La diferencia es importante cuando se utiliza el resultado en la misma expresión:

// Forma sufijo: primero se utiliza el valor actual, luego se incrementa
let a = 5;
let b = a++;
console.log(a); // 6 (a se incrementó)
console.log(b); // 5 (b tomó el valor original de a antes del incremento)

// Forma prefijo: primero se incrementa, luego se utiliza el nuevo valor
let c = 5;
let d = ++c;
console.log(c); // 6 (c se incrementó)
console.log(d); // 6 (d tomó el valor de c después del incremento)

Esta diferencia es crucial en bucles y otras operaciones donde el orden de evaluación importa:

let contador = 0;

// Ejemplo de uso en un ciclo while
while (contador < 3) {
    console.log(contador++); // Imprime 0, 1, 2
}

contador = 0;
while (contador < 3) {
    console.log(++contador); // Imprime 1, 2, 3
}

Operadores de asignación compuestos

JavaScript proporciona operadores de asignación compuestos que combinan una operación aritmética con una asignación, lo que hace que el código sea más conciso.

Asignación con suma (+=)

let puntos = 10;
puntos += 5; // Equivale a: puntos = puntos + 5;
console.log(puntos); // 15

let mensaje = "Hola";
mensaje += " mundo"; // Funciona también con strings (concatenación)
console.log(mensaje); // "Hola mundo"

Asignación con resta (-=)

let vidas = 100;
vidas -= 25; // Equivale a: vidas = vidas - 25;
console.log(vidas); // 75

Asignación con multiplicación (*=)

let precio = 20;
precio *= 1.21; // Equivale a: precio = precio * 1.21; (añadir 21% de IVA)
console.log(precio); // 24.2

Asignación con división (/=)

let total = 100;
total /= 4; // Equivale a: total = total / 4;
console.log(total); // 25

Asignación con módulo (%=)

let valor = 17;
valor %= 5; // Equivale a: valor = valor % 5;
console.log(valor); // 2

Asignación con exponenciación (**=)

let base = 2;
base **= 3; // Equivale a: base = base ** 3;
console.log(base); // 8

Estos operadores compuestos mejoran la legibilidad del código y reducen la posibilidad de errores, ya que mencionamos la variable solo una vez.

Comportamiento con diferentes tipos de datos

Los operadores aritméticos en JavaScript tienen un comportamiento interesante cuando se utilizan con diferentes tipos de datos:

Con booleanos

Los valores booleanos se convierten a números (true → 1, false → 0):

console.log(true + 1); // 2
console.log(false + 1); // 1
console.log(10 * true); // 10
console.log(10 * false); // 0

Con null y undefined

El valor null se convierte a 0, mientras que undefined generalmente produce NaN:

console.log(10 + null); // 10 (null se convierte a 0)
console.log(10 * null); // 0

console.log(10 + undefined); // NaN
console.log(10 * undefined); // NaN

Con strings

Como vimos anteriormente, el comportamiento varía:

// El operador + concatena si algún operando es string
console.log(5 + "10"); // "510"

// Los otros operadores convierten a números
console.log(10 - "5"); // 5
console.log(10 * "5"); // 50
console.log(10 / "2"); // 5

Casos especiales (NaN, Infinity)

NaN (Not a Number)

NaN es un valor especial que representa un resultado de operación numérica no válido:

console.log(0 / 0); // NaN
console.log(parseInt("Hola")); // NaN
console.log(Math.sqrt(-1)); // NaN (en matemáticas reales)

// Cualquier operación con NaN resulta en NaN
console.log(10 + NaN); // NaN
console.log(NaN * 5); // NaN

// Para comprobar si un valor es NaN
console.log(isNaN(NaN)); // true
console.log(isNaN("texto")); // true (porque "texto" no es un número válido)
console.log(Number.isNaN(NaN)); // true (más estricto, no hace conversión)
console.log(Number.isNaN("texto")); // false (no intenta convertir)

Infinity

Infinity representa el infinito matemático:

console.log(1 / 0); // Infinity
console.log(-1 / 0); // -Infinity

// Operaciones con Infinity
console.log(Infinity + 10); // Infinity
console.log(Infinity - 10); // Infinity
console.log(Infinity * 10); // Infinity
console.log(Infinity / 10); // Infinity
console.log(10 / Infinity); // 0

// Casos especiales
console.log(Infinity + Infinity); // Infinity
console.log(Infinity - Infinity); // NaN
console.log(Infinity * 0); // NaN

Precisión numérica en JavaScript

Es importante mencionar que JavaScript utiliza el estándar IEEE 754 para representar números, lo que puede llevar a resultados inesperados en cálculos con decimales:

console.log(0.1 + 0.2); // 0.30000000000000004 (no exactamente 0.3)

Para operaciones donde la precisión decimal es crítica (como cálculos financieros), es recomendable:

  1. Usar enteros multiplicando por un factor:

    // En lugar de: 0.1 + 0.2
    let resultado = (10 + 20) / 100;
    console.log(resultado); // 0.3
    
  2. Redondear el resultado:

    let suma = 0.1 + 0.2;
    let sumaRedondeada = Math.round(suma * 100) / 100;
    console.log(sumaRedondeada); // 0.3
    
  3. Usar bibliotecas específicas para cálculos de alta precisión en aplicaciones reales.

Resumen

Los operadores aritméticos en JavaScript nos permiten realizar todo tipo de cálculos matemáticos en nuestras aplicaciones. Hemos visto los operadores básicos (suma, resta, multiplicación, división), así como otros más específicos como el módulo y la exponenciación. También hemos explorado los operadores de incremento, decremento y asignación compuesta que facilitan operaciones comunes.

Es importante comprender cómo se comportan estos operadores con diferentes tipos de datos y estar atento a casos especiales como NaN e Infinity. Además, debemos ser conscientes de las limitaciones de precisión en cálculos con decimales y aplicar estrategias adecuadas cuando la exactitud decimal sea crucial.

En el próximo artículo, profundizaremos en los operadores de asignación en JavaScript, expandiendo lo que hemos comenzado a ver con los operadores de asignación compuesta.