PROGRAMACIÓN EN C++ – CLASE 20

(Creado por el analista de sistemas y docente Leonel Iván Saafigueroa)


ALGORITMO DE LUHN

Creado por un científico de IBM, el algoritmo de Luhn es utilizado en la verificación de números de identificación, como en las tarjetas de crédito o el IMEI de los teléfonos móviles.


Son números que usamos todos los días, muy pocas veces nos preguntamos quién los crea, o los motivos por los cuales se dice que solo deben ser compartidos con personas de confianza. El número de las tarjetas consta de 16 dígitos, están separados en grupos de 4 para poder identificarlos mejor, no es porque cada grupo de 4 dígitos signifique una cosa, aunque todo depende de quien emita la tarjeta.

El ingeniero informático Hans Peter Luhn, diseñó en 1954 un algoritmo basado en el principio del módulo aritmético (suma matemática mod-10), que permite la identificación de posibles errores durante la digitación o transmisión de una cantidad considerable de números, por ejemplo durante la digitación de un número de tarjeta por una persona en un formulario web.
Su algoritmo se conoce como “algoritmo o fórmula de Luhn” o “algoritmo de módulo 10“.

Para generar el dígito de verificación empleando el algoritmo de Luhn se deben seguir estos pasos:

1. En una secuencia de dígitos dada, el dígito de verificación será el último valor, que en principio se desconoce.
2. Partiendo desde la primera posición, se multiplica cada dígito de posición impar por 2. Si el resultado es un número de dos dígitos, entonces se suman estos dos valores, o también podemos restarle 9, el resultado sería el mismo.
3. Se suman todos los dígitos obtenidos.
4. Calculamos el resto de dividir el resultado por 10 (esto en matemáticas se denomina el MOD 10), luego la diferencia que obtenemos entre 10 y este resto nos dará como resultado el dígito verificador (sería la diferencia que falta para llegar al siguiente múltiplo de 10).



Veamos el código (comentado línea por línea):

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// LUHN1
#include <iostream>
#include <cstdlib>
using namespace std;
int main() {
// Solicitar al usuario que ingrese los 16 dígitos de la tarjeta.
string ingreso;
cout << "Ingrese los 16 dígitos de su tarjeta: ";
cin >> ingreso;
// Verificar si la longitud del ingreso es exactamente 16 caracteres.
if (ingreso.length() == 16) {
// Declarar un arreglo para almacenar los 16 dígitos como enteros.
int tarjeta[16];
// Convertir cada carácter del string a un entero y almacenarlo en el arreglo.
for (int i = 0; i < 16; ++i) {
tarjeta[i] = ingreso[i] - '0'; // Restamos '0' para convertir caracteres ASCII a enteros.
}
// Calcular la suma verificador siguiendo las reglas del algoritmo Luhn.
int verificador = 0;
for (int i = 0; i < 15; i += 2) { // Iterar sobre cada segundo dígito.
tarjeta[i] *= 2; // Duplicar el valor del dígito.
if (tarjeta[i] > 9) { // Si el resultado es mayor a 9, restarle 9.
tarjeta[i] -= 9;
}
}
// Sumar todos los valores resultantes del cálculo anterior.
for (int i = 0; i < 15; ++i) {
verificador += tarjeta[i];
}
// Calcular el dígito verificador final.
if (verificador % 10 == 0) {
verificador = 0;
} else {
verificador = 10 - (verificador % 10);
}
// Validar si el dígito verificador calculado coincide con el último dígito ingresado.
if (verificador == tarjeta[15]) {
cout << "El número de la tarjeta ES CORRECTO." << endl;
} else {
cout << "El número de la tarjeta NO ES CORRECTO." << endl;
}
} else {
// Mostrar un mensaje de error si la longitud del ingreso no es 16 caracteres.
cout << "Error. Debe ingresar 16 dígitos." << endl;
}
return 0;
}
// LUHN1 #include <iostream> #include <cstdlib> using namespace std; int main() { // Solicitar al usuario que ingrese los 16 dígitos de la tarjeta. string ingreso; cout << "Ingrese los 16 dígitos de su tarjeta: "; cin >> ingreso; // Verificar si la longitud del ingreso es exactamente 16 caracteres. if (ingreso.length() == 16) { // Declarar un arreglo para almacenar los 16 dígitos como enteros. int tarjeta[16]; // Convertir cada carácter del string a un entero y almacenarlo en el arreglo. for (int i = 0; i < 16; ++i) { tarjeta[i] = ingreso[i] - '0'; // Restamos '0' para convertir caracteres ASCII a enteros. } // Calcular la suma verificador siguiendo las reglas del algoritmo Luhn. int verificador = 0; for (int i = 0; i < 15; i += 2) { // Iterar sobre cada segundo dígito. tarjeta[i] *= 2; // Duplicar el valor del dígito. if (tarjeta[i] > 9) { // Si el resultado es mayor a 9, restarle 9. tarjeta[i] -= 9; } } // Sumar todos los valores resultantes del cálculo anterior. for (int i = 0; i < 15; ++i) { verificador += tarjeta[i]; } // Calcular el dígito verificador final. if (verificador % 10 == 0) { verificador = 0; } else { verificador = 10 - (verificador % 10); } // Validar si el dígito verificador calculado coincide con el último dígito ingresado. if (verificador == tarjeta[15]) { cout << "El número de la tarjeta ES CORRECTO." << endl; } else { cout << "El número de la tarjeta NO ES CORRECTO." << endl; } } else { // Mostrar un mensaje de error si la longitud del ingreso no es 16 caracteres. cout << "Error. Debe ingresar 16 dígitos." << endl; } return 0; }
// LUHN1
#include <iostream>
#include <cstdlib>

