source: git/factory/int_int.cc @ ee668e

jengelh-datetimespielwiese
Last change on this file since ee668e was ee668e, checked in by Jan Engelhardt <jengelh@…>, 11 years ago
factory/build: restore out-of-tree build support When attempting an OOT build, it fails to find <factory/cplusplus.h>, because cplusplus.h is always (even in in-tree builds) produced in "${builddir}", and not "${top_srcdir}/../factory". Furthermore, one must not rely on the basename of ${top_srcdir}, and going above ${top_srcdir} is undefined and may lead to spurious build failures. (Consider a hypothetical chroot on ${top_srcdir}). Therefore, create a directory include/factory and use -Iinclude such that <factory/*> yields a buildable state, move all exported header files there. Previous OOT build log: 17:22 seven:../factory/obj > make CXX cplusplus.o CXXLD cplusplus ./cplusplus > ./cplusplus.h ../bin/makeheader ../factory.template factory.h ../bin/makeheader ../factoryconf.template factoryconf.h YACC readcf.cc make all-am make[1]: Entering directory `/home/jengelh/obs/zu/home/jengelh/science/singsource/factory/obj' CXX libfactory_a-algext.o CXX libfactory_a-canonicalform.o In file included from ../cf_factory.h:12:0, from ../canonicalform.cc:7: ../../factory/cf_gmp.h:14:33: fatal error: factory/cplusplus.h: Ingen slik fil eller filkatalog compilation terminated. make[1]: *** [libfactory_a-canonicalform.o] Error 1 make[1]: Leaving directory `/home/jengelh/obs/zu/home/jengelh/science/singsource/factory/obj' make: *** [all] Error 2
  • Property mode set to 100644
File size: 13.5 KB
Line 
1/* emacs edit mode for this file is -*- C++ -*- */
2/* $Id$ */
3
4#include "config.h"
5
6#include "canonicalform.h"
7#include "imm.h"
8#include "int_int.h"
9#include "int_rat.h"
10#include <factory/cf_gmp.h>
11#include "gmpext.h"
12
13#ifdef HAVE_OMALLOC
14const omBin InternalInteger::InternalInteger_bin = omGetSpecBin(sizeof(InternalInteger));
15#endif
16
17InternalInteger::InternalInteger()
18{
19    mpz_init( thempi );
20}
21
22InternalInteger::InternalInteger( const int i )
23{
24    mpz_init_set_si( thempi, i );
25}
26
27InternalInteger::InternalInteger( const mpz_ptr mpi) { thempi[0]=*mpi;}
28
29InternalInteger::InternalInteger( const char * str, const int base )
30{
31    mpz_init_set_str( thempi, str, base );
32}
33
34InternalInteger::~InternalInteger()
35{
36    mpz_clear( thempi );
37}
38
39InternalCF* InternalInteger::deepCopyObject() const
40{
41    mpz_t dummy;
42    mpz_init_set( dummy, thempi );
43    return new InternalInteger( dummy );
44}
45
46#ifndef NOSTREAMIO
47void InternalInteger::print( OSTREAM & os, char * c )
48{
49    if ( *c == '*' && mpz_cmp_si( thempi, 1 ) == 0 )
50        os << c+1;
51    else if ( *c == '*' && mpz_cmp_si( thempi, -1 ) == 0 )
52        os << '-' << c+1;
53    else {
54        char * str = new char[mpz_sizeinbase( thempi, 10 ) + 2];
55        str = mpz_get_str( str, 10, thempi );
56        os << str << c;
57        delete [] str;
58    }
59}
60#endif /* NOSTREAMIO */
61
62bool InternalInteger::is_imm() const
63{
64    return mpz_is_imm( thempi );
65}
66
67InternalCF* InternalInteger::genZero()
68{
69    if ( isZero() )
70        return copyObject();
71    else
72        return new InternalInteger();
73}
74
75InternalCF* InternalInteger::genOne()
76{
77    if ( isOne() )
78        return copyObject();
79    else
80        return new InternalInteger( 1 );
81}
82
83//{{{ InternalCF * InternalInteger::neg ()
84// docu: see CanonicalForm::operator -()
85InternalCF *
86InternalInteger::neg ()
87{
88    if ( getRefCount() > 1 )
89    {
90        decRefCount();
91        mpz_t dummy;
92        mpz_init_set( dummy, thempi );
93        mpz_neg( dummy, dummy );
94        return new InternalInteger( dummy );
95    }
96    else
97    {
98        mpz_neg( thempi, thempi );
99        return this;
100    }
101}
102//}}}
103
104
105InternalCF* InternalInteger::addsame( InternalCF * c )
106{
107    if ( getRefCount() > 1 )
108    {
109        decRefCount();
110        mpz_t dummy;
111        mpz_init( dummy );
112        mpz_add( dummy, thempi, MPI( c ) );
113        if ( mpz_is_imm( dummy ) )
114        {
115            InternalCF * res = int2imm( mpz_get_si( dummy ) );
116            mpz_clear( dummy );
117            return res;
118        }
119        else
120            return new InternalInteger( dummy );
121    }
122    else
123    {
124        mpz_add( thempi, thempi, MPI( c ) );
125        if ( mpz_is_imm( thempi ) )
126        {
127            InternalCF * res = int2imm( mpz_get_si( thempi ) );
128            delete this;
129            return res;
130        }
131        else
132            return this;
133    }
134}
135
136InternalCF* InternalInteger::subsame( InternalCF * c )
137{
138    if ( getRefCount() > 1 )
139    {
140        decRefCount();
141        mpz_t dummy;
142        mpz_init( dummy );
143        mpz_sub( dummy, thempi, MPI( c ) );
144        if ( mpz_is_imm( dummy ) )
145        {
146            InternalCF * res = int2imm( mpz_get_si( dummy ) );
147            mpz_clear( dummy );
148            return res;
149        }
150        else
151            return new InternalInteger( dummy );
152    }
153    else
154    {
155        mpz_sub( thempi, thempi, MPI( c ) );
156        if ( mpz_is_imm( thempi ) )
157        {
158            InternalCF * res = int2imm( mpz_get_si( thempi ) );
159            delete this;
160            return res;
161        }
162        else
163            return this;
164    }
165}
166
167InternalCF* InternalInteger::mulsame( InternalCF * c )
168{
169    if ( getRefCount() > 1 )
170    {
171        decRefCount();
172        mpz_t dummy;
173        mpz_init( dummy );
174        mpz_mul( dummy, thempi, MPI( c ) );
175        #if 0
176        if ( mpz_is_imm( dummy ) )
177        {
178        // can this happen ???
179            InternalCF * res = int2imm( mpz_get_si( dummy ) );
180            mpz_clear( dummy );
181            return res;
182        }
183        else
184        #endif
185            return new InternalInteger( dummy );
186    }
187    else
188    {
189        mpz_mul( thempi, thempi, MPI( c ) );
190        #if 0
191        if ( mpz_is_imm( &thempi ) )
192        {
193        // can this happen ???
194            InternalCF * res = int2imm( mpz_get_si( &thempi ) );
195            delete this;
196            return res;
197        }
198        else
199        #endif
200            return this;
201    }
202}
203
204//{{{ int InternalInteger::comparesame, comparecoeff ( InternalCF * c )
205// docu: see CanonicalForm::operator <(), CanonicalForm::operator ==()
206int
207InternalInteger::comparesame ( InternalCF * c )
208{
209    ASSERT( ! ::is_imm( c ) && c->levelcoeff() == IntegerDomain, "incompatible base coefficients" );
210    return mpz_cmp( thempi, MPI( c ) );
211}
212
213int
214InternalInteger::comparecoeff ( InternalCF * c )
215{
216    ASSERT( ::is_imm( c ) == INTMARK, "incompatible base coefficients" );
217    return mpz_cmp_si( thempi, imm2int( c ) );
218}
219//}}}
220
221InternalCF* InternalInteger::addcoeff( InternalCF* c )
222{
223    ASSERT( ::is_imm( c ) == INTMARK, "incompatible base coefficients" );
224    int cc = imm2int( c );
225    if ( getRefCount() > 1 )
226    {
227        decRefCount();
228        mpz_t dummy;
229        mpz_init( dummy );
230        if ( cc < 0 )
231            mpz_sub_ui( dummy, thempi, -cc );
232        else
233            mpz_add_ui( dummy, thempi, cc );
234        if ( mpz_is_imm( dummy ) )
235        {
236            InternalCF * res = int2imm( mpz_get_si( dummy ) );
237            mpz_clear( dummy );
238            return res;
239        }
240        else
241            return new InternalInteger( dummy );
242    }
243    else
244    {
245        if ( cc < 0 )
246            mpz_sub_ui( thempi, thempi, -cc );
247        else
248            mpz_add_ui( thempi, thempi, cc );
249        if ( mpz_is_imm( thempi ) )
250        {
251            InternalCF * res = int2imm( mpz_get_si( thempi ) );
252            delete this;
253            return res;
254        }
255        else
256            return this;
257    }
258}
259
260InternalCF* InternalInteger::subcoeff( InternalCF* c, bool negate )
261{
262    ASSERT( ::is_imm( c ) == INTMARK, "incompatible base coefficients" );
263    int cc = imm2int( c );
264    if ( getRefCount() > 1 )
265    {
266        decRefCount();
267        mpz_t dummy;
268        if ( negate )
269        {
270            mpz_init_set_si( dummy, cc );
271            mpz_sub( dummy, dummy, thempi );
272        }
273        else
274        {
275            mpz_init( dummy );
276            if ( cc < 0 )
277                mpz_add_ui( dummy, thempi, -cc );
278            else
279                mpz_sub_ui( dummy, thempi, cc );
280        }
281        if ( mpz_is_imm( dummy ) )
282        {
283            InternalCF * res = int2imm( mpz_get_si( dummy ) );
284            mpz_clear( dummy );
285            return res;
286        }
287        else
288            return new InternalInteger( dummy );
289    }
290    else
291    {
292        if ( negate )
293        {
294            mpz_t dummy;
295            mpz_init_set_si( dummy, cc );
296            mpz_sub( thempi, dummy, thempi );
297            mpz_clear( dummy );
298        }
299        else
300            if ( cc < 0 )
301                mpz_add_ui( thempi, thempi, -cc );
302            else
303                mpz_sub_ui( thempi, thempi, cc );
304        if ( mpz_is_imm( thempi ) )
305        {
306            InternalCF * res = int2imm( mpz_get_si( thempi ) );
307            delete this;
308            return res;
309        }
310        else
311            return this;
312    }
313}
314
315InternalCF* InternalInteger::mulcoeff( InternalCF* c )
316{
317    ASSERT( ::is_imm( c ) == INTMARK, "incompatible base coefficients" );
318    int cc = imm2int( c );
319    if ( getRefCount() > 1 )
320    {
321        decRefCount();
322        mpz_t dummy;
323        mpz_init( dummy );
324        if ( cc < 0 )
325        {
326            mpz_mul_ui( dummy, thempi, -cc );
327            mpz_neg( dummy, dummy );
328        }
329        else
330            mpz_mul_ui( dummy, thempi, cc );
331        if ( mpz_is_imm( dummy ) )
332        {
333            InternalCF * res = int2imm( mpz_get_si( dummy ) );
334            mpz_clear( dummy );
335            return res;
336        }
337        else
338            return new InternalInteger( dummy );
339    }
340    else
341    {
342        if ( cc < 0 )
343        {
344            mpz_mul_ui( thempi, thempi, -cc );
345            mpz_neg( thempi, thempi );
346        }
347        else
348            mpz_mul_ui( thempi, thempi, cc );
349        if ( mpz_is_imm( thempi ) )
350        {
351            InternalCF * res = int2imm( mpz_get_si( thempi ) );
352            delete this;
353            return res;
354        }
355        else
356            return this;
357    }
358}
359
360//{{{ InternalCF * InternalInteger::bgcdsame, bgcdcoeff ( const InternalCF * const c )
361// docu: see CanonicalForm::bgcd()
362InternalCF *
363InternalInteger::bgcdsame ( const InternalCF * const c ) const
364{
365    ASSERT( ! ::is_imm( c ) && c->levelcoeff() == IntegerDomain, "incompatible base coefficients" );
366
367    // simply return 1 if we are calculating over the rationals
368    if ( cf_glob_switches.isOn( SW_RATIONAL ) )
369         return int2imm( 1 );
370
371    // calculate gcd
372    mpz_t result;
373    mpz_init( result );
374    mpz_gcd( result, thempi, MPI( c ) );
375    mpz_abs( result, result );
376
377    // check for immediate result
378    if ( mpz_is_imm( result ) )
379    {
380        InternalCF * res = int2imm( mpz_get_si( result ) );
381        mpz_clear( result );
382        return res;
383    }
384    else
385        return new InternalInteger( result );
386}
387
388InternalCF *
389InternalInteger::bgcdcoeff ( const InternalCF * const c )
390{
391    ASSERT( ::is_imm( c ) == INTMARK, "incompatible base coefficients" );
392
393    // simply return 1 if we are calculating over the rationals
394    if ( cf_glob_switches.isOn( SW_RATIONAL ) )
395         return int2imm( 1 );
396
397    int cInt = imm2int( c );
398
399    // trivial cases
400    if ( cInt == 1 || cInt == -1 )
401        return int2imm( 1 );
402    else if ( cInt == 0 )
403        return copyObject();
404
405    // calculate gcd.  We need a positive operand since
406    // `mpz_gcd_ui()' operates an unsigned int's only.
407    if ( cInt < 0 ) cInt = -cInt;
408    mpz_t dummy;
409    mpz_init( dummy );
410    // we do not need dummy since we know that cInt != 0
411    cInt = mpz_gcd_ui( dummy, thempi, cInt );
412    mpz_clear( dummy );
413    if ( cInt < 0 ) cInt = -cInt;
414    return int2imm( cInt );
415}
416//}}}
417
418//{{{ InternalCF * InternalInteger::bextgcdsame( InternalCF * c, CanonicalForm & a, CanonicalForm & b )
419InternalCF *
420InternalInteger::bextgcdsame( InternalCF * c, CanonicalForm & a, CanonicalForm & b )
421{
422    ASSERT( ! ::is_imm( c ) && c->levelcoeff() == IntegerDomain, "incompatible base coefficients" );
423
424    // simply return 1 if we are calculating over the rationals
425    if ( cf_glob_switches.isOn( SW_RATIONAL ) )
426    {
427        a = 1/CanonicalForm( copyObject() ); b = 0;
428        return int2imm( 1 );
429    }
430
431    // calculate extended gcd
432    mpz_t result, aMPI, bMPI;
433    mpz_init( result );
434    mpz_init( aMPI );
435    mpz_init( bMPI );
436    mpz_gcdext( result, aMPI, bMPI, thempi, MPI( c ) );
437
438    // check and modify signs
439    if ( mpz_sgn( result ) < 0 )
440    {
441        mpz_neg( result, result );
442        mpz_neg( aMPI, aMPI );
443        mpz_neg( bMPI, bMPI );
444    }
445
446    // postconditioning of result
447    if ( mpz_is_imm( aMPI ) )
448    {
449        a = CanonicalForm( int2imm( mpz_get_si( aMPI ) ) );
450        mpz_clear( aMPI );
451    }
452    else
453        a = CanonicalForm( new InternalInteger( aMPI ) );
454    if ( mpz_is_imm( bMPI ) )
455    {
456        b = CanonicalForm( int2imm( mpz_get_si( bMPI ) ) );
457        mpz_clear( bMPI );
458    }
459    else
460        b = CanonicalForm( new InternalInteger( bMPI ) );
461    if ( mpz_is_imm( result ) )
462    {
463        InternalCF * res = int2imm( mpz_get_si( result ) );
464        mpz_clear( result );
465        return res;
466    }
467    else
468        return new InternalInteger( result );
469}
470
471InternalCF *
472InternalInteger::bextgcdcoeff( InternalCF * c, CanonicalForm & a, CanonicalForm & b )
473{
474    ASSERT( ::is_imm( c ) == INTMARK, "incompatible base coefficients" );
475
476    // simply return 1 if we are calculating over the rationals
477    if ( cf_glob_switches.isOn( SW_RATIONAL ) )
478    {
479        a = 1/CanonicalForm( copyObject() ); b = 0;
480        return int2imm( 1 );
481    }
482
483    int cInt = imm2int( c );
484
485    // trivial cases
486    if ( cInt == 1 || cInt == -1 )
487    {
488        a = 0; b = cInt;
489        return int2imm( 1 );
490    }
491    else if ( cInt == 0 )
492    {
493        a = 1; b = 0;
494        return copyObject();
495    }
496
497    // calculate q and r such that CO = q*cInt + r
498    InternalCF * q = 0, * r = 0;
499    divremcoeff( c, q, r, false );
500
501    // we do not repeat all the code to calculate the gcd of two
502    // immediates.  Note that r is an immediate since c != 0, so
503    // we do not have to destroy it.  q is destroyed by the
504    // CanonicalForm destructor, hence we do not need to worry
505    // about it, either.
506    CanonicalForm aPrime, bPrime;
507    CanonicalForm result = bextgcd( c, r, aPrime, bPrime );
508    a = bPrime;
509    b = aPrime - CanonicalForm( q ) * bPrime;
510
511    return result.getval();
512}
513//}}}
514
515int InternalInteger::intval() const
516{
517  return (int)mpz_get_si( thempi );
518}
519
520int InternalInteger::intmod( int p ) const
521{
522  return (int)mpz_fdiv_ui( thempi, (unsigned long)p );
523}
524
525//{{{ int InternalInteger::sign () const
526// docu: see CanonicalForm::sign()
527int
528InternalInteger::sign () const
529{
530    return mpz_sgn( thempi );
531}
532//}}}
533
534//{{{ InternalCF * InternalInteger::sqrt ()
535// docu: see CanonicalForm::sqrt()
536InternalCF *
537InternalInteger::sqrt ()
538{
539    ASSERT( mpz_cmp_si( thempi, 0 ) >= 0, "sqrt() argument < 0" );
540    mpz_t result;
541    mpz_init( result );
542    mpz_sqrt( result, thempi );
543    if ( mpz_is_imm( result ) )
544    {
545        InternalCF * res = int2imm( mpz_get_si( result ) );
546        mpz_clear( result );
547        return res;
548    }
549    else
550        return new InternalInteger( result );
551}
552//}}}
553
554//{{{ int InternalInteger::ilog2 ()
555// docu: see CanonicalForm::ilog2()
556int
557InternalInteger::ilog2 ()
558{
559    ASSERT( mpz_cmp_si( thempi, 0 ) > 0, "log() argument <= 0" );
560    return mpz_sizeinbase( thempi, 2 ) - 1;
561}
562//}}}
Note: See TracBrowser for help on using the repository browser.