Propiedades de programación

📅 Actualizado en febrero 2026 ✍️ Ángel López ⏱️ 20 min de lectura ✓ Nivel principiante ★ ★ ★ ★ ★ (5/5)

En lógica proposicional, a menudo es necesario transformar una fórmula en otra equivalente para simplificarla, hacerla más legible o adaptarla a un contexto específico. Estas transformaciones se rigen por un conjunto de leyes o reglas que constituyen las propiedades fundamentales del álgebra booleana, la misma matemática que gobierna las condiciones de los programas informáticos.

Dominar estas propiedades es esencial para cualquier programador: permiten simplificar condiciones complejas en sentencias if, while y for, eliminar redundancias, y escribir código más limpio y eficiente. En este artículo estudiaremos cada ley con su formulación teórica, la demostraremos mediante tablas de verdad y la aplicaremos directamente en Java con ejemplos prácticos.

Retrato de George Boole, matemático británico creador del álgebra booleana
George Boole (1815–1864), matemático británico creador del álgebra booleana que fundamenta toda la lógica digital. Imagen: Wikimedia Commons, dominio público.

📖 ¿Qué son las propiedades lógicas?

Las propiedades de la lógica proposicional (también llamadas leyes del álgebra booleana) son equivalencias matemáticas que permiten reescribir una expresión lógica en otra forma sin alterar su valor de verdad. Así como en aritmética sabemos que a × (b + c) = a×b + a×c, en lógica existen reglas análogas para los operadores AND, OR y NOT.

Estas leyes fueron formalizadas por George Boole en su obra The Laws of Thought (1854) y complementadas por Augustus De Morgan. Hoy constituyen la base teórica de los circuitos digitales, los compiladores y la optimización de código.

💡
Concepto clave: Dos fórmulas son equivalentes (≡) si producen el mismo resultado para todas las combinaciones posibles de valores de sus variables. Las propiedades que estudiaremos son equivalencias demostradas.

📊 Tabla resumen de todas las leyes

La siguiente tabla recopila todas las propiedades fundamentales como referencia rápida. Cada una se desarrolla en detalle en las secciones siguientes:

LeyForma con ANDForma con OR
Complementop ∧ ¬p = 0p ∨ ¬p = 1
Idempotenciap ∧ p = pp ∨ p = p
Identidadp ∧ 1 = p  /  p ∧ 0 = 0p ∨ 0 = p  /  p ∨ 1 = 1
Doble negación¬(¬p) = p
Asociación(p ∧ q) ∧ r = p ∧ (q ∧ r)(p ∨ q) ∨ r = p ∨ (q ∨ r)
Distribuciónp ∧ (q ∨ r) = (p∧q) ∨ (p∧r)p ∨ (q ∧ r) = (p∨q) ∧ (p∨r)
Absorciónp ∧ (p ∨ q) = pp ∨ (p ∧ q) = p
De Morgan¬(p ∧ q) = ¬p ∨ ¬q¬(p ∨ q) = ¬p ∧ ¬q

🔄 Ley del complemento

La ley del complemento establece que una proposición combinada con su propia negación produce resultados predecibles: la conjunción siempre es falsa y la disyunción siempre es verdadera.

PropiedadFórmulaEn JavaResultado
Complemento ANDp ∧ ¬p = 0x && !xSiempre false
Complemento ORp ∨ ¬p = 1x || !xSiempre true
NOT falso¬0 = 1!falsetrue
NOT verdadero¬1 = 0!truefalse
Aplicación práctica: Si en tu código encuentras una condición como if (activo && !activo), sabrás instantáneamente que nunca se ejecutará (es una contradicción). Y if (activo || !activo) siempre se ejecutará (es una tautología).

🔁 Ley de idempotencia

La idempotencia indica que aplicar un operador lógico a un valor consigo mismo no altera el resultado:

FórmulaEn JavaSimplificación
p ∧ p = p(x > 5) && (x > 5)x > 5
p ∨ p = p(x > 5) || (x > 5)x > 5

Aunque parece trivial, esta ley es útil para detectar condiciones redundantes en código. Si tras refactorizar un programa encuentras una condición repetida, puedes eliminar el duplicado con total seguridad.

🎯 Ley de identidad

La ley de identidad define cómo se comportan los operadores cuando uno de los operandos es una constante (verdadero o falso):