using namespace std;

int main() {
  // Solicitar al usuario que ingrese los 16 dígitos de la tarjeta.
  string ingreso;
  cout << "Ingrese los 16 dígitos de su tarjeta: ";
  cin >> ingreso;

  // Verificar si la longitud del ingreso es exactamente 16 caracteres.
  if (ingreso.length() == 16) {
    // Declarar un arreglo para almacenar los 16 dígitos como enteros.
    int tarjeta[16];

    // Convertir cada carácter del string a un entero y almacenarlo en el arreglo.
    for (int i = 0; i < 16; ++i) {
      tarjeta[i] = ingreso[i] - '0'; // Restamos '0' para convertir caracteres ASCII a enteros.
    }

    // Calcular la suma verificador siguiendo las reglas del algoritmo Luhn.
    int verificador = 0;
    for (int i = 0; i < 15; i += 2) { // Iterar sobre cada segundo dígito.
      tarjeta[i] *= 2;          // Duplicar el valor del dígito.
      if (tarjeta[i] > 9) {       // Si el resultado es mayor a 9, restarle 9.
        tarjeta[i] -= 9;
      }
    }

    // Sumar todos los valores resultantes del cálculo anterior.
    for (int i = 0; i < 15; ++i) {
      verificador += tarjeta[i];
    }

    // Calcular el dígito verificador final.
    if (verificador % 10 == 0) {
      verificador = 0;
    } else {
      verificador = 10 - (verificador % 10);
    }

    // Validar si el dígito verificador calculado coincide con el último dígito ingresado.
    if (verificador == tarjeta[15]) {
      cout << "El número de la tarjeta ES CORRECTO." << endl;
    } else {
      cout << "El número de la tarjeta NO ES CORRECTO." << endl;
    }

  } else {
    // Mostrar un mensaje de error si la longitud del ingreso no es 16 caracteres.
    cout << "Error. Debe ingresar 16 dígitos." << endl;
  }

  return 0;
}



En el siguiente ejemplo nos pondremos en el lugar de la entidad bancaria que emite las tarjetas, y ver cómo calcular directamente el dígito verificador.

Son necesarias solo unas pequeñas modificaciones para mostrar directamente como resultado el dígito verificador. Además se debe de ingresar 15 dígitos en vez de 16.

