source: git/factory/int_intdiv.cc @ 362fc67

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