source: git/factory/cf_gcd.cc @ c6ed6f

fieker-DuValspielwiese
Last change on this file since c6ed6f was c6ed6f, checked in by Wilfred Pohl <pohl@…>, 18 years ago
bcontent git-svn-id: file:///usr/local/Singular/svn/trunk@8840 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 16.9 KB
RevLine 
[493c477]1/* emacs edit mode for this file is -*- C++ -*- */
[c6ed6f]2/* $Id: cf_gcd.cc,v 1.34 2005-12-09 09:49:28 pohl Exp $ */
[9bab9f]3
[ab4548f]4#include <config.h>
5
[9bab9f]6#include "assert.h"
[93b061]7#include "debug.h"
8
[9bab9f]9#include "cf_defs.h"
10#include "canonicalform.h"
11#include "cf_iter.h"
12#include "cf_reval.h"
[edb4893]13#include "cf_primes.h"
[fbefc9]14#include "cf_algorithm.h"
[f63dbca]15#include "cf_map.h"
[1b73cc0]16#include "sm_sparsemod.h"
[f63dbca]17#include "fac_util.h"
[71da5e]18#include "ftmpl_functions.h"
[edb4893]19
[f11d7b]20#ifdef HAVE_NTL
[034eec]21#include <NTL/ZZX.h>
[f11d7b]22#include "NTLconvert.h"
[034eec]23bool isPurePoly(const CanonicalForm & f);
[f11d7b]24#endif
25
[edb4893]26static CanonicalForm gcd_poly( const CanonicalForm & f, const CanonicalForm& g, bool modularflag );
27
[f63dbca]28bool
29gcd_test_one ( const CanonicalForm & f, const CanonicalForm & g, bool swap )
[9bab9f]30{
31    int count = 0;
32    // assume polys have same level;
33    CFRandom * sample = CFRandomFactory::generate();
[f63dbca]34    REvaluation e( 2, tmax( f.level(), g.level() ), *sample );
[9bab9f]35    delete sample;
[f63dbca]36    CanonicalForm lcf, lcg;
37    if ( swap ) {
[150dc8]38        lcf = swapvar( LC( f ), Variable(1), f.mvar() );
39        lcg = swapvar( LC( g ), Variable(1), f.mvar() );
[f63dbca]40    }
41    else {
[150dc8]42        lcf = LC( f, Variable(1) );
43        lcg = LC( g, Variable(1) );
[f63dbca]44    }
[9bab9f]45    while ( ( e( lcf ).isZero() || e( lcg ).isZero() ) && count < 100 ) {
[150dc8]46        e.nextpoint();
47        count++;
[9bab9f]48    }
49    if ( count == 100 )
[150dc8]50        return false;
[f63dbca]51    CanonicalForm F, G;
52    if ( swap ) {
[150dc8]53        F=swapvar( f, Variable(1), f.mvar() );
54        G=swapvar( g, Variable(1), g.mvar() );
[f63dbca]55    }
56    else {
[150dc8]57        F = f;
58        G = g;
[f63dbca]59    }
[9bab9f]60    if ( e(F).taildegree() > 0 && e(G).taildegree() > 0 )
[150dc8]61        return false;
[9bab9f]62    return gcd( e( F ), e( G ) ).degree() < 1;
63}
64
[dd3e561]65//{{{ static CanonicalForm balance ( const CanonicalForm & f, const CanonicalForm & q )
66//{{{ docu
67//
68// balance() - map f from positive to symmetric representation
69//   mod q.
70//
71// This makes sense for univariate polynomials over Z only.
72// q should be an integer.
73//
74// Used by gcd_poly_univar0().
75//
76//}}}
[edb4893]77static CanonicalForm
78balance ( const CanonicalForm & f, const CanonicalForm & q )
79{
[dd3e561]80    Variable x = f.mvar();
[edb4893]81    CanonicalForm result = 0, qh = q / 2;
[1986a2]82    CanonicalForm c;
[dd3e561]83    CFIterator i;
[edb4893]84    for ( i = f; i.hasTerms(); i++ ) {
[150dc8]85        c = mod( i.coeff(), q );
86        if ( c > qh )
87            result += power( x, i.exp() ) * (c - q);
88        else
89            result += power( x, i.exp() ) * c;
[edb4893]90    }
91    return result;
92}
[dd3e561]93//}}}
[edb4893]94
[dd3e561]95//{{{ static CanonicalForm icontent ( const CanonicalForm & f, const CanonicalForm & c )
96//{{{ docu
97//
98// icontent() - return gcd of c and all coefficients of f which
99//   are in a coefficient domain.
100//
101// Used by icontent().
102//
103//}}}
[9bab9f]104static CanonicalForm
105icontent ( const CanonicalForm & f, const CanonicalForm & c )
106{
107    if ( f.inCoeffDomain() )
[150dc8]108        return gcd( f, c );
[9bab9f]109    else {
[150dc8]110        CanonicalForm g = c;
111        for ( CFIterator i = f; i.hasTerms() && ! g.isOne(); i++ )
112            g = icontent( i.coeff(), g );
113        return g;
[9bab9f]114    }
115}
[dd3e561]116//}}}
[9bab9f]117
[c6ed6f]118//{{{ static CanonicalForm bcontent ( const CanonicalForm & f, const CanonicalForm & b )
119//{{{ docu
120//
121// bcontent() - return gcd of b and all coefficients of f which
122//   are in a basic domain.
123//
124// Used by gcd().
125//
126//}}}
127static CanonicalForm
128bcontent ( const CanonicalForm & f, const CanonicalForm & c )
129{
130    if ( f.inBaseDomain() )
131        return bgcd( f, c );
132    else if ( f.inCoeffDomain() )
133        return f.genOne();
134    else {
135        CanonicalForm g = c;
136        for ( CFIterator i = f; i.hasTerms() && ! g.isOne(); i++ )
137            g = bcontent( i.coeff(), g );
138        if( g.lc().sign() < 0 )
139            return -g;
140        else
141            return g;
142    }
143}
144//}}}
145
146
[dd3e561]147//{{{ CanonicalForm icontent ( const CanonicalForm & f )
148//{{{ docu
149//
150// icontent() - return gcd over all coefficients of f which are
151//   in a coefficient domain.
152//
153//}}}
[9bab9f]154CanonicalForm
155icontent ( const CanonicalForm & f )
156{
157    return icontent( f, 0 );
158}
[dd3e561]159//}}}
[9bab9f]160
[dd3e561]161//{{{ CanonicalForm extgcd ( const CanonicalForm & f, const CanonicalForm & g, CanonicalForm & a, CanonicalForm & b )
162//{{{ docu
163//
164// extgcd() - returns polynomial extended gcd of f and g.
165//
166// Returns gcd(f, g) and a and b sucht that f*a+g*b=gcd(f, g).
167// The gcd is calculated using an extended euclidean polynomial
168// remainder sequence, so f and g should be polynomials over an
169// euclidean domain.  Normalizes result.
170//
171// Note: be sure that f and g have the same level!
172//
173//}}}
[9bab9f]174CanonicalForm
175extgcd ( const CanonicalForm & f, const CanonicalForm & g, CanonicalForm & a, CanonicalForm & b )
176{
[034eec]177#ifdef HAVE_NTL
[2667bc8]178  if (isOn(SW_USE_NTL_GCD_P) && ( getCharacteristic() > 0 )
[034eec]179  && isPurePoly(f) && isPurePoly(g))
180  {
181    zz_pContext ccc(getCharacteristic());
182    ccc.restore();
183    zz_p::init(getCharacteristic());
184    zz_pX F1=convertFacCF2NTLzzpX(f);
185    zz_pX G1=convertFacCF2NTLzzpX(g);
186    zz_pX R;
187    zz_pX A,B;
188    XGCD(R,A,B,F1,G1);
189    a=convertNTLzzpX2CF(A,f.mvar());
190    b=convertNTLzzpX2CF(B,f.mvar());
191    return convertNTLzzpX2CF(R,f.mvar());
192  }
193#endif
194  CanonicalForm contf = content( f );
195  CanonicalForm contg = content( g );
[9bab9f]196
[034eec]197  CanonicalForm p0 = f / contf, p1 = g / contg;
198  CanonicalForm f0 = 1, f1 = 0, g0 = 0, g1 = 1, q, r;
[9bab9f]199
[034eec]200  while ( ! p1.isZero() ) {
201      divrem( p0, p1, q, r );
202      p0 = p1; p1 = r;
203      r = g0 - g1 * q;
204      g0 = g1; g1 = r;
205      r = f0 - f1 * q;
206      f0 = f1; f1 = r;
207  }
208  CanonicalForm contp0 = content( p0 );
209  a = f0 / ( contf * contp0 );
210  b = g0 / ( contg * contp0 );
211  p0 /= contp0;
212  if ( p0.sign() < 0 ) {
213      p0 = -p0;
214      a = -a;
215      b = -b;
216  }
217  return p0;
[9bab9f]218}
[dd3e561]219//}}}
[9bab9f]220
[edb4893]221static CanonicalForm
222gcd_poly_univar0( const CanonicalForm & F, const CanonicalForm & G, bool primitive )
223{
[de1a82]224#ifdef HAVE_NTL
[2667bc8]225  if (isOn(SW_USE_NTL_GCD_P) && isPurePoly(F) && isPurePoly(G))
[f11d7b]226  {
227    if ( getCharacteristic() > 0 )
228    {
[33d8725]229      //CanonicalForm cf=F.lc();
230      //CanonicalForm f=F / cf;
231      //CanonicalForm cg=G.lc();
232      //CanonicalForm g= G / cg;
[f11d7b]233      zz_pContext ccc(getCharacteristic());
234      ccc.restore();
235      zz_p::init(getCharacteristic());
236      zz_pX F1=convertFacCF2NTLzzpX(F);
237      zz_pX G1=convertFacCF2NTLzzpX(G);
238      zz_pX R=GCD(F1,G1);
[33d8725]239      return  convertNTLzzpX2CF(R,F.mvar());
[edb4893]240    }
[f11d7b]241    else
242    {
[33d8725]243      CanonicalForm f=F ;
244      CanonicalForm g=G ;
245      bool rat=isOn( SW_RATIONAL );
246      if ( isOn( SW_RATIONAL ) )
247      {
248         DEBOUTLN( cerr, "NTL_gcd: ..." );
249         CanonicalForm cdF = bCommonDen( F );
250         CanonicalForm cdG = bCommonDen( G );
251         Off( SW_RATIONAL );
252         CanonicalForm l = lcm( cdF, cdG );
253         On( SW_RATIONAL );
254         f *= l, g *= l;
255      }
256      DEBOUTLN( cerr, "NTL_gcd: f=" << f );
257      DEBOUTLN( cerr, "NTL_gcd: g=" << g );
258      ZZX F1=convertFacCF2NTLZZX(f);
259      ZZX G1=convertFacCF2NTLZZX(g);
[f11d7b]260      ZZX R=GCD(F1,G1);
[33d8725]261      CanonicalForm r=convertNTLZZX2CF(R,F.mvar());
262      DEBOUTLN( cerr, "NTL_gcd: -> " << r );
263      if (rat)
264      {
265        r /= r.lc();
266        DEBOUTLN( cerr, "NTL_gcd2: -> " << r );
267      }
268      return r;
[edb4893]269    }
[f11d7b]270  }
271#endif
272  CanonicalForm f, g, c, cg, cl, BB, B, M, q, Dp, newD, D, newq;
273  int p, i, n;
274
275  if ( primitive )
276  {
277    f = F;
278    g = G;
279    c = 1;
280  }
281  else
282  {
283    CanonicalForm cF = content( F ), cG = content( G );
284    f = F / cF;
285    g = G / cG;
286    c = bgcd( cF, cG );
287  }
288  cg = gcd( f.lc(), g.lc() );
289  cl = ( f.lc() / cg ) * g.lc();
[93b061]290//     B = 2 * cg * tmin(
[150dc8]291//         maxnorm(f)*power(CanonicalForm(2),f.degree())*isqrt(f.degree()+1),
292//         maxnorm(g)*power(CanonicalForm(2),g.degree())*isqrt(g.degree()+1)
293//         )+1;
[f11d7b]294  M = tmin( maxNorm(f), maxNorm(g) );
295  BB = power(CanonicalForm(2),tmin(f.degree(),g.degree()))*M;
296  q = 0;
297  i = cf_getNumSmallPrimes() - 1;
298  while ( true )
299  {
300    B = BB;
301    while ( i >= 0 && q < B )
302    {
303      p = cf_getSmallPrime( i );
304      i--;
305      while ( i >= 0 && mod( cl, p ) == 0 )
306      {
307        p = cf_getSmallPrime( i );
308        i--;
309      }
310      setCharacteristic( p );
311      Dp = gcd( mapinto( f ), mapinto( g ) );
312      Dp = ( Dp / Dp.lc() ) * mapinto( cg );
313      setCharacteristic( 0 );
314      if ( Dp.degree() == 0 )
315        return c;
316      if ( q.isZero() )
317      {
318        D = mapinto( Dp );
319        q = p;
320        B = power(CanonicalForm(2),D.degree())*M+1;
321      }
322      else
323      {
324        if ( Dp.degree() == D.degree() )
325        {
326          chineseRemainder( D, q, mapinto( Dp ), p, newD, newq );
327          q = newq;
328          D = newD;
[150dc8]329        }
[f11d7b]330        else if ( Dp.degree() < D.degree() )
331        {
332          // all previous p's are bad primes
333          q = p;
334          D = mapinto( Dp );
335          B = power(CanonicalForm(2),D.degree())*M+1;
[150dc8]336        }
[f11d7b]337        // else p is a bad prime
338      }
339    }
340    if ( i >= 0 )
341    {
342      // now balance D mod q
343      D = pp( balance( D, q ) );
344      if ( divides( D, f ) && divides( D, g ) )
345        return D * c;
346      else
347        q = 0;
[edb4893]348    }
[f11d7b]349    else
350      return gcd_poly( F, G, false );
351    DEBOUTLN( cerr, "another try ..." );
352  }
[edb4893]353}
354
[41a8db]355CanonicalForm
[f63dbca]356gcd_poly1( const CanonicalForm & f, const CanonicalForm & g, bool modularflag )
[9bab9f]357{
358    CanonicalForm C, Ci, Ci1, Hi, bi, pi, pi1, pi2;
359    int delta;
360    Variable v = f.mvar();
361
362    if ( f.degree( v ) >= g.degree( v ) ) {
[150dc8]363        pi = f; pi1 = g;
[9bab9f]364    }
365    else {
[150dc8]366        pi = g; pi1 = f;
[9bab9f]367    }
368    Ci = content( pi ); Ci1 = content( pi1 );
369    C = gcd( Ci, Ci1 );
370    pi1 = pi1 / Ci1; pi = pi / Ci;
[034eec]371    if ( pi.isUnivariate() && pi1.isUnivariate() )
372    {
373#ifdef HAVE_NTL
[2667bc8]374      if ((isOn(SW_USE_NTL_GCD_P)||isOn(SW_USE_NTL_GCD_0))
375       && isPurePoly(pi) && isPurePoly(pi1))
[33d8725]376         return gcd_poly_univar0(f, g, true);
[034eec]377#endif
[33d8725]378      if ( modularflag)
[034eec]379        return gcd_poly_univar0( pi, pi1, true ) * C;
[edb4893]380    }
[034eec]381    else if ( gcd_test_one( pi1, pi, true ) )
382      return C;
[9bab9f]383    delta = degree( pi, v ) - degree( pi1, v );
384    Hi = power( LC( pi1, v ), delta );
385    if ( (delta+1) % 2 )
[150dc8]386        bi = 1;
[9bab9f]387    else
[150dc8]388        bi = -1;
[9bab9f]389    while ( degree( pi1, v ) > 0 ) {
[150dc8]390        pi2 = psr( pi, pi1, v );
391        pi2 = pi2 / bi;
392        pi = pi1; pi1 = pi2;
393        if ( degree( pi1, v ) > 0 ) {
394            delta = degree( pi, v ) - degree( pi1, v );
395            if ( (delta+1) % 2 )
396                bi = LC( pi, v ) * power( Hi, delta );
397            else
398                bi = -LC( pi, v ) * power( Hi, delta );
399            Hi = power( LC( pi1, v ), delta ) / power( Hi, delta-1 );
400        }
[9bab9f]401    }
402    if ( degree( pi1, v ) == 0 )
[150dc8]403        return C;
[9bab9f]404    else {
[150dc8]405        return C * pp( pi );
[9bab9f]406    }
407}
408
[dd3e561]409//{{{ static CanonicalForm gcd_poly ( const CanonicalForm & f, const CanonicalForm & g, bool modularflag )
410//{{{ docu
411//
412// gcd_poly() - calculate polynomial gcd.
413//
414// This is the dispatcher for polynomial gcd calculation.  We call either
415// ezgcd(), sparsemod() or gcd_poly1() in dependecy on the current
416// characteristic and settings of SW_USE_EZGCD and SW_USE_SPARSEMOD, resp.
417//
418// modularflag is reached down to gcd_poly1() without change in case of
419// zero characteristic.
420//
421// Used by gcd() and gcd_poly_univar0().
422//
423//}}}
[bfc606]424int si_factor_reminder=1;
[f63dbca]425static CanonicalForm
[dd3e561]426gcd_poly ( const CanonicalForm & f, const CanonicalForm & g, bool modularflag )
[f63dbca]427{
[e074407]428    if ( getCharacteristic() != 0 ) {
[150dc8]429        return gcd_poly1( f, g, false );
[e074407]430    }
431    else if ( isOn( SW_USE_EZGCD ) && ! ( f.isUnivariate() && g.isUnivariate() ) ) {
[150dc8]432        CFMap M, N;
433        compress( f, g, M, N );
[e22ea7]434#if 0
[de1a82]435        CanonicalForm r=N( ezgcd( M(f), M(g) ) );
[bfc606]436        if ((f%r!=0) || (g % r !=0))
437        {
438           if (si_factor_reminder)
439           printf("ezgcd failed, trying gcd_poly1\n");
440           return gcd_poly1( f, g, modularflag);
441        }
[e22ea7]442        else
443           return r;
444#else
445         return N( ezgcd( M(f), M(g) ) );
446#endif   
[f63dbca]447    }
[de1a82]448    else if ( isOn( SW_USE_SPARSEMOD )
449    && ! ( f.isUnivariate() && g.isUnivariate() ) )
450    {
[e22ea7]451#if 0
[de1a82]452        CanonicalForm r=sparsemod( f, g );
[bfc606]453        if ((f%r!=0) || (g % r !=0))
454        {
455           if (si_factor_reminder)
456           printf("sparsemod failed, trying gcd_poly1\n");
[e22ea7]457           return r;
458           //return gcd_poly1( f, g, modularflag);
[bfc606]459        }
[e22ea7]460        else
461          return r;
462#else
463        return sparsemod( f, g );
464#endif
[1b73cc0]465    }
[de1a82]466    else
467    {
[150dc8]468        return gcd_poly1( f, g, modularflag );
[f63dbca]469    }
470}
[dd3e561]471//}}}
[93b061]472
[dd3e561]473//{{{ static CanonicalForm cf_content ( const CanonicalForm & f, const CanonicalForm & g )
474//{{{ docu
475//
476// cf_content() - return gcd(g, content(f)).
477//
478// content(f) is calculated with respect to f's main variable.
479//
480// Used by gcd(), content(), content( CF, Variable ).
481//
482//}}}
[9bab9f]483static CanonicalForm
484cf_content ( const CanonicalForm & f, const CanonicalForm & g )
485{
486    if ( f.inPolyDomain() || ( f.inExtension() && ! getReduce( f.mvar() ) ) ) {
[150dc8]487        CFIterator i = f;
488        CanonicalForm result = g;
489        while ( i.hasTerms() && ! result.isOne() ) {
490            result = gcd( result, i.coeff() );
491            i++;
492        }
493        return result;
[9bab9f]494    }
495    else
[150dc8]496        if ( f.sign() < 0 )
497            return -f;
498        else
499            return f;
[9bab9f]500}
[dd3e561]501//}}}
[9bab9f]502
[4ea0ab]503//{{{ CanonicalForm content ( const CanonicalForm & f )
504//{{{ docu
505//
506// content() - return content(f) with respect to main variable.
507//
[dd3e561]508// Normalizes result.
509//
[4ea0ab]510//}}}
[9bab9f]511CanonicalForm
512content ( const CanonicalForm & f )
513{
514    return cf_content( f, 0 );
515}
[4ea0ab]516//}}}
[9bab9f]517
[dd3e561]518//{{{ CanonicalForm content ( const CanonicalForm & f, const Variable & x )
519//{{{ docu
520//
521// content() - return content(f) with respect to x.
522//
523// x should be a polynomial variable.
524//
525//}}}
[9bab9f]526CanonicalForm
527content ( const CanonicalForm & f, const Variable & x )
528{
[dd3e561]529    ASSERT( x.level() > 0, "cannot calculate content with respect to algebraic variable" );
530    Variable y = f.mvar();
531
532    if ( y == x )
[150dc8]533        return cf_content( f, 0 );
[dd3e561]534    else  if ( y < x )
[150dc8]535        return f;
[9bab9f]536    else
[150dc8]537        return swapvar( content( swapvar( f, y, x ), y ), y, x );
[9bab9f]538}
[dd3e561]539//}}}
[9bab9f]540
[dd3e561]541//{{{ CanonicalForm vcontent ( const CanonicalForm & f, const Variable & x )
542//{{{ docu
543//
544// vcontent() - return content of f with repect to variables >= x.
545//
546// The content is recursively calculated over all coefficients in
547// f having level less than x.  x should be a polynomial
548// variable.
549//
550//}}}
[9bab9f]551CanonicalForm
552vcontent ( const CanonicalForm & f, const Variable & x )
553{
[dd3e561]554    ASSERT( x.level() > 0, "cannot calculate vcontent with respect to algebraic variable" );
555
[9bab9f]556    if ( f.mvar() <= x )
[150dc8]557        return content( f, x );
[9bab9f]558    else {
[150dc8]559        CFIterator i;
560        CanonicalForm d = 0;
561        for ( i = f; i.hasTerms() && ! d.isOne(); i++ )
562            d = gcd( d, vcontent( i.coeff(), x ) );
563        return d;
[9bab9f]564    }
565}
[dd3e561]566//}}}
[9bab9f]567
[4ea0ab]568//{{{ CanonicalForm pp ( const CanonicalForm & f )
569//{{{ docu
570//
571// pp() - return primitive part of f.
572//
[dd3e561]573// Returns zero if f equals zero, otherwise f / content(f).
574//
[4ea0ab]575//}}}
[9bab9f]576CanonicalForm
577pp ( const CanonicalForm & f )
578{
579    if ( f.isZero() )
[150dc8]580        return f;
[9bab9f]581    else
[150dc8]582        return f / content( f );
[9bab9f]583}
[4ea0ab]584//}}}
[9bab9f]585
586CanonicalForm
587gcd ( const CanonicalForm & f, const CanonicalForm & g )
588{
589    if ( f.isZero() )
[150dc8]590        if ( g.lc().sign() < 0 )
591            return -g;
592        else
593            return g;
[9bab9f]594    else  if ( g.isZero() )
[150dc8]595        if ( f.lc().sign() < 0 )
596            return -f;
597        else
598            return f;
[9bab9f]599    else  if ( f.inBaseDomain() )
[c6ed6f]600        return bcontent( g, f );
[9bab9f]601    else  if ( g.inBaseDomain() )
[c6ed6f]602        return bcontent( f, g );
[9bab9f]603    else  if ( f.mvar() == g.mvar() )
[150dc8]604        if ( f.inExtension() && getReduce( f.mvar() ) )
605            return 1;
606        else {
607            if ( divides( f, g ) )
608                if ( f.lc().sign() < 0 )
609                    return -f;
610                else
611                    return f;
612            else  if ( divides( g, f ) )
613                if ( g.lc().sign() < 0 )
614                    return -g;
615                else
616                    return g;
617            if ( getCharacteristic() == 0 && isOn( SW_RATIONAL ) ) {
618                CanonicalForm cdF = bCommonDen( f );
619                CanonicalForm cdG = bCommonDen( g );
620                Off( SW_RATIONAL );
621                CanonicalForm l = lcm( cdF, cdG );
622                On( SW_RATIONAL );
623                CanonicalForm F = f * l, G = g * l;
624                Off( SW_RATIONAL );
[bf95b5]625                do { l = gcd_poly( F, G, true ); }
626                while ((!divides(l,F)) || (!divides(l,G)));
[150dc8]627                On( SW_RATIONAL );
628                if ( l.lc().sign() < 0 )
629                    return -l;
630                else
631                    return l;
632            }
633            else {
[bf95b5]634                CanonicalForm d;
635                do{ d = gcd_poly( f, g, getCharacteristic()==0 ); }
636                while ((!divides(d,f)) || (!divides(d,g)));
[150dc8]637                if ( d.lc().sign() < 0 )
638                    return -d;
639                else
640                    return d;
641            }
642        }
[9bab9f]643    else  if ( f.mvar() > g.mvar() )
[150dc8]644        return cf_content( f, g );
[9bab9f]645    else
[150dc8]646        return cf_content( g, f );
[9bab9f]647}
648
[dd3e561]649//{{{ CanonicalForm lcm ( const CanonicalForm & f, const CanonicalForm & g )
650//{{{ docu
651//
652// lcm() - return least common multiple of f and g.
653//
654// The lcm is calculated using the formula lcm(f, g) = f * g / gcd(f, g).
655//
656// Returns zero if one of f or g equals zero.
657//
658//}}}
[9bab9f]659CanonicalForm
660lcm ( const CanonicalForm & f, const CanonicalForm & g )
661{
[dd3e561]662    if ( f.isZero() || g.isZero() )
[150dc8]663        return f;
[dd3e561]664    else
[150dc8]665        return ( f / gcd( f, g ) ) * g;
[9bab9f]666}
[dd3e561]667//}}}
Note: See TracBrowser for help on using the repository browser.