# HG changeset patch # User Jordi Gutiérrez Hermoso # Date 1285830331 18000 # Node ID 905492c1ed8cbb195456dea9c873ec09c8fede17 # Parent a4d245b374aa79cd17c31f97690e9edfe805691a Implement gcd for Gaussian (complex) integers diff -r a4d245b374aa -r 905492c1ed8c src/ChangeLog --- a/src/ChangeLog Thu Sep 30 02:05:30 2010 -0500 +++ b/src/ChangeLog Thu Sep 30 02:05:31 2010 -0500 @@ -1,3 +1,12 @@ +2010-09-30 Jordi Gutiérrez Hermoso + * DLD-FUNCTIONS/gcd.cc (divide): New function, complex integer + division with remainder. + (simple_gcd): Overload for complex values. + (extended_gcd): Ditto. + (do_simple_gcd): Dispatch for complex gcd. + (do_extended_gcd): Ditto. + (Fgcd): Mention that complex gcd is now also possible. + 2010-09-30 Jordi Gutiérrez Hermoso * DLD-FUNCTIONS/gcd.cc (extended_gcd): Fix bug that didn't diff -r a4d245b374aa -r 905492c1ed8c src/DLD-FUNCTIONS/gcd.cc --- a/src/DLD-FUNCTIONS/gcd.cc Thu Sep 30 02:05:30 2010 -0500 +++ b/src/DLD-FUNCTIONS/gcd.cc Thu Sep 30 02:05:31 2010 -0500 @@ -1,7 +1,7 @@ /* Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 David Bateman -Copyirght (C) 2010 Jaroslav Hajek +Copyright (C) 2010 Jaroslav Hajek, Jordi Gutiérrez Hermoso This file is part of Octave. @@ -36,7 +36,7 @@ #include "error.h" #include "oct-obj.h" -static double +static double simple_gcd (double a, double b) { if (! xisinteger (a) || ! xisinteger (b)) @@ -53,6 +53,47 @@ return aa; } +// Don't use the Complex and FloatComplex typedefs because we need to +// refer to the actual float precision FP in the body (and when gcc +// implements template aliases from C++0x, can do a small fix here). +template +static void +divide(const std::complex& a, const std::complex& b, + std::complex& q, std::complex& r) +{ + FP qr = floor((a/b).real() + 0.5); + FP qi = floor((a/b).imag() + 0.5); + q = std::complex(qr,qi); + r = a - q*b; +} + +template +static std::complex +simple_gcd (const std::complex& a, const std::complex& b) +{ + if ( ! xisinteger (a.real ()) || ! xisinteger(a.imag ()) || + ! xisinteger (b.real ()) || ! xisinteger(b.imag ()) ) + (*current_liboctave_error_handler) + ("gcd: all complex parts must be integers"); + + std::complex aa = a, bb = b; + + if ( abs(aa) < abs(bb) ) + { + std::swap(aa,bb); + } + + while ( abs(bb) != 0) + { + std::complex qq, rr; + divide (aa, bb, qq, rr); + aa = bb; + bb = rr; + } + + return aa; +} + template static octave_int simple_gcd (const octave_int& a, const octave_int& b) @@ -67,7 +108,7 @@ return aa; } -static double +static double extended_gcd (double a, double b, double& x, double& y) { if (! xisinteger (a) || ! xisinteger (b)) @@ -89,12 +130,54 @@ ly = yy; yy = ty; } - x = a >= 0 ? lx : -lx; + x = a >= 0 ? lx : -lx; y = b >= 0 ? ly : -ly; return aa; } +template +static std::complex +extended_gcd (const std::complex& a, const std::complex& b, + std::complex& x, std::complex& y) +{ + if ( ! xisinteger (a.real ()) || ! xisinteger(a.imag ()) || + ! xisinteger (b.real ()) || ! xisinteger(b.imag ()) ) + (*current_liboctave_error_handler) + ("gcd: all complex parts must be integers"); + + std::complex aa = a, bb = b; + bool swapped = false; + if ( abs(aa) < abs(bb) ) + { + std::swap(aa,bb); + swapped = true; + } + + std::complex xx = 0, lx = 1, yy = 1, ly = 0; + while ( abs(bb) != 0) + { + std::complex qq, rr; + divide (aa, bb, qq, rr); + aa = bb; bb = rr; + + std::complex tx = lx - qq*xx; + lx = xx; xx = tx; + + std::complex ty = ly - qq*yy; + ly = yy; yy = ty; + } + + x = lx; + y = ly; + if (swapped) + { + std::swap(x,y); + } + + return aa; +} + template static octave_int extended_gcd (const octave_int& a, const octave_int& b, @@ -178,8 +261,11 @@ MAKE_INT_BRANCH (uint64); #undef MAKE_INT_BRANCH case btyp_complex: + retval = do_simple_gcd (a,b); + break; case btyp_float_complex: - error ("gcd: complex numbers not allowed"); + retval = do_simple_gcd (a,b); + break; default: error ("gcd: invalid class combination for gcd: %s and %s\n", a.class_name ().c_str (), b.class_name ().c_str ()); @@ -275,8 +361,11 @@ MAKE_INT_BRANCH (uint64); #undef MAKE_INT_BRANCH case btyp_complex: + retval = do_extended_gcd (a, b, x, y); + break; case btyp_float_complex: - error ("gcd: complex numbers not allowed"); + retval = do_extended_gcd (a, b, x, y); + break; default: error ("gcd: invalid class combination for gcd: %s and %s\n", a.class_name ().c_str (), b.class_name ().c_str ()); @@ -309,7 +398,10 @@ Compute the greatest common divisor of @var{a1}, @var{a2}, @dots{}. If more\n\ than one argument is given all arguments must be the same size or scalar.\n\ In this case the greatest common divisor is calculated for each element\n\ -individually. All elements must be integers. For example,\n\ +individually. All elements must be ordinary or Gaussian (complex)\n\ +integers. Note that for Gaussian integers, the gcd is not unique up to\n\ +units (multiplication by 1, -1, @var{i} or address@hidden), so an arbitrary\n\ +greatest common divisor amongst four possible is returned. For example,\n\ \n\ @noindent\n\ and\n\ @@ -380,6 +472,7 @@ %!assert(gcd (200, 300, 50, 35), 5) %!assert(gcd (int16(200), int16(300), int16(50), int16(35)), int16(5)) %!assert(gcd (uint64(200), uint64(300), uint64(50), uint64(35)), uint64(5)) +%!assert(gcd (18-i, -29+3i), -3-4i) %!error gcd (); # HG changeset patch # User Jordi Gutiérrez Hermoso # Date 1285830330 18000 # Node ID a4d245b374aa79cd17c31f97690e9edfe805691a # Parent b721e12140ccfb01d15eeeaf4cee8995ca80e996 Fix off-by-one and typo bugs in gcd diff -r b721e12140cc -r a4d245b374aa src/ChangeLog --- a/src/ChangeLog Wed Sep 29 22:08:34 2010 +0200 +++ b/src/ChangeLog Thu Sep 30 02:05:30 2010 -0500 @@ -1,3 +1,9 @@ +2010-09-30 Jordi Gutiérrez Hermoso + + * DLD-FUNCTIONS/gcd.cc (extended_gcd): Fix bug that didn't + distinguish the two output coefficients. + (Fgcd): Fix off-by-one bug and typo from copy-pasted code. + 2010-09-29 Jaroslav Hajek * oct-map.cc (octave_map::contents): Fix off-by-1 error. diff -r b721e12140cc -r a4d245b374aa src/DLD-FUNCTIONS/gcd.cc --- a/src/DLD-FUNCTIONS/gcd.cc Wed Sep 29 22:08:34 2010 +0200 +++ b/src/DLD-FUNCTIONS/gcd.cc Thu Sep 30 02:05:30 2010 -0500 @@ -75,7 +75,7 @@ ("gcd: all values must be integers"); double aa = fabs (a), bb = fabs (b); - double xx = 0, lx = 1, yy = 0, ly = 1; + double xx = 0, lx = 1, yy = 1, ly = 0; while (bb != 0) { double qq = floor (aa / bb); @@ -101,7 +101,7 @@ octave_int& x, octave_int& y) { T aa = a.abs ().value (), bb = b.abs ().value (); - T xx = 0, lx = 1, yy = 0, ly = 1; + T xx = 0, lx = 1, yy = 1, ly = 0; while (bb != 0) { T qq = aa / bb; @@ -350,10 +350,10 @@ for (int j = 2; j < nargin; j++) { octave_value x; - retval(0) = do_extended_gcd (retval(0), args(1), + retval(0) = do_extended_gcd (retval(0), args(j), x, retval(j+1)); for (int i = 0; i < j; i++) - retval(i).assign (octave_value::op_el_mul_eq, x); + retval(i+1).assign (octave_value::op_el_mul_eq, x); if (error_state) break; }