Veamos el código (comentado línea por línea):

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// LUHN2
#include <iostream>
#include <cstdlib>
using namespace std;
int main() {
// Solicitar al usuario que ingrese los 15 dígitos para calcular el verificador.
string ingreso;
cout << "Ingrese 15 números para generar el Dígito verificador: ";
cin >> ingreso;
// Verificar si la longitud del ingreso es exactamente 15 caracteres.
if (ingreso.length() == 15) {
// Declarar un arreglo para almacenar los 15 dígitos como enteros.
int tarjeta[15];
// Convertir cada carácter del string a un entero y almacenarlo en el arreglo.
for (int i = 0; i < 15; ++i) {
tarjeta[i] = ingreso[i] - '0'; // Restamos '0' para convertir caracteres ASCII a enteros.
}
// Calcular la suma verificador siguiendo las reglas del algoritmo Luhn.
int verificador = 0;
for (int i = 0; i < 15; i += 2) { // Iterar sobre cada segundo dígito.
tarjeta[i] *= 2; // Duplicar el valor del dígito.
if (tarjeta[i] > 9) { // Si el resultado es mayor a 9, restarle 9.
tarjeta[i] -= 9;
}
}
// Sumar todos los valores resultantes del cálculo anterior.
for (int i = 0; i < 15; ++i) {
verificador += tarjeta[i];
}
// Calcular el dígito verificador final.
if (verificador % 10 == 0) {
verificador = 0;
} else {
verificador = 10 - (verificador % 10);
}
// Mostrar el dígito resultante.
cout << "El dígito verificador es: " << verificador << endl;
} else {
// Mostrar un mensaje de error si la longitud del ingreso no es 15 caracteres.
cout << "Error. Debe ingresar 15 dígitos." << endl;
}
return 0;
}
// LUHN2 #include <iostream> #include <cstdlib> using namespace std; int main() { // Solicitar al usuario que ingrese los 15 dígitos para calcular el verificador. string ingreso; cout << "Ingrese 15 números para generar el Dígito verificador: "; cin >> ingreso; // Verificar si la longitud del ingreso es exactamente 15 caracteres. if (ingreso.length() == 15) { // Declarar un arreglo para almacenar los 15 dígitos como enteros. int tarjeta[15]; // Convertir cada carácter del string a un entero y almacenarlo en el arreglo. for (int i = 0; i < 15; ++i) { tarjeta[i] = ingreso[i] - '0'; // Restamos '0' para convertir caracteres ASCII a enteros. } // Calcular la suma verificador siguiendo las reglas del algoritmo Luhn. int verificador = 0; for (int i = 0; i < 15; i += 2) { // Iterar sobre cada segundo dígito. tarjeta[i] *= 2; // Duplicar el valor del dígito. if (tarjeta[i] > 9) { // Si el resultado es mayor a 9, restarle 9. tarjeta[i] -= 9; } } // Sumar todos los valores resultantes del cálculo anterior. for (int i = 0; i < 15; ++i) { verificador += tarjeta[i]; } // Calcular el dígito verificador final. if (verificador % 10 == 0) { verificador = 0; } else { verificador = 10 - (verificador % 10); } // Mostrar el dígito resultante. cout << "El dígito verificador es: " << verificador << endl; } else { // Mostrar un mensaje de error si la longitud del ingreso no es 15 caracteres. cout << "Error. Debe ingresar 15 dígitos." << endl; } return 0; }
// LUHN2
#include <iostream>
#include <cstdlib>

using namespace std;

