source: git/factory/int_intdiv.cc @ f5d2647

spielwiese
Last change on this file since f5d2647 was 16f511, checked in by Oleksandr Motsak <motsak@…>, 11 years ago
Fixed the usage of "config.h" (if defined HAVE_CONFIG_H)
  • Property mode set to 100644
File size: 10.0 KB
Line 
1/* emacs edit mode for this file is -*- C++ -*- */
2
3//{{{ docu
4//
5// int_intdiv.cc - `InternalInteger' division algorithms.
6//
7//}}}
8
9#ifdef HAVE_CONFIG_H
10#include "config.h"
11#endif /* HAVE_CONFIG_H */
12
13#include "canonicalform.h"
14#include "imm.h"
15#include "int_cf.h"
16#include "int_int.h"
17#include "int_rat.h"
18#include <factory/cf_gmp.h>
19#include "gmpext.h"
20#include "templates/ftmpl_functions.h"
21
22//{{{ InternalCF * InternalInteger::dividesame, dividecoeff ( InternalCF * c )
23// docu: see CanonicalForm::operator /()
24InternalCF *
25InternalInteger::dividesame ( InternalCF * c )
26{
27    ASSERT( ! ::is_imm( c ) && c->levelcoeff() == IntegerDomain,
28            "type error: InternalInteger expected" );
29
30    if ( c == this ) {
31        if ( deleteObject() ) delete this;
32        return int2imm( 1 );
33    }
34
35    if ( cf_glob_switches.isOn( SW_RATIONAL ) ) {
36        mpz_t n, d;
37        mpz_init_set( n, thempi );
38        mpz_init_set( d, MPI( c ) );
39        if ( deleteObject() ) delete this;
40        InternalRational * result = new InternalRational( n, d );
41        return result->normalize_myself();
42    }
43
44    if ( getRefCount() > 1 ) {
45        decRefCount();
46        mpz_t mpiResult;
47        mpz_init( mpiResult );
48        if ( mpz_sgn( MPI( c ) ) > 0 )
49            mpz_fdiv_q( mpiResult, thempi, MPI( c ) );
50        else
51            mpz_cdiv_q( mpiResult, thempi, MPI( c ) );
52        return normalizeMPI( mpiResult );
53    } else {
54        if ( mpz_sgn( MPI( c ) ) > 0 )
55            mpz_fdiv_q( thempi, thempi, MPI( c ) );
56        else
57            mpz_cdiv_q( thempi, thempi, MPI( c ) );
58        return normalizeMyself();
59    }
60}
61
62InternalCF *
63InternalInteger::dividecoeff ( InternalCF * c, bool invert )
64{
65    ASSERT( ::is_imm( c ) == INTMARK,
66            "type error: immediate integer expected" );
67    ASSERT( invert || imm2int( c ) != 0,
68            "math error: divide by zero" );
69
70    long intC = imm2int( c );
71
72    if ( cf_glob_switches.isOn( SW_RATIONAL ) ) {
73        mpz_t n, d;
74        if ( invert ) {
75            mpz_init_set_si( n, intC );
76            mpz_init_set( d, thempi );
77        } else {
78            mpz_init_set( n, thempi );
79            mpz_init_set_si( d, intC );
80        }
81        if ( deleteObject() ) delete this;
82        InternalRational * result = new InternalRational( n, d );
83        return result->normalize_myself();
84    }
85
86    if ( invert ) {
87        int mpiSign = mpz_sgn( thempi );
88        if ( deleteObject() ) delete this;
89        if ( intC >= 0 )
90            return int2imm( 0 );
91        else
92            return int2imm( -mpiSign );
93    } else if ( getRefCount() > 1 ) {
94        decRefCount();
95        mpz_t mpiResult;
96        mpz_init( mpiResult );
97        if ( intC > 0 )
98            mpz_fdiv_q_ui( mpiResult, thempi, intC );
99        else {
100            mpz_fdiv_q_ui( mpiResult, thempi, -intC );
101            mpz_neg( mpiResult, mpiResult );
102        }
103        return normalizeMPI( mpiResult );
104    } else {
105        if ( intC > 0 )
106            mpz_fdiv_q_ui( thempi, thempi, intC );
107        else {
108            mpz_fdiv_q_ui( thempi, thempi, -intC );
109            mpz_neg( thempi, thempi );
110        }
111        return normalizeMyself();
112    }
113}
114//}}}
115
116//{{{ InternalCF * InternalInteger::divsame, divcoeff ( InternalCF * c )
117// docu: see CanonicalForm::div()
118InternalCF *
119InternalInteger::divsame ( InternalCF * c )
120{
121    ASSERT( ! ::is_imm( c ) && c->levelcoeff() == IntegerDomain,
122            "type error: InternalInteger expected" );
123
124    if ( c == this ) {
125        if ( deleteObject() ) delete this;
126        return int2imm( 1 );
127    }
128
129    if ( getRefCount() > 1 ) {
130        deleteObject();
131        mpz_t mpiResult;
132        mpz_init( mpiResult );
133        mpz_divexact( mpiResult, thempi, MPI( c ) );
134        return normalizeMPI( mpiResult );
135    } else {
136        mpz_divexact( thempi, thempi, MPI( c ) );
137        return normalizeMyself();
138    }
139}
140
141InternalCF *
142InternalInteger::divcoeff ( InternalCF * c, bool invert )
143{
144    ASSERT( ::is_imm( c ) == INTMARK,
145            "type error: immediate integer expected" );
146    ASSERT( invert || imm2int( c ) != 0,
147            "math error: divide by zero" );
148    ASSERT( ! invert || imm2int( c ) == 0,
149            "math error: c does not divide CO" );
150
151    if ( invert ) {
152        if ( deleteObject() ) delete this;
153        // this may happen iff `c' == 0
154        return int2imm( 0 );
155    } else if ( getRefCount() > 1 ) {
156        deleteObject();
157        mpz_t mpiC;
158        mpz_t mpiResult;
159        mpz_init_set_si( mpiC, imm2int( c ) );
160        mpz_init( mpiResult );
161        mpz_divexact( mpiResult, thempi, mpiC );
162        mpz_clear( mpiC );
163        return normalizeMPI( mpiResult );
164    } else {
165        mpz_t mpiC;
166        mpz_init_set_si( mpiC, imm2int( c ) );
167        mpz_divexact( thempi, thempi, mpiC );
168        mpz_clear( mpiC );
169        return normalizeMyself();
170    }
171}
172//}}}
173
174//{{{ InternalCF * InternalInteger::modulosame, modulocoeff ( InternalCF * c )
175// docu: see CanonicalForm::operator %()
176InternalCF *
177InternalInteger::modulosame ( InternalCF * c )
178{
179    ASSERT( ! ::is_imm( c ) && c->levelcoeff() == IntegerDomain,
180            "type error: InternalInteger expected" );
181
182    if ( (c == this) || cf_glob_switches.isOn( SW_RATIONAL ) ) {
183        if ( deleteObject() ) delete this;
184        return int2imm( 0 );
185    }
186
187    if ( getRefCount() > 1 ) {
188        decRefCount();
189        mpz_t mpiResult;
190        mpz_init( mpiResult );
191        mpz_mod( mpiResult, thempi, MPI( c ) );
192        return uiNormalizeMPI( mpiResult );
193    } else {
194        mpz_mod( thempi, thempi, MPI( c ) );
195        return uiNormalizeMyself();
196    }
197}
198
199InternalCF *
200InternalInteger::modulocoeff ( InternalCF * c, bool invert )
201{
202    ASSERT( ::is_imm( c ) == INTMARK,
203            "type error: immediate integer expected" );
204    ASSERT( invert || imm2int( c ) != 0,
205            "math error: divide by zero" );
206
207    if ( cf_glob_switches.isOn( SW_RATIONAL ) ) {
208        if ( deleteObject() ) delete this;
209        return int2imm( 0 );
210    }
211
212    long intC = imm2int( c );
213
214    if ( invert ) {
215        if ( intC >= 0 ) {
216            if ( deleteObject() ) delete this;
217            return c;
218        } else {
219            // no checks for refCount == 1 are done.  It is not worth ...
220            mpz_t mpiResult;
221            mpz_init_set( mpiResult, thempi );
222            mpz_abs( mpiResult, mpiResult );
223            mpz_sub_ui( mpiResult, mpiResult, -intC );
224            if ( deleteObject() ) delete this;
225            return uiNormalizeMPI( mpiResult );
226        }
227    } else {
228        mpz_t dummy;
229        mpz_init( dummy );
230        InternalCF * result = int2imm( mpz_mod_ui( dummy, thempi, tabs( intC ) ) );
231        mpz_clear( dummy );
232        if ( deleteObject() ) delete this;
233        return result;
234    }
235}
236//}}}
237
238//{{{ InternalCF * InternalInteger::modsame, modcoeff ( InternalCF * c )
239// docu: see CanonicalForm::mod()
240InternalCF *
241InternalInteger::modsame ( InternalCF * c )
242{
243    return modulosame( c );
244}
245
246InternalCF *
247InternalInteger::modcoeff ( InternalCF * c, bool invert )
248{
249    return modulocoeff( c, invert );
250}
251//}}}
252
253//{{{ void InternalInteger::divremsame, divremcoeff ( InternalCF * c, InternalCF * & quot, InternalCF * & rem )
254// docu: see CanonicalForm::divrem()
255void
256InternalInteger::divremsame ( InternalCF * c, InternalCF * & quot, InternalCF * & rem )
257{
258    ASSERT( ! ::is_imm( c ) && c->levelcoeff() == IntegerDomain,
259            "type error: InternalInteger expected" );
260
261    if ( c == this ) {
262        quot = int2imm( 1 );
263        rem = int2imm( 0 );
264        return;
265    }
266
267    if ( cf_glob_switches.isOn( SW_RATIONAL ) ) {
268        mpz_t n, d;
269        mpz_init_set( n, thempi );
270        mpz_init_set( d, MPI( c ) );
271        InternalRational * result = new InternalRational( n, d );
272        quot = result->normalize_myself();
273        rem = int2imm( 0 );
274        return;
275    }
276
277    mpz_t q;
278    mpz_t r;
279    mpz_init( q ); mpz_init( r );
280    if ( mpz_sgn( MPI( c ) ) > 0 )
281        mpz_fdiv_qr( q, r, thempi, MPI( c ) );
282    else
283        mpz_cdiv_qr( q, r, thempi, MPI( c ) );
284
285    quot = normalizeMPI( q );
286    rem = uiNormalizeMPI( r );
287}
288
289void
290InternalInteger::divremcoeff ( InternalCF * c, InternalCF * & quot, InternalCF * & rem, bool invert )
291{
292    ASSERT( ::is_imm( c ) == INTMARK,
293            "type error: immediate integer expected" );
294    ASSERT( invert || imm2int( c ) != 0,
295            "math error: divide by zero" );
296
297    long intC = imm2int( c );
298
299    if ( cf_glob_switches.isOn( SW_RATIONAL ) ) {
300        mpz_t n, d;
301        if ( invert ) {
302            mpz_init_set_si( n, intC );
303            mpz_init_set( d, thempi );
304        } else {
305            mpz_init_set( n, thempi );
306            mpz_init_set_si( d, intC );
307        }
308        InternalRational * result = new InternalRational( n, d );
309        quot = result->normalize_myself();
310        rem = int2imm( 0 );
311        return;
312    }
313
314    if ( invert ) {
315        if ( intC >= 0 ) {
316            rem = c;
317            quot = int2imm( 0 );
318        } else {
319            mpz_t mpiResult;
320            mpz_init_set( mpiResult, thempi );
321            mpz_abs( mpiResult, mpiResult );
322            mpz_sub_ui( mpiResult, mpiResult, -intC );
323            rem = uiNormalizeMPI( mpiResult );
324            quot = int2imm( -mpz_sgn( thempi ) );
325        }
326    } else {
327        mpz_t q;
328        mpz_t dummy;
329        mpz_init( q ); mpz_init( dummy );
330        if ( intC > 0 ) {
331            rem = int2imm( mpz_fdiv_qr_ui( q, dummy, thempi, intC ) );
332            quot = normalizeMPI( q );
333        } else {
334            rem = int2imm( mpz_fdiv_qr_ui( q, dummy, thempi, -intC ) );
335            mpz_neg( q, q );
336            quot = normalizeMPI( q );
337        }
338        mpz_clear( dummy );
339    }
340}
341//}}}
342
343//{{{ bool InternalInteger::divremsamet, divremcoefft ( InternalCF * c, InternalCF * & quot, InternalCF * & rem )
344// docu: see CanonicalForm::divremt()
345bool
346InternalInteger::divremsamet ( InternalCF * c, InternalCF * & quot, InternalCF * & rem )
347{
348    divremsame( c, quot, rem );
349    return true;
350}
351
352bool
353InternalInteger::divremcoefft ( InternalCF * c, InternalCF * & quot, InternalCF * & rem, bool invert )
354{
355    divremcoeff( c, quot, rem, invert );
356    return true;
357}
358//}}}
Note: See TracBrowser for help on using the repository browser.