GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
gcd.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2004-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include "dNDArray.h"
31 #include "CNDArray.h"
32 #include "fNDArray.h"
33 #include "fCNDArray.h"
34 #include "lo-mappers.h"
35 #include "oct-binmap.h"
36 
37 #include "defun.h"
38 #include "error.h"
39 #include "ovl.h"
40 
41 static double
42 simple_gcd (double a, double b)
43 {
45  error ("gcd: all values must be integers");
46 
47  double aa = fabs (a);
48  double bb = fabs (b);
49 
50  while (bb != 0)
51  {
52  double tt = fmod (aa, bb);
53  aa = bb;
54  bb = tt;
55  }
56 
57  return aa;
58 }
59 
60 // Don't use the Complex and FloatComplex typedefs because we need to
61 // refer to the actual float precision FP in the body (and when gcc
62 // implements template aliases from C++0x, can do a small fix here).
63 template <typename FP>
64 static void
65 divide (const std::complex<FP>& a, const std::complex<FP>& b,
66  std::complex<FP>& q, std::complex<FP>& r)
67 {
68  FP qr = std::floor ((a/b).real () + 0.5);
69  FP qi = std::floor ((a/b).imag () + 0.5);
70 
71  q = std::complex<FP> (qr, qi);
72 
73  r = a - q*b;
74 }
75 
76 template <typename FP>
77 static std::complex<FP>
78 simple_gcd (const std::complex<FP>& a, const std::complex<FP>& b)
79 {
80  if (! octave::math::isinteger (a.real ())
81  || ! octave::math::isinteger (a.imag ())
82  || ! octave::math::isinteger (b.real ())
83  || ! octave::math::isinteger (b.imag ()))
84  error ("gcd: all complex parts must be integers");
85 
86  std::complex<FP> aa = a;
87  std::complex<FP> bb = b;
88 
89  if (abs (aa) < abs (bb))
90  std::swap (aa, bb);
91 
92  while (abs (bb) != 0)
93  {
94  std::complex<FP> qq, rr;
95  divide (aa, bb, qq, rr);
96  aa = bb;
97  bb = rr;
98  }
99 
100  return aa;
101 }
102 
103 template <typename T>
104 static octave_int<T>
106 {
107  T aa = a.abs ().value ();
108  T bb = b.abs ().value ();
109 
110  while (bb != 0)
111  {
112  T tt = aa % bb;
113  aa = bb;
114  bb = tt;
115  }
116 
117  return aa;
118 }
119 
120 static double
121 extended_gcd (double a, double b, double& x, double& y)
122 {
124  error ("gcd: all values must be integers");
125 
126  double aa = fabs (a);
127  double bb = fabs (b);
128 
129  double xx, lx, yy, ly;
130  xx = 0, lx = 1;
131  yy = 1, ly = 0;
132 
133  while (bb != 0)
134  {
135  double qq = std::floor (aa / bb);
136  double tt = fmod (aa, bb);
137 
138  aa = bb;
139  bb = tt;
140 
141  double tx = lx - qq*xx;
142  lx = xx;
143  xx = tx;
144 
145  double ty = ly - qq*yy;
146  ly = yy;
147  yy = ty;
148  }
149 
150  x = (a >= 0 ? lx : -lx);
151  y = (b >= 0 ? ly : -ly);
152 
153  return aa;
154 }
155 
156 template <typename FP>
157 static std::complex<FP>
158 extended_gcd (const std::complex<FP>& a, const std::complex<FP>& b,
159  std::complex<FP>& x, std::complex<FP>& y)
160 {
161  if (! octave::math::isinteger (a.real ())
162  || ! octave::math::isinteger (a.imag ())
163  || ! octave::math::isinteger (b.real ())
164  || ! octave::math::isinteger (b.imag ()))
165  error ("gcd: all complex parts must be integers");
166 
167  std::complex<FP> aa = a;
168  std::complex<FP> bb = b;
169  bool swapped = false;
170  if (abs (aa) < abs (bb))
171  {
172  std::swap (aa, bb);
173  swapped = true;
174  }
175 
176  std::complex<FP> xx, lx, yy, ly;
177  xx = 0, lx = 1;
178  yy = 1, ly = 0;
179 
180  while (abs(bb) != 0)
181  {
182  std::complex<FP> qq, rr;
183  divide (aa, bb, qq, rr);
184  aa = bb;
185  bb = rr;
186 
187  std::complex<FP> tx = lx - qq*xx;
188  lx = xx;
189  xx = tx;
190 
191  std::complex<FP> ty = ly - qq*yy;
192  ly = yy;
193  yy = ty;
194  }
195 
196  x = lx;
197  y = ly;
198 
199  if (swapped)
200  std::swap (x, y);
201 
202  return aa;
203 }
204 
205 template <typename T>
206 static octave_int<T>
209 {
210  T aa = a.abs ().value ();
211  T bb = b.abs ().value ();
212  T xx, lx, yy, ly;
213  xx = 0, lx = 1;
214  yy = 1, ly = 0;
215 
216  while (bb != 0)
217  {
218  T qq = aa / bb;
219  T tt = aa % bb;
220  aa = bb;
221  bb = tt;
222 
223  T tx = lx - qq*xx;
224  lx = xx;
225  xx = tx;
226 
227  T ty = ly - qq*yy;
228  ly = yy;
229  yy = ty;
230  }
231 
232  x = octave_int<T> (lx) * a.signum ();
233  y = octave_int<T> (ly) * b.signum ();
234 
235  return aa;
236 }
237 
238 template <typename NDA>
239 static octave_value
241 {
242  typedef typename NDA::element_type T;
244 
245  if (a.is_scalar_type () && b.is_scalar_type ())
246  {
247  // Optimize scalar case.
248  T aa = octave_value_extract<T> (a);
249  T bb = octave_value_extract<T> (b);
250  retval = simple_gcd (aa, bb);
251  }
252  else
253  {
254  NDA aa = octave_value_extract<NDA> (a);
255  NDA bb = octave_value_extract<NDA> (b);
256  retval = binmap<T> (aa, bb, simple_gcd, "gcd");
257  }
258 
259  return retval;
260 }
261 
262 // Dispatcher
263 static octave_value
264 do_simple_gcd (const octave_value& a, const octave_value& b)
265 {
268  b.builtin_type ());
269  switch (btyp)
270  {
271  case btyp_double:
272  if (a.issparse () && b.issparse ())
273  {
274  retval = do_simple_gcd<SparseMatrix> (a, b);
275  break;
276  }
277  OCTAVE_FALLTHROUGH;
278 
279  case btyp_float:
280  retval = do_simple_gcd<NDArray> (a, b);
281  break;
282 
283 #define MAKE_INT_BRANCH(X) \
284  case btyp_ ## X: \
285  retval = do_simple_gcd<X ## NDArray> (a, b); \
286  break
287 
288  MAKE_INT_BRANCH (int8);
289  MAKE_INT_BRANCH (int16);
290  MAKE_INT_BRANCH (int32);
291  MAKE_INT_BRANCH (int64);
292  MAKE_INT_BRANCH (uint8);
293  MAKE_INT_BRANCH (uint16);
294  MAKE_INT_BRANCH (uint32);
295  MAKE_INT_BRANCH (uint64);
296 
297 #undef MAKE_INT_BRANCH
298 
299  case btyp_complex:
300  retval = do_simple_gcd<ComplexNDArray> (a, b);
301  break;
302 
303  case btyp_float_complex:
304  retval = do_simple_gcd<FloatComplexNDArray> (a, b);
305  break;
306 
307  default:
308  error ("gcd: invalid class combination for gcd: %s and %s\n",
309  a.class_name ().c_str (), b.class_name ().c_str ());
310  }
311 
312  if (btyp == btyp_float)
313  retval = retval.float_array_value ();
314 
315  return retval;
316 }
317 
318 template <typename NDA>
319 static octave_value
322 {
323  typedef typename NDA::element_type T;
325 
326  if (a.is_scalar_type () && b.is_scalar_type ())
327  {
328  // Optimize scalar case.
329  T aa = octave_value_extract<T> (a);
330  T bb = octave_value_extract<T> (b);
331  T xx, yy;
332  retval = extended_gcd (aa, bb, xx, yy);
333  x = xx;
334  y = yy;
335  }
336  else
337  {
338  NDA aa = octave_value_extract<NDA> (a);
339  NDA bb = octave_value_extract<NDA> (b);
340 
341  dim_vector dv = aa.dims ();
342  if (aa.numel () == 1)
343  dv = bb.dims ();
344  else if (bb.numel () != 1 && bb.dims () != dv)
345  octave::err_nonconformant ("gcd", a.dims (), b.dims ());
346 
347  NDA gg (dv), xx (dv), yy (dv);
348 
349  const T *aptr = aa.fortran_vec ();
350  const T *bptr = bb.fortran_vec ();
351 
352  bool inca = aa.numel () != 1;
353  bool incb = bb.numel () != 1;
354 
355  T *gptr = gg.fortran_vec ();
356  T *xptr = xx.fortran_vec ();
357  T *yptr = yy.fortran_vec ();
358 
359  octave_idx_type n = gg.numel ();
360  for (octave_idx_type i = 0; i < n; i++)
361  {
362  octave_quit ();
363 
364  *gptr++ = extended_gcd (*aptr, *bptr, *xptr++, *yptr++);
365 
366  aptr += inca;
367  bptr += incb;
368  }
369 
370  x = xx;
371  y = yy;
372 
373  retval = gg;
374  }
375 
376  return retval;
377 }
378 
379 // Dispatcher
380 static octave_value
381 do_extended_gcd (const octave_value& a, const octave_value& b,
383 {
385 
387  b.builtin_type ());
388  switch (btyp)
389  {
390  case btyp_double:
391  case btyp_float:
392  retval = do_extended_gcd<NDArray> (a, b, x, y);
393  break;
394 
395 #define MAKE_INT_BRANCH(X) \
396  case btyp_ ## X: \
397  retval = do_extended_gcd<X ## NDArray> (a, b, x, y); \
398  break
399 
400  MAKE_INT_BRANCH (int8);
401  MAKE_INT_BRANCH (int16);
402  MAKE_INT_BRANCH (int32);
403  MAKE_INT_BRANCH (int64);
404  MAKE_INT_BRANCH (uint8);
405  MAKE_INT_BRANCH (uint16);
406  MAKE_INT_BRANCH (uint32);
407  MAKE_INT_BRANCH (uint64);
408 
409 #undef MAKE_INT_BRANCH
410 
411  case btyp_complex:
412  retval = do_extended_gcd<ComplexNDArray> (a, b, x, y);
413  break;
414 
415  case btyp_float_complex:
416  retval = do_extended_gcd<FloatComplexNDArray> (a, b, x, y);
417  break;
418 
419  default:
420  error ("gcd: invalid class combination for gcd: %s and %s\n",
421  a.class_name ().c_str (), b.class_name ().c_str ());
422  }
423 
424  // For consistency.
425  if (a.issparse () && b.issparse ())
426  {
427  retval = retval.sparse_matrix_value ();
428  x = x.sparse_matrix_value ();
429  y = y.sparse_matrix_value ();
430  }
431 
432  if (btyp == btyp_float)
433  {
434  retval = retval.float_array_value ();
435  x = x.float_array_value ();
436  y = y.float_array_value ();
437  }
438 
439  return retval;
440 }
441 
442 DEFUN (gcd, args, nargout,
443  doc: /* -*- texinfo -*-
444 @deftypefn {} {@var{g} =} gcd (@var{a1}, @var{a2}, @dots{})
445 @deftypefnx {} {[@var{g}, @var{v1}, @dots{}] =} gcd (@var{a1}, @var{a2}, @dots{})
446 Compute the greatest common divisor of @var{a1}, @var{a2}, @dots{}.
447 
448 All arguments must be the same size or scalar. For arrays, the greatest common
449 divisor is calculated for each element individually. All elements must be
450 ordinary or Gaussian (complex) integers. Note that for Gaussian integers, the
451 gcd is only unique up to a phase factor (multiplication by 1, -1, i, or -i), so
452 an arbitrary greatest common divisor among the four possible is returned.
453 
454 Optional return arguments @var{v1}, @dots{}, contain integer vectors such
455 that,
456 
457 @tex
458 $g = v_1 a_1 + v_2 a_2 + \cdots$
459 @end tex
460 @ifnottex
461 
462 @example
463 @var{g} = @var{v1} .* @var{a1} + @var{v2} .* @var{a2} + @dots{}
464 @end example
465 
466 @end ifnottex
467 
468 Example code:
469 
470 @example
471 @group
472 gcd ([15, 9], [20, 18])
473  @result{} 5 9
474 @end group
475 @end example
476 
477 @seealso{lcm, factor, isprime}
478 @end deftypefn */)
479 {
480  int nargin = args.length ();
481 
482  if (nargin < 2)
483  print_usage ();
484 
486 
487  if (nargout > 1)
488  {
489  retval.resize (nargin + 1);
490 
491  retval(0) = do_extended_gcd (args(0), args(1), retval(1), retval(2));
492 
493  for (int j = 2; j < nargin; j++)
494  {
495  octave_value x;
496  retval(0) = do_extended_gcd (retval(0), args(j), x, retval(j+1));
497  for (int i = 0; i < j; i++)
499  }
500  }
501  else
502  {
503  retval(0) = do_simple_gcd (args(0), args(1));
504 
505  for (int j = 2; j < nargin; j++)
506  retval(0) = do_simple_gcd (retval(0), args(j));
507  }
508 
509  return retval;
510 }
511 
512 /*
513 %!assert (gcd (200, 300, 50, 35), 5)
514 %!assert (gcd (int16 (200), int16 (300), int16 (50), int16 (35)), int16 (5))
515 %!assert (gcd (uint64 (200), uint64 (300), uint64 (50), uint64 (35)), uint64 (5))
516 %!assert (gcd (18-i, -29+3i), -3-4i)
517 
518 %!test
519 %! p = [953 967];
520 %! u = [953 + i*971, 967 + i*977];
521 %! [d, k(1), k(2)] = gcd (p(1), p(2));
522 %! [z, w(1), w(2)] = gcd (u(1), u(2));
523 %! assert (d, 1);
524 %! assert (sum (p.*k), d);
525 %! assert (abs (z), sqrt (2));
526 %! assert (abs (sum (u.*w)), sqrt (2));
527 
528 %!error <all values must be integers> gcd (1/2, 2)
529 %!error <all complex parts must be integers> gcd (e + i*pi, 1)
530 
531 %!error gcd ()
532 
533 %!test
534 %! s.a = 1;
535 %! fail ("gcd (s)");
536 */
void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
Definition: Array.cc:1011
void assign(const idx_vector &i, const Array< T > &rhs, const T &rfv)
Indexed assignment (always with resize & fill).
Definition: Array.cc:1116
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:95
octave_int< T > signum() const
Definition: oct-inttypes.h:873
octave_int< T > abs() const
Definition: oct-inttypes.h:872
SparseMatrix sparse_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:853
bool issparse(void) const
Definition: ov.h:706
builtin_type_t builtin_type(void) const
Definition: ov.h:643
bool is_scalar_type(void) const
Definition: ov.h:697
std::string class_name(void) const
Definition: ov.h:1256
@ op_el_mul_eq
Definition: ov.h:146
FloatNDArray float_array_value(bool frc_str_conv=false) const
Definition: ov.h:815
dim_vector dims(void) const
Definition: ov.h:500
Definition: mx-defs.h:82
ColumnVector real(const ComplexColumnVector &a)
Definition: dColVector.cc:137
ColumnVector imag(const ComplexColumnVector &a)
Definition: dColVector.cc:143
OCTINTERP_API void print_usage(void)
Definition: defun.cc:53
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:56
void error(const char *fmt,...)
Definition: error.cc:968
static double simple_gcd(double a, double b)
Definition: gcd.cc:42
static octave_value do_extended_gcd(const octave_value &a, const octave_value &b, octave_value &x, octave_value &y)
Definition: gcd.cc:320
static void divide(const std::complex< FP > &a, const std::complex< FP > &b, std::complex< FP > &q, std::complex< FP > &r)
Definition: gcd.cc:65
static octave_value do_simple_gcd(const octave_value &a, const octave_value &b)
Definition: gcd.cc:240
static double extended_gcd(double a, double b, double &x, double &y)
Definition: gcd.cc:121
#define MAKE_INT_BRANCH(X)
F77_RET_T const F77_DBLE * x
octave_idx_type n
Definition: mx-inlines.cc:753
T * r
Definition: mx-inlines.cc:773
bool isinteger(double x)
Definition: lo-mappers.h:218
std::complex< T > floor(const std::complex< T > &x)
Definition: lo-mappers.h:130
void err_nonconformant(const char *op, octave_idx_type op1_len, octave_idx_type op2_len)
builtin_type_t btyp_mixed_numeric(builtin_type_t x, builtin_type_t y)
Determine the resulting type for a possible mixed-type operation.
Definition: ov-base.cc:65
builtin_type_t
Definition: ov-base.h:72
@ btyp_float_complex
Definition: ov-base.h:76
@ btyp_double
Definition: ov-base.h:73
@ btyp_float
Definition: ov-base.h:74
@ btyp_complex
Definition: ov-base.h:75
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811
static T abs(T x)
Definition: pr-output.cc:1678