int main() {
  // Solicitar al usuario que ingrese los 15 dígitos para calcular el verificador.
  string ingreso;
  cout << "Ingrese 15 números para generar el Dígito verificador: ";
  cin >> ingreso;

  // Verificar si la longitud del ingreso es exactamente 15 caracteres.
  if (ingreso.length() == 15) {
    // Declarar un arreglo para almacenar los 15 dígitos como enteros.
    int tarjeta[15];

    // Convertir cada carácter del string a un entero y almacenarlo en el arreglo.
    for (int i = 0; i < 15; ++i) {
      tarjeta[i] = ingreso[i] - '0'; // Restamos '0' para convertir caracteres ASCII a enteros.
    }

    // Calcular la suma verificador siguiendo las reglas del algoritmo Luhn.
    int verificador = 0;
    for (int i = 0; i < 15; i += 2) { // Iterar sobre cada segundo dígito.
      tarjeta[i] *= 2;          // Duplicar el valor del dígito.
      if (tarjeta[i] > 9) {       // Si el resultado es mayor a 9, restarle 9.
        tarjeta[i] -= 9;
      }
    }

    // Sumar todos los valores resultantes del cálculo anterior.
    for (int i = 0; i < 15; ++i) {
      verificador += tarjeta[i];
    }

    // Calcular el dígito verificador final.
    if (verificador % 10 == 0) {
      verificador = 0;
    } else {
      verificador = 10 - (verificador % 10);
    }

    // Mostrar el dígito resultante.
    cout << "El dígito verificador es: " << verificador << endl;

  } else {
    // Mostrar un mensaje de error si la longitud del ingreso no es 15 caracteres.
    cout << "Error. Debe ingresar 15 dígitos." << endl;
  }

  return 0;
}

Si ingresamos los siguiente 15 dígitos: “439818598367000“, luego presionamos la tecla ENTER.

El programa nos respondá con la cadena: “El Dígito verificador es: 2“.
Por lo tanto, el número de tarjeta junto a su número verificador seria: “4398185983670002“.

El resultado del programa debe coincidir con nuestros cálculos para funcionar bien.



Veamos el código (comentado línea por línea):

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// LUHN3
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main() {
// Inicializar generador de números aleatorios.
srand(time(NULL)); // Iniciamos la semilla random con la hora.
int ok = 0; // Flag para indicar si se encontró un número válido.
int verificador = 0;
// Dimensionar los arreglos.
int t[16];
int tarjeta[16];
cout << "Generando un nuevo número de tarjeta al azar..." << endl;
while (ok == 0) {
// Generar 16 números aleatorios.
for (int i = 0; i < 16; ++i) {
t[i] = rand() % 10; // Genera un valor entre 0 y 9.
tarjeta[i] = t[i];
}
cout << "Intentando con el número:" << endl;
// Imprimir la tarjeta generada.
for (int i = 0; i < 16; ++i) {
cout << t[i];
}
cout << endl;
// Calcular la suma verificador siguiendo las reglas del algoritmo Luhn.
int verificador = 0;
for (int i = 0; i < 15; i += 2) { // Iterar sobre cada segundo dígito.
tarjeta[i] *= 2; // Duplicar el valor del dígito.
if (tarjeta[i] > 9) { // Si el resultado es mayor a 9, restarle 9.
tarjeta[i] -= 9;
}
}
// Sumar todos los valores resultantes del cálculo anterior.
for (int i = 0; i < 15; ++i) {
verificador += tarjeta[i];
}
// Calcular el dígito verificador final.
if (verificador % 10 == 0) {
verificador = 0;
} else {
verificador = 10 - (verificador % 10);
}
if (verificador == tarjeta[15]) {
cout << "El número de la tarjeta ES CORRECTO: ";
for (int i = 0; i < 16; ++i) {
cout << t[i];
}
cout << endl;
ok = 1; // Se encontró un número válido.
} else {
cout << "El número de la tarjeta NO ES CORRECTO." << endl;
}
}
return 0;
}
// LUHN3 #include <iostream> #include <cstdlib> #include <ctime> using namespace std; int main() { // Inicializar generador de números aleatorios. srand(time(NULL)); // Iniciamos la semilla random con la hora. int ok = 0; // Flag para indicar si se encontró un número válido. int verificador = 0; // Dimensionar los arreglos. int t[16]; int tarjeta[16]; cout << "Generando un nuevo número de tarjeta al azar..." << endl; while (ok == 0) { // Generar 16 números aleatorios. for (int i = 0; i < 16; ++i) { t[i] = rand() % 10; // Genera un valor entre 0 y 9. tarjeta[i] = t[i]; } cout << "Intentando con el número:" << endl; // Imprimir la tarjeta generada. for (int i = 0; i < 16; ++i) { cout << t[i]; } cout << endl; // Calcular la suma verificador siguiendo las reglas del algoritmo Luhn. int verificador = 0; for (int i = 0; i < 15; i += 2) { // Iterar sobre cada segundo dígito. tarjeta[i] *= 2; // Duplicar el valor del dígito. if (tarjeta[i] > 9) { // Si el resultado es mayor a 9, restarle 9. tarjeta[i] -= 9; } } // Sumar todos los valores resultantes del cálculo anterior. for (int i = 0; i < 15; ++i) { verificador += tarjeta[i]; } // Calcular el dígito verificador final. if (verificador % 10 == 0) { verificador = 0; } else { verificador = 10 - (verificador % 10); } if (verificador == tarjeta[15]) { cout << "El número de la tarjeta ES CORRECTO: "; for (int i = 0; i < 16; ++i) { cout << t[i]; } cout << endl; ok = 1; // Se encontró un número válido. } else { cout << "El número de la tarjeta NO ES CORRECTO." << endl; } } return 0; }
// LUHN3
#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

int main() {
  // Inicializar generador de números aleatorios.
  srand(time(NULL)); // Iniciamos la semilla random con la hora.

  int ok = 0; // Flag para indicar si se encontró un número válido.
  int verificador = 0;

  // Dimensionar los arreglos.
  int t[16];
  int tarjeta[16];

  cout << "Generando un nuevo número de tarjeta al azar..." << endl;

  while (ok == 0) {
    // Generar 16 números aleatorios.
    for (int i = 0; i < 16; ++i) {
      t[i] = rand() % 10; // Genera un valor entre 0 y 9.
      tarjeta[i] = t[i];
    }

    cout << "Intentando con el número:" << endl;
    // Imprimir la tarjeta generada.
    for (int i = 0; i < 16; ++i) {
      cout << t[i];
    }
    cout << endl;

// Calcular la suma verificador siguiendo las reglas del algoritmo Luhn.
    int verificador = 0;
    for (int i = 0; i < 15; i += 2) { // Iterar sobre cada segundo dígito.
      tarjeta[i] *= 2;          // Duplicar el valor del dígito.
      if (tarjeta[i] > 9) {       // Si el resultado es mayor a 9, restarle 9.
        tarjeta[i] -= 9;
      }
    }
    // Sumar todos los valores resultantes del cálculo anterior.
    for (int i = 0; i < 15; ++i) {
      verificador += tarjeta[i];
    }
    // Calcular el dígito verificador final.
    if (verificador % 10 == 0) {
      verificador = 0;
    } else {
      verificador = 10 - (verificador % 10);
    }

    if (verificador == tarjeta[15]) {
      cout << "El número de la tarjeta ES CORRECTO: ";
      for (int i = 0; i < 16; ++i) {
        cout << t[i];
      }
      cout << endl;
      ok = 1; // Se encontró un número válido.
    } else {
      cout << "El número de la tarjeta NO ES CORRECTO." << endl;
    }
  }
  return 0;
}



Una última versión de nuestro programa podría ser más óptimo, en vez de elegir 16 dígitos y probar una y otra vez, podría elegir solo los primeros 15 dígitos de forma aleatoria y calcular el dígito verificador, para luego mostrar como resultado un número de tarjeta válido creado de un solo intento.

Veamos el código (comentado línea por línea):

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// LUHN4
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main() {
// Inicializar generador de números aleatorios.
srand(time(NULL)); // Iniciamos la semilla random con la hora.
int verificador = 0;
// Dimensionar los arreglos.
int t[15];
int tarjeta[15];
cout << "Generando número de tarjeta al azar..." << endl;
// Generar 15 números aleatorios.
for (int i = 0; i < 15; ++i) {
t[i] = rand() % 10; // Genera un valor entre 0 y 9.
tarjeta[i] = t[i];
}
// Calcular la suma verificador siguiendo las reglas del algoritmo Luhn.
for (int i = 0; i < 15; i += 2) { // Iterar sobre cada segundo dígito.
tarjeta[i] *= 2; // Duplicar el valor del dígito.
if (tarjeta[i] > 9) { // Si el resultado es mayor a 9, restarle 9.
tarjeta[i] -= 9;
}
}
// Sumar todos los valores resultantes del cálculo anterior.
for (int i = 0; i < 15; ++i) {
verificador += tarjeta[i];
}
// Calcular el dígito verificador final.
if (verificador % 10 == 0) {
verificador = 0;
} else {
verificador = 10 - (verificador % 10);
}
//Mostramos el número de tarjeta generado.
for (int i = 0; i < 15; ++i) {
cout << t[i];
}
cout << verificador;
return 0;
}
// LUHN4 #include <iostream> #include <cstdlib> #include <ctime> using namespace std; int main() { // Inicializar generador de números aleatorios. srand(time(NULL)); // Iniciamos la semilla random con la hora. int verificador = 0; // Dimensionar los arreglos. int t[15]; int tarjeta[15]; cout << "Generando número de tarjeta al azar..." << endl; // Generar 15 números aleatorios. for (int i = 0; i < 15; ++i) { t[i] = rand() % 10; // Genera un valor entre 0 y 9. tarjeta[i] = t[i]; } // Calcular la suma verificador siguiendo las reglas del algoritmo Luhn. for (int i = 0; i < 15; i += 2) { // Iterar sobre cada segundo dígito. tarjeta[i] *= 2; // Duplicar el valor del dígito. if (tarjeta[i] > 9) { // Si el resultado es mayor a 9, restarle 9. tarjeta[i] -= 9; } } // Sumar todos los valores resultantes del cálculo anterior. for (int i = 0; i < 15; ++i) { verificador += tarjeta[i]; } // Calcular el dígito verificador final. if (verificador % 10 == 0) { verificador = 0; } else { verificador = 10 - (verificador % 10); } //Mostramos el número de tarjeta generado. for (int i = 0; i < 15; ++i) { cout << t[i]; } cout << verificador; return 0; }
// LUHN4
#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

int main() {
  // Inicializar generador de números aleatorios.
  srand(time(NULL)); // Iniciamos la semilla random con la hora.

  int verificador = 0;

  // Dimensionar los arreglos.
  int t[15];
  int tarjeta[15];

  cout << "Generando número de tarjeta al azar..." << endl;

  // Generar 15 números aleatorios.
  for (int i = 0; i < 15; ++i) {
    t[i] = rand() % 10; // Genera un valor entre 0 y 9.
    tarjeta[i] = t[i];
  }

// Calcular la suma verificador siguiendo las reglas del algoritmo Luhn.
  for (int i = 0; i < 15; i += 2) { // Iterar sobre cada segundo dígito.
    tarjeta[i] *= 2;                // Duplicar el valor del dígito.
    if (tarjeta[i] > 9) {           // Si el resultado es mayor a 9, restarle 9.
      tarjeta[i] -= 9;
    }
  }
  // Sumar todos los valores resultantes del cálculo anterior.
  for (int i = 0; i < 15; ++i) {
    verificador += tarjeta[i];
  }
  // Calcular el dígito verificador final.
  if (verificador % 10 == 0) {
    verificador = 0;
  } else {
    verificador = 10 - (verificador % 10);
  }

  //Mostramos el número de tarjeta generado.

  for (int i = 0; i < 15; ++i) {
        cout << t[i];
        }
  cout << verificador;

  return 0;
}


TAREA PARA EL HOGAR

Investiga en Internet cuales son los códigos que identifican a las tarjetas de créditos más conocidas, luego crea un programa que permita elegir el tipo de tarjeta y pueda generar números validos al azar.