source: git/factory/int_intdiv.cc

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