FórmulaResultadoExplicación
p ∧ 1 = pEl valor de pAND con verdadero no altera p
p ∧ 0 = 0Siempre falsoAND con falso anula todo
p ∨ 0 = pEl valor de pOR con falso no altera p
p ∨ 1 = 1Siempre verdaderoOR con verdadero absorbe todo
Java
boolean activo = true;

// Identidad AND: el true no aporta nada
boolean r1 = activo && true;   // equivale a: activo
boolean r2 = activo && false;  // equivale a: false (siempre)

// Identidad OR: el false no aporta nada
boolean r3 = activo || false;  // equivale a: activo
boolean r4 = activo || true;   // equivale a: true (siempre)

System.out.println(r1 + ", " + r2 + ", " + r3 + ", " + r4);
// true, false, true, true

🔃 Ley de doble negación

La doble negación establece que negar dos veces una proposición devuelve su valor original: ¬(¬p) = p. En Java: !!x equivale a x.

Java
boolean p = true;
System.out.println(!!p);  // true (doble negación = original)

boolean q = false;
System.out.println(!!q);  // false

// ❌ Código redundante:
if (!!esValido) { ... }
// ✅ Simplificado:
if (esValido) { ... }
⚠️
Error común: En revisiones de código es frecuente encontrar dobles negaciones accidentales como if (!(!condicion)). Siempre se pueden simplificar a if (condicion).

🔗 Ley de asociación

La ley de asociación permite reagrupar los operandos sin cambiar el resultado, siempre que el operador sea el mismo:

FórmulaEn Java
(p ∧ q) ∧ r = p ∧ (q ∧ r)(a && b) && c == a && (b && c)
(p ∨ q) ∨ r = p ∨ (q ∨ r)(a || b) || c == a || (b || c)

En la práctica, esto significa que en una cadena de AND o de OR puedes agrupar los términos como prefieras, por ejemplo para mejorar la legibilidad. Java ya evalúa de izquierda a derecha con cortocircuito, pero conceptualmente los paréntesis no afectan al resultado lógico.

📦 Ley de distribución

La distribución permite «repartir» un operador sobre otro, de forma análoga a la propiedad distributiva de la multiplicación sobre la suma:

FórmulaEquivalente en Java
p ∧ (q ∨ r) = (p∧q) ∨ (p∧r)a && (b || c) == (a && b) || (a && c)
p ∨ (q ∧ r) = (p∨q) ∧ (p∨r)a || (b && c) == (a || b) && (a || c)
Java
// Ejemplo: descuento si es cliente VIP Y (compra > 100 O tiene cupón)
boolean esVIP = true;
boolean compraGrande = false;
boolean tieneCupon = true;

// Forma compacta (distribución sin expandir)
boolean descuento1 = esVIP && (compraGrande || tieneCupon);

// Forma expandida (distribución aplicada)
boolean descuento2 = (esVIP && compraGrande) || (esVIP && tieneCupon);

System.out.println(descuento1 == descuento2);  // true (equivalentes)

🧹 Ley de absorción

La absorción es quizás la ley más poderosa para simplificar código, ya que elimina términos completos que resultan redundantes:

FórmulaSimplificaciónMotivo
p ∧ (p ∨ q) = pSolo queda pSi p es false, todo es false. Si p es true, (p ∨ q) es true, y true ∧ true = true = p.
p ∨ (p ∧ q) = pSolo queda pSi p es true, todo es true. Si p es false, (p ∧ q) es false, y false ∨ false = false = p.
Java
boolean esAdmin = true;
boolean tienePermiso = false;

// ❌ Condición con absorción no simplificada
if (esAdmin && (esAdmin || tienePermiso)) {
    System.out.println("Acceso");
}

// ✅ Simplificada por absorción: solo necesitamos esAdmin
if (esAdmin) {
    System.out.println("Acceso");
}

🧮 Leyes de De Morgan

Retrato de Augustus De Morgan, matemático británico que formuló las leyes de De Morgan
Augustus De Morgan (1806–1871), matemático británico cuyas leyes son fundamentales en lógica y programación. Imagen: Wikimedia Commons, dominio público.

Las leyes de De Morgan son probablemente las propiedades más utilizadas en programación. Describen cómo se distribuye la negación sobre las operaciones AND y OR:

LeyFórmula lógicaEn Java
Primera ley¬(p ∧ q) = ¬p ∨ ¬q!(a && b) == (!a || !b)
Segunda ley¬(p ∨ q) = ¬p ∧ ¬q!(a || b) == (!a && !b)

La regla es sencilla: al negar una expresión compuesta, se niegan todos los operandos y se cambia el operador (AND pasa a OR y viceversa).

Java
int edad = 15;
boolean tienePermiso = false;

// Condición original: NO (es mayor de edad Y tiene permiso)
boolean original = !(edad >= 18 && tienePermiso);

// Aplicando De Morgan: es menor de edad O no tiene permiso
boolean deMorgan = (edad < 18) || !tienePermiso;

System.out.println("Original: " + original);    // true
System.out.println("De Morgan: " + deMorgan);    // true
System.out.println("¿Iguales? " + (original == deMorgan));  // true
Consejo práctico: Cuando veas una negación delante de paréntesis con && o ||, aplica De Morgan para «distribuir» la negación. El código resultante casi siempre es más fácil de leer: !(a && b)!a || !b.

☕ Aplicación práctica en Java

El siguiente programa demuestra todas las leyes de forma sistemática, verificando que cada par de expresiones produce el mismo resultado para todas las combinaciones de valores:

VerificadorLeyes.java
public class VerificadorLeyes {

    static boolean verificar2vars(String nombre,
            java.util.function.BiFunction<Boolean,Boolean,Boolean> f1,
            java.util.function.BiFunction<Boolean,Boolean,Boolean> f2) {
        boolean[] vals = {true, false};
        boolean ok = true;
        for (boolean p : vals) {
            for (boolean q : vals) {
                if (!f1.apply(p, q).equals(f2.apply(p, q))) {
                    ok = false;
                }
            }
        }
        System.out.printf("  %-25s → %s%n", nombre, ok ? "✅ Verificada" : "❌ Falla");
        return ok;
    }

    public static void main(String[] args) {
        System.out.println("=== Verificación de leyes lógicas ===\n");

        // Complemento
        verificar2vars("Complemento AND",
            (p, q) -> p && !p,
            (p, q) -> false);

        verificar2vars("Complemento OR",
            (p, q) -> p || !p,
            (p, q) -> true);

        // Idempotencia
        verificar2vars("Idempotencia AND",
            (p, q) -> p && p,
            (p, q) -> p);

        verificar2vars("Idempotencia OR",
            (p, q) -> p || p,
            (p, q) -> p);

        // Identidad
        verificar2vars("Identidad AND true",
            (p, q) -> p && true,
            (p, q) -> p);

        verificar2vars("Identidad OR false",
            (p, q) -> p || false,
            (p, q) -> p);

        // Doble negación
        verificar2vars("Doble negación",
            (p, q) -> !!p,
            (p, q) -> p);

        // De Morgan
        verificar2vars("De Morgan 1ª ley",
            (p, q) -> !(p && q),
            (p, q) -> !p || !q);

        verificar2vars("De Morgan 2ª ley",
            (p, q) -> !(p || q),
            (p, q) -> !p && !q);

        // Distribución
        verificar2vars("Distribución AND/OR",
            (p, q) -> p && (p || q),  // absorción: resultado = p
            (p, q) -> p);

        // Absorción
        verificar2vars("Absorción OR/AND",
            (p, q) -> p || (p && q),
            (p, q) -> p);
    }
}

🔬 Demostración de equivalencias

Las leyes permiten demostrar que dos fórmulas son equivalentes mediante transformaciones paso a paso. Veamos un ejemplo clásico:

Demostrar que: ¬(p → q) ≡ p ∧ ¬q

PasoExpresiónLey aplicada
1¬(p → q)Punto de partida
2¬((¬p) ∨ q)Definición de implicación: p→q ≡ ¬p ∨ q
3¬(¬p) ∧ ¬qDe Morgan: ¬(A ∨ B) = ¬A ∧ ¬B
4p ∧ ¬qDoble negación: ¬(¬p) = p

✅ Partiendo de ¬(p → q) y aplicando tres leyes, llegamos a p ∧ ¬q. Queda demostrada la equivalencia.

Java
// Verificación por tabla de verdad
boolean[] v = {true, false};
System.out.println("  p\t  q\t  ¬(p→q)\t  p∧¬q\t  ¿Iguales?");
for (boolean p : v) {
    for (boolean q : v) {
        boolean f1 = !(!p || q);    // ¬(p → q)
        boolean f2 = p && !q;       // p ∧ ¬q
        System.out.printf("  %s\t  %s\t  %s\t\t  %s\t  %s%n",
            p, q, f1, f2, f1 == f2 ? "✓" : "✗");
    }
}
// Las 4 filas muestran ✓: equivalencia demostrada

❌ Errores frecuentes

🔹 Error 1: aplicar De Morgan sin cambiar el operador

Java
// ❌ Error: negar operandos PERO NO cambiar el operador
// !(a && b) NO es igual a (!a && !b)
boolean a = true, b = false;
System.out.println(!(a && b));     // true
System.out.println(!a && !b);      // false ← ¡DIFERENTE!

// ✅ Correcto: negar operandos Y cambiar el operador
System.out.println(!a || !b);      // true ← Ahora sí coincide

🔹 Error 2: confundir distribución con asociación

La asociación reagrupa sin cambiar operadores: (a && b) && c = a && (b && c). La distribución mezcla operadores diferentes: a && (b || c) = (a && b) || (a && c). Confundirlas lleva a transformaciones incorrectas.

🔹 Error 3: no verificar con tabla de verdad

Cuando simplificamos una condición en el código, siempre conviene verificar con las 4 (o 8) combinaciones posibles. Un solo caso mal transformado puede introducir un bug sutil y difícil de detectar.

📝 Ejercicios prácticos

Ejercicio 1: Identificar la ley aplicada

Para cada par de expresiones, indica qué ley lógica se ha aplicado:

a) !(x && y)!x || !y

b) a && (a || b)a

c) (p || q) || rp || (q || r)

d) !!activoactivo

Ejercicio 2: Simplificar condiciones

Simplifica las siguientes expresiones Java aplicando las leyes lógicas apropiadas:

a) !(edad >= 18 || tienePermiso)

b) esAdmin && (esAdmin || esEditor)

c) activo && true && !(!valido)

Ejercicio 3: Demostrar una equivalencia

Demuestra que ¬(p ∨ (¬p ∧ q)) es equivalente a ¬p ∧ ¬q. Hazlo de dos formas: mediante transformaciones algebraicas (paso a paso indicando la ley aplicada) y mediante un programa Java que verifique las 4 filas de la tabla de verdad.

❓ Preguntas frecuentes sobre Propiedades de programación

Las dudas más comunes respondidas de forma clara y directa.

Son un conjunto de leyes matemáticas (complemento, idempotencia, identidad, doble negación, asociación, distribución, absorción y De Morgan) que permiten transformar expresiones lógicas en otras equivalentes. En programación se usan para simplificar condiciones en sentencias if, while y otras estructuras de control, haciendo el código más legible y eficiente.
Las leyes de De Morgan permiten reescribir la negación de expresiones compuestas: NOT(p AND q) equivale a (NOT p) OR (NOT q), y NOT(p OR q) equivale a (NOT p) AND (NOT q). En Java esto se traduce en que !(a && b) es igual a (!a || !b). Son esenciales para simplificar condiciones complejas y para hacer el código más legible.
La ley de idempotencia establece que p AND p = p y p OR p = p. En Java significa que (x > 5 && x > 5) es equivalente a simplemente (x > 5). Aunque parece obvio, es común encontrar condiciones redundantes en código que se pueden simplificar aplicando esta ley.
La ley de distribución permite expandir o factorizar expresiones: p AND (q OR r) = (p AND q) OR (p AND r). La ley de absorción simplifica eliminando términos redundantes: p AND (p OR q) = p. La absorción es más radical porque elimina completamente una parte de la expresión, mientras que la distribución la reorganiza.
Hay dos métodos principales: mediante tablas de verdad (comparando que ambas fórmulas producen el mismo resultado para todas las combinaciones de entrada) o mediante transformaciones algebraicas (aplicando las leyes lógicas paso a paso para convertir una fórmula en la otra). En Java se puede verificar programáticamente evaluando ambas expresiones con todos los valores posibles.
Valora este artículo

💬 Foro de discusión

¿Tienes dudas sobre Propiedades de programación? Comparte tu pregunta con la comunidad.

¿Tienes cuenta? o comenta como invitado ↓

Todavía no hay mensajes. ¡Sé el primero en participar!