Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Lógica Proposicional para Programación

Conceptos lógicos fundamentales aplicados a contratos, aserciones y verificación de código

Universidad Nacional de Río Negro

La lógica proposicional es la herramienta formal que permite razonar sobre la veracidad o falsedad de afirmaciones dentro del software. En programación, su aplicación es directa: desde la escritura de estructuras condicionales simples hasta la especificación y verificación formal de programas mediante contratos (precondiciones, postcondiciones e invariantes).

Esta guía introduce los conectivos lógicos, las equivalencias fundamentales y su correlato con las aserciones en el código.


1. Proposiciones y conectivos lógicos

Una proposición es una afirmación declarativa que puede ser únicamente verdadera (V) o falsa (F). En código, una proposición se representa típicamente mediante expresiones booleanas o variables de tipo bool (en C, #include <stdbool.h>).

Conectivos lógicos fundamentales

Los conectivos lógicos permiten combinar proposiciones atómicas para formar proposiciones compuestas. A continuación se presentan los conectivos principales, su notación lógica y su traducción al lenguaje C:

ConectivoSímbolo lógicoOperador en CDefinición informal
Negación¬P\neg P!PEs verdadera si y solo si PP es falsa.
ConjunciónP∧QP \land QP && QEs verdadera si y solo si tanto PP como QQ son verdaderas.
DisyunciónP∨QP \lor QP || QEs verdadera si al menos una de las dos proposiciones es verdadera.
Condicional (Implicación)P  ⟹  QP \implies Q(No nativo)Representa “Si ocurre PP, entonces se cumple QQ”.
Bicondicional (Equivalencia)P  ⟺  QP \iff QP == QEs verdadera si ambas tienen el mismo valor de verdad.

2. La Implicación Lógica (P  ⟹  QP \implies Q) y su rol en Contratos

El condicional o implicación, denotado por P  ⟹  QP \implies Q, es el bloque constructivo de las precondiciones y postcondiciones en el diseño por contrato.

Tabla de verdad de la implicación

La implicación P  ⟹  QP \implies Q solo es falsa cuando el antecedente (PP) es verdadero y el consecuente (QQ) es falso. En cualquier otro caso, la implicación es verdadera:

PPQQP  ⟹  QP \implies QComentario pedagógico
VVVEl antecedente se cumple y la promesa se respeta.
VFFEl antecedente se cumple pero la promesa falla (violación del contrato).
FVVEl antecedente no se cumple; no hay obligación (cumplimiento por vacuidad).
FFVEl antecedente no se cumple; no hay obligación (cumplimiento por vacuidad).

Equivalencia lógica fundamental: Implicación Material

Dado que en C/C++ y Java no existe un operador nativo para la implicación lógica, debés traducirla utilizando conectivos elementales. La ley de implicación material establece la siguiente equivalencia:

P  ⟹  Q≡¬P∨QP \implies Q \equiv \neg P \lor Q

En código, esta equivalencia se traduce de la siguiente manera:

// Para verificar formalmente que P implica Q:
assert(!P || Q);

3. Leyes lógicas esenciales y simplificación de código

El uso de equivalencias lógicas permite reescribir condiciones complejas en el código de forma más legible y eficiente, reduciendo la carga cognitiva.

Leyes de De Morgan

Estas leyes describen cómo distribuir la negación sobre una conjunción o una disyunción:

  1. Negación de una conjunción:

    ¬(P∧Q)≡¬P∨¬Q\neg(P \land Q) \equiv \neg P \lor \neg Q

    En C: !(P && Q) es lógicamente equivalente a !P || !Q.

  2. Negación de una disyunción:

    ¬(P∨Q)≡¬P∧¬Q\neg(P \lor Q) \equiv \neg P \land \neg Q

    En C: !(P || Q) es lógicamente equivalente a !P && !Q.

Ejemplo de refactorización de código

Considerá el siguiente bloque condicional que valida si un puntero no es nulo y el valor de su nodo es válido:

// Condición compleja y redundante
if (!(ptr != NULL && ptr->valor > 0))
{
    // Manejo de error
}

Aplicando la primera Ley de De Morgan, podés reescribir la condición eliminando la negación externa:

¬(ptr≠NULL∧ptr->valor>0)≡¬(ptr≠NULL)∨¬(ptr->valor>0)\neg(\text{ptr} \neq \text{NULL} \land \text{ptr->valor} > 0) \equiv \neg(\text{ptr} \neq \text{NULL}) \lor \neg(\text{ptr->valor} > 0)

Lo cual equivale a:

ptr==NULL∨ptr->valor≤0\text{ptr} == \text{NULL} \lor \text{ptr->valor} \le 0

Refactorizando el código:

if (ptr == NULL || ptr->valor <= 0)
{
    // Manejo de error
}

4. Ejercicios

Poné a prueba tu comprensión de la lógica proposicional aplicada al código con los siguientes ejercicios.