En el artículo anterior expliqué cómo se resuelven las ecuaciones diofánticas y su relación con las ecuaciones de congruencia. En la presente entrada vamos a ver un programa en Python que las resuelve.
#! /usr/bin/env python # -*- coding: utf-8 -*- # Resuelve ecuaciones diofánticas tipo ax + by = c import sys from sys import argv def extendedEuclideanAlgorithm(old_r, r): negative = False s, old_t = 0, 0 old_s, t = 1, 1 if (r < 0): r = abs(r) negative = True while r > 0: q = old_r / r #MCD: r, old_r = old_r - q * r, r #Coeficiente s: s, old_s = old_s - q * s, s #Coeficiente t: t, old_t = old_t - q * t, t if negative: old_t = old_t * -1 return old_r, old_s, old_t a = long(argv[1]) b = long(argv[2]) c = long(argv[3]) mcd, s, t = extendedEuclideanAlgorithm(a, b) if c % mcd == 0: a1, b1, c1 = -a / mcd, b / mcd, c / mcd x1, y1 = s * c1, t * c1 print "x = {0}{1:+d}k" . format(x1, b1) print "y = {0}{1:+d}k" . format(y1, a1) else: print "No tiene solución"
Para calcuar 23x -4y = 11 hacemos:
vic@LESBIAN:~/mates$ ./diofanticas.py 23 -4 11 x = -11-4k y = -66-23k
Aplicando el concepto de clase de equivalencia, tal y como se explica en el anterior artículo, podemos computar la forma paramétrica más simplificada como muestra el siguiente programa:
#! /usr/bin/env python # -*- coding: utf-8 -*- # Resuelve ecuaciones diofánticas tipo ax + by = c # El primero par x e y es la forma parmétrica más simplificada import sys from sys import argv def extendedEuclideanAlgorithm(old_r, r): negative = False s, old_t = 0, 0 old_s, t = 1, 1 if (r < 0): r = abs(r) negative = True while r > 0: q = old_r / r #MCD: r, old_r = old_r - q * r, r #Coeficiente s: s, old_s = old_s - q * s, s #Coeficiente t: t, old_t = old_t - q * t, t if negative: old_t = old_t * -1 return old_r, old_s, old_t a = long(argv[1]) b = long(argv[2]) c = long(argv[3]) mcd, s, t = extendedEuclideanAlgorithm(a, b) if c % mcd == 0: a1, b1, c1 = a / mcd, b / mcd, c / mcd x1, y1 = s * c1, t * c1 # Uso abs() pues Python no hace la división Euclídea con cociente negativo equivClass = x1 % abs(b1) print "x = {0}{1:+d}k" . format(equivClass, b1) print "y = {0}{1:+d}k" . format((c1 - (a1 * equivClass)) / b1, -a1) print "x = {0}{1:+d}k" . format(x1, b1) print "y = {0}{1:+d}k" . format(y1, -a1) else: print "No tiene solución"
Este es el resultado de diferentes ejecuciones:
vic@LESBIAN:~/mates$ ./diofanticas.py 4 7 29 x = 2+7k y = 3-4k x = 58+7k y = -29-4k
vic@LESBIAN:~/mates$ ./diofanticas.py 23 -4 11 x = 1-4k y = 3-23k x = -11-4k y = -66-23k
El uso de la función abs(), que nos devuelve el valor absoluto, es debido a que Python no hace la división Euclídea cuando el cociente es negativo. Los dos pasos:
- q = old_r / r
- old_r = old_r – q * r
Se podrían unificar con la función divmod(), pero me parece menos claro para quien no conoce el lenguaje, siendo los dos pasos más parecidos al pseudocódigo.