/[dtapublic]/projs/dtats/trunk/shared_source/c_datd/gmp_rats.c
ViewVC logotype

Annotation of /projs/dtats/trunk/shared_source/c_datd/gmp_rats.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 90 - (hide annotations) (download)
Sun Dec 4 16:14:46 2016 UTC (7 years, 11 months ago) by dashley
Original Path: projs/trunk/shared_source/c_datd/gmp_rats.c
File MIME type: text/plain
File size: 32182 byte(s)
Correct some size_t issues.
1 dashley 71 //$Header$
2     //-------------------------------------------------------------------------------------------------
3     //This file is part of "David T. Ashley's Shared Source Code", a set of shared components
4     //integrated into many of David T. Ashley's projects.
5     //-------------------------------------------------------------------------------------------------
6     //This source code and any program in which it is compiled/used is provided under the MIT License,
7     //reproduced below.
8     //-------------------------------------------------------------------------------------------------
9     //Permission is hereby granted, free of charge, to any person obtaining a copy of
10     //this software and associated documentation files(the "Software"), to deal in the
11     //Software without restriction, including without limitation the rights to use,
12     //copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the
13     //Software, and to permit persons to whom the Software is furnished to do so,
14     //subject to the following conditions :
15     //
16     //The above copyright notice and this permission notice shall be included in all
17     //copies or substantial portions of the Software.
18     //
19     //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20     //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21     //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
22     //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23     //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24     //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25     //SOFTWARE.
26     //-------------------------------------------------------------------------------------------------
27     #define MODULE_GMP_RATS
28    
29     #include <assert.h>
30     #include <stdio.h>
31     #include <string.h>
32    
33     #include "bstrfunc.h"
34     #include "charfunc.h"
35     #include "gmp_ints.h"
36     #include "gmp_rats.h"
37    
38     #if defined(APP_TYPE_SIMPLE_DOS_CONSOLE)
39     #include "ccmalloc.h"
40     #elif defined(APP_TYPE_IJUSCRIPTER_IJUCONSOLE)
41     #include "tclalloc.h"
42     #else
43     #include <malloc.h>
44     #endif
45    
46    
47     /******************************************************************/
48     /*** STATUS FUNCTIONS *******************************************/
49     /******************************************************************/
50     //Functions in this category provide information about rational
51     //numbers.
52     //08/08/01: Visual inspection OK.
53     int GMP_RATS_mpq_is_nan(const GMP_RATS_mpq_struct *rn)
54     {
55     assert(rn != NULL);
56    
57     //A rational number is NAN in one of two
58     //circumstances. If either of the integer components
59     //is NAN, or else if there is a zero denominator.
60     if (GMP_INTS_mpz_get_flags(&(rn->num)) || GMP_INTS_mpz_get_flags(&(rn->den)))
61     {
62     return(1);
63     }
64     if (GMP_INTS_mpz_is_zero(&(rn->den)))
65     {
66     return(1);
67     }
68    
69     //We're clean ...
70     return(0);
71     }
72    
73    
74     /******************************************************************/
75     /*** INITIALIZATION, CLEARING, AND SETTING FUNCTIONS ************/
76     /******************************************************************/
77     //08/07/01: Visual inspection OK.
78     void GMP_RATS_mpq_init(GMP_RATS_mpq_struct *arg)
79     {
80     //Eyeball the input parameter.
81     assert(arg != NULL);
82    
83     //Initialize the numerator and denominator.
84     GMP_INTS_mpz_init(&(arg->num));
85     GMP_INTS_mpz_init(&(arg->den));
86    
87     //Canonically, we must start off as 0/1--canonical zero.
88     GMP_INTS_mpz_set_ui(&(arg->num), 0);
89     GMP_INTS_mpz_set_ui(&(arg->den), 1);
90     }
91    
92    
93     //08/07/01: Visual inspection OK.
94     void GMP_RATS_mpq_clear(GMP_RATS_mpq_struct *arg)
95     {
96     //Eyeball the input parameter.
97     assert(arg != NULL);
98    
99     //Clear the numerator and denominator. The called functions
100     //will check for NULL pointers and so forth.
101     GMP_INTS_mpz_clear(&(arg->num));
102     GMP_INTS_mpz_clear(&(arg->den));
103     }
104    
105    
106     //08/07/01: Visual inspection OK.
107     void GMP_RATS_mpq_set_si(GMP_RATS_mpq_struct *arg,
108     int num,
109     int den)
110     {
111     //Eyeball the input parameters.
112     assert(arg != NULL);
113    
114     //Set the numerator and denominator.
115     GMP_INTS_mpz_set_si(&(arg->num), num);
116     GMP_INTS_mpz_set_si(&(arg->den), den);
117     }
118    
119    
120     //08/08/01: Visual inspection OK.
121     void GMP_RATS_mpq_copy( GMP_RATS_mpq_struct *dst,
122     const GMP_RATS_mpq_struct *src)
123     {
124     assert(dst != NULL);
125     assert(src != NULL);
126    
127     GMP_INTS_mpz_copy(&(dst->num), &(src->num));
128     GMP_INTS_mpz_copy(&(dst->den), &(src->den));
129     }
130    
131    
132     //08/13/01: Visual inspection OK.
133     void GMP_RATS_mpq_swap( GMP_RATS_mpq_struct *a,
134     GMP_RATS_mpq_struct *b)
135     {
136     assert(a != NULL);
137     assert(b != NULL);
138    
139     //Handle the swap by swapping integer components.
140     GMP_INTS_mpz_swap(&(a->num), &(b->num));
141     GMP_INTS_mpz_swap(&(a->den), &(b->den));
142     }
143    
144    
145     //08/13/01: Visual inspection OK.
146     void GMP_RATS_mpq_swap_components(GMP_RATS_mpq_struct *arg)
147     {
148     assert(arg != NULL);
149    
150     GMP_INTS_mpz_swap(&(arg->num), &(arg->den));
151     }
152    
153    
154     //08/07/01: Visual inspection OK.
155     void GMP_RATS_mpq_set_complex_slash_sepd_rat_num(const char *s,
156     int *failure,
157     GMP_RATS_mpq_struct *rn)
158     {
159     char *slash_posn, *numerator, *denominator;
160 dashley 90 size_t s_len, numerator_len, denominator_len;
161     size_t i;
162 dashley 71
163     //Eyeball the input parameters.
164     assert(s != NULL);
165     assert(failure != NULL);
166     assert(rn != NULL);
167    
168     //Start off believing there is no failure.
169     *failure = 0;
170    
171     //Figure out if there is one and only one slash in the
172     //string. If this condition isn't met, we cannot
173     //go further.
174     slash_posn = strchr(s, '/');
175     if (!slash_posn)
176     {
177     *failure = 1;
178     return;
179     }
180     if (strchr(slash_posn + 1, '/')) //There is a second occurence.
181     {
182     *failure = 1;
183     return;
184     }
185    
186     //At this point we have one and only one slash.
187     //Crack the string in two. We must do this because the
188     //input is a constant string. We are not allowed to touch it
189     //in the logical domain because of the "const" keyword. We can't
190     //do this in the physical domain because the debugger will nail
191     //us for it.
192     s_len = strlen(s);
193     numerator_len = slash_posn - s;
194     denominator_len = strlen(slash_posn + 1);
195     #if defined(APP_TYPE_SIMPLE_DOS_CONSOLE)
196     numerator = CCMALLOC_malloc(sizeof(char) * (numerator_len + 1));
197     denominator = CCMALLOC_malloc(sizeof(char) * (denominator_len + 1));
198     #elif defined(APP_TYPE_IJUSCRIPTER_IJUCONSOLE)
199     numerator = TclpAlloc(sizeof(char) * (numerator_len + 1));
200     denominator = TclpAlloc(sizeof(char) * (denominator_len + 1));
201     #else
202     numerator = malloc(sizeof(char) * (numerator_len + 1));
203     denominator = malloc(sizeof(char) * (denominator_len + 1));
204     #endif
205    
206     assert(numerator != NULL);
207     assert(denominator != NULL);
208    
209     for (i=0; i<numerator_len; i++)
210     {
211     numerator[i] = s[i];
212     }
213     numerator[numerator_len] = 0;
214    
215     for (i=0; i<denominator_len; i++)
216     {
217     denominator[i] = s[slash_posn - s + 1 + i];
218     }
219     denominator[denominator_len] = 0;
220    
221     //Try to parse out the numerator as an arbitrary integer.
222     //If this can't be done, it is an immediate failure.
223     GMP_INTS_mpz_set_general_int(&(rn->num),
224     failure,
225     numerator);
226     if (*failure)
227     {
228     *failure = 1; //Clamp to 1, don't know what non-zero value
229     //was there.
230     goto ret_pt;
231     }
232    
233     //Try to parse out the denominator.
234     GMP_INTS_mpz_set_general_int(&(rn->den),
235     failure,
236     denominator);
237     if (*failure)
238     {
239     *failure = 1; //Clamp to 1, don't know what non-zero value
240     //was there.
241     goto ret_pt;
242     }
243    
244     //At this point, we have both a numerator and denominator.
245     //Clean up and return.
246     ret_pt:
247     #if defined(APP_TYPE_SIMPLE_DOS_CONSOLE)
248     CCMALLOC_free(numerator);
249     CCMALLOC_free(denominator);
250     #elif defined(APP_TYPE_IJUSCRIPTER_IJUCONSOLE)
251     TclpFree(numerator);
252     TclpFree(denominator);
253     #else
254     free(numerator);
255     free(denominator);
256     #endif
257     }
258    
259    
260     //08/07/01: Visual inspection OK.
261     void GMP_RATS_mpq_set_sci_not_rat_num(const char *s,
262     int *failure,
263     GMP_RATS_mpq_struct *rn)
264     {
265     int parse_failure;
266     //Return code from the floating point parsing
267     //function.
268     char mant_sign;
269     //Sign character, if any, from the mantissa,
270     //or N otherwise.
271     size_t mant_bdp;
272     //The index to the start of the mantissa before
273     //the decimal point.
274     size_t mant_bdp_len;
275     //The length of the mantissa before the decimal
276     //point. Zero means not defined, i.e. that
277     //no characters were parsed and interpreted as
278     //that part of a floating point number.
279     size_t mant_adp;
280     size_t mant_adp_len;
281     //Similar fields for after the decimal point.
282     char exp_sign;
283     //Sign of the exponent, if any, or N otherwise.
284     size_t exp;
285     size_t exp_len;
286     //Similar fields as to the mantissa, but for the
287     //exponent.
288     size_t si;
289     //Iteration variable.
290     int exponent_val;
291     //The value of the exponent. We can't accept
292     //an exponent outside the range of a 24-bit
293     //signed integer. The 24-bit limit is arbitrary.
294     //For one thing, it gives room to detect overflow
295     //as are adding and multiplying by 10.
296    
297     //Eyeball the input parameters.
298     assert(s != NULL);
299     assert(failure != NULL);
300     assert(rn != NULL);
301     //Subcomponents of the rational number will be checked as
302     //we make integer calls, if we're in debug mode.
303    
304     //Start off believing no failure.
305     *failure = 0;
306    
307     //Set the output to 0/1. This is the default case for some
308     //steps below.
309     GMP_RATS_mpq_set_si(rn, 0, 1);
310    
311     //Attempt to parse the number as a general number
312     //in scientific notation.
313     BSTRFUNC_parse_gen_sci_not_num(s,
314     &parse_failure,
315     &mant_sign,
316     &mant_bdp,
317     &mant_bdp_len,
318     &mant_adp,
319     &mant_adp_len,
320     &exp_sign,
321     &exp,
322     &exp_len);
323    
324     //If it wouldn't parse as a general number, can't go further.
325     if (parse_failure)
326     {
327     *failure = 1;
328     return;
329     }
330     else
331     {
332     //The number parsed out. The general strategy is to form a rational number
333     //consisting of the mantissa, with the decimal point shifted fully right, over
334     //a denominator of 1. From there, we process the exponent and combine it with
335     //the number of characters after the decimal point to form a virtual exponent.
336     //If the exponent is positive, we multiply the numerator by the power of 10.
337     //If the exponent is negative, we multiply the denominator by that power of 10.
338    
339     //We want to trim the trailing zeros off of the portion of the mantissa after the
340     //decimal point. We only need to back up indices, no need to make copies, etc.
341     //Note that it is possible that there are only zeros, in which case we'll end
342     //up with a length of zero.
343     while ((mant_adp_len > 0) && (s[mant_adp + mant_adp_len - 1]=='0'))
344     mant_adp_len--;
345    
346     //Trim the leading zeros off of the portion of the mantissa before the
347     //decimal point. Note that it is possible that there is only a zero,
348     //so we may trim it down to nothing.
349     while ((mant_bdp_len > 0) && (s[mant_bdp]=='0'))
350     {
351     mant_bdp++;
352     mant_bdp_len--;
353     }
354    
355     //If we have only zeros in the mantissa, both before the
356     //decimal point and after, then we return 0.
357     if ((mant_bdp_len + mant_adp_len) == 0)
358     {
359     *failure = 0;
360     return;
361     }
362    
363     //Convert the numerator to an integer which represents the
364     //part before the mantissa and the part after the mantissa
365     //concatenated as an integer. We could call a function to do
366     //this, but the function is not really any better in algorithm.
367     //We can do it ourselves.
368     GMP_INTS_mpz_set_ui(&(rn->num), 0);
369     for (si = 0; si < mant_bdp_len; si++)
370     {
371     int val;
372    
373     GMP_INTS_mpz_mul_si(&(rn->num), &(rn->num), 10);
374     val = CHARFUNC_digit_to_val(s[mant_bdp + si]);
375     if (val >= 0)
376     GMP_INTS_mpz_add_ui(&(rn->num), &(rn->num), val);
377     }
378     for (si = 0; si < mant_adp_len; si++)
379     {
380     int val;
381    
382     GMP_INTS_mpz_mul_si(&(rn->num), &(rn->num), 10);
383     val = CHARFUNC_digit_to_val(s[mant_adp + si]);
384     if (val >= 0)
385     GMP_INTS_mpz_add_ui(&(rn->num), &(rn->num), val);
386     }
387    
388     //The numerator should now have an integer which is
389     //The absolute value of the mantissa. Process the possible
390     //sign.
391     if (mant_sign == '-')
392     GMP_INTS_mpz_negate(&(rn->num));
393    
394     //We now need to form a value from the exponent, if any.
395     //First, tackle the exponent. Process the
396     //exponent into a signed integer. We have to
397     //balk at anything outside of 24 bits. The
398     //procedure used automatically handles
399     //leading zeros correctly.
400     exponent_val = 0;
401     for (si=exp; si<(exp+exp_len); si++)
402     {
403     int val;
404    
405     val = CHARFUNC_digit_to_val(s[si]);
406    
407     assert(val >= 0 && val <= 9);
408    
409     exponent_val *= 10;
410     exponent_val += val;
411    
412     if (((exp_sign=='-') && (exponent_val>8388608))
413     ||
414     ((exp_sign != '-') && (exponent_val>8388607)))
415     {
416     *failure = 1;
417     return;
418     }
419     }
420    
421     //If we're here, the exponent has been computed and
422     //is within 24 bits. However, we need to adjust for
423     //the sign.
424     if (exp_sign == '-')
425     exponent_val = -exponent_val;
426    
427     //We need to adjust the exponent for the number of digits
428     //after the decimal point.
429     exponent_val -= mant_adp_len;
430    
431     //Again, clip for size.
432     if ((exponent_val < -8388608) || (exponent_val > 8388607))
433     {
434     *failure = 1;
435     return;
436     }
437    
438     //There are two cases to consider. If the exponent
439     //is positive, we need to multiply the numerator
440     //by 10 exponentiated to the power of the exponent.
441     //If the exponent is negative, we need to do the
442     //same thing to the denominator. If the exponent
443     //is negative, we don't need to do anything.
444     if (exponent_val > 0)
445     {
446     GMP_INTS_mpz_struct k10, k10_exponentiated;
447    
448     GMP_INTS_mpz_init(&k10);
449     GMP_INTS_mpz_init(&k10_exponentiated);
450    
451     GMP_INTS_mpz_set_ui(&k10, 10);
452    
453     GMP_INTS_mpz_pow_ui(&k10_exponentiated, &k10, exponent_val);
454    
455     GMP_INTS_mpz_mul(&(rn->num), &(rn->num), &k10_exponentiated);
456    
457     GMP_INTS_mpz_clear(&k10);
458     GMP_INTS_mpz_clear(&k10_exponentiated);
459    
460     *failure = 0;
461    
462     if (GMP_INTS_mpz_get_flags(&(rn->num)) || GMP_INTS_mpz_get_flags(&(rn->den)))
463     *failure = 1;
464    
465     return;
466     }
467     else if (exponent_val < 0)
468     {
469     GMP_INTS_mpz_struct k10, k10_exponentiated;
470    
471     GMP_INTS_mpz_init(&k10);
472     GMP_INTS_mpz_init(&k10_exponentiated);
473    
474     GMP_INTS_mpz_set_ui(&k10, 10);
475    
476     GMP_INTS_mpz_pow_ui(&k10_exponentiated, &k10, -exponent_val);
477    
478     GMP_INTS_mpz_mul(&(rn->den), &(rn->den), &k10_exponentiated);
479    
480     GMP_INTS_mpz_clear(&k10);
481     GMP_INTS_mpz_clear(&k10_exponentiated);
482    
483     *failure = 0;
484    
485     if (GMP_INTS_mpz_get_flags(&(rn->num)) || GMP_INTS_mpz_get_flags(&(rn->den)))
486     *failure = 1;
487    
488     return;
489     }
490     }
491     }
492    
493    
494     //08/07/01: Visual inspection OK.
495     void GMP_RATS_mpq_set_all_format_rat_num(const char *s,
496     int *failure,
497     GMP_RATS_mpq_struct *rn)
498     {
499     //Eyeball the input parameters.
500     assert(s != NULL);
501     assert(failure != NULL);
502     assert(rn != NULL);
503    
504     //Assume no failure.
505     *failure = 0;
506    
507     //Try in order to parse as integers with slash then
508     //as number in scientific notation.
509     GMP_RATS_mpq_set_complex_slash_sepd_rat_num(s,
510     failure,
511     rn);
512     if (!*failure)
513     return;
514    
515     GMP_RATS_mpq_set_sci_not_rat_num(s,
516     failure,
517     rn);
518    
519     if (*failure)
520     *failure = 1; //Clamp output.
521     }
522    
523    
524     /******************************************************************/
525     /*** NORMALIZATION FUNCTIONS ************************************/
526     /******************************************************************/
527     //08/07/01: Visual inspection OK.
528     void GMP_RATS_mpq_normalize_sign(GMP_RATS_mpq_struct *rn)
529     {
530     //Eyeball the input.
531     assert(rn != NULL);
532    
533     if (GMP_INTS_mpz_is_neg(&rn->num) && GMP_INTS_mpz_is_neg(&rn->den))
534     {
535     //Both negative, can negate both, this leaves both positive,
536     //which is the normalized form for a positive rational
537     //number.
538     GMP_INTS_mpz_negate(&rn->num);
539     GMP_INTS_mpz_negate(&rn->den);
540     }
541     else if (!GMP_INTS_mpz_is_neg(&rn->num) && GMP_INTS_mpz_is_neg(&rn->den))
542     {
543     //Denominator neg, numerator non-neg, can negate both. This
544     //will leave numerator neg, denominator pos, which is
545     //normalized form for negative rational number.
546     GMP_INTS_mpz_negate(&rn->num);
547     GMP_INTS_mpz_negate(&rn->den);
548     }
549     }
550    
551    
552     //08/07/01: Visual inspection OK.
553     void GMP_RATS_mpq_normalize(GMP_RATS_mpq_struct *rn)
554     {
555     //Eyeball the input.
556     assert(rn != NULL);
557    
558     //Cover some special cases. If either component has flags
559     //set, don't even touch it.
560     if (GMP_INTS_mpz_get_flags(&(rn->num)) || GMP_INTS_mpz_get_flags(&(rn->den)))
561     {
562     return;
563     }
564     //If the denominator is zero, normalize it to 1/0, the canonical
565     //for for an illegal rational number.
566     else if (GMP_INTS_mpz_is_zero(&(rn->den)))
567     {
568     GMP_RATS_mpq_set_si(rn, 1, 0);
569     return;
570     }
571     //If the numerator is zero, convert the number to the canonical
572     //form for zero of 0/1.
573     else if (GMP_INTS_mpz_is_zero(&(rn->num)))
574     {
575     GMP_RATS_mpq_set_si(rn, 0, 1);
576     return;
577     }
578     else
579     {
580     int num_is_neg;
581     int den_is_neg;
582     GMP_INTS_mpz_struct gcd, quotient, remainder;
583    
584     //Allocate space for the integers used.
585     GMP_INTS_mpz_init(&gcd);
586     GMP_INTS_mpz_init(&quotient);
587     GMP_INTS_mpz_init(&remainder);
588    
589     //This is the most normal case, where we need to
590     //look at reducing the numerator and denominator.
591     //One way to do it would be to obtain the g.c.d.
592     //and divide this out, and this is the route
593     //we'll take. However, must grab out the sign.
594     if (GMP_INTS_mpz_is_neg(&(rn->num)))
595     {
596     num_is_neg = 1;
597     GMP_INTS_mpz_negate(&(rn->num));
598     }
599     else
600     {
601     num_is_neg = 0;
602     }
603    
604     if (GMP_INTS_mpz_is_neg(&(rn->den)))
605     {
606     den_is_neg = 1;
607     GMP_INTS_mpz_negate(&(rn->den));
608     }
609     else
610     {
611     den_is_neg = 0;
612     }
613    
614     //Calculate the GCD.
615     GMP_INTS_mpz_gcd(&gcd, &(rn->num), &(rn->den));
616    
617     //Divide the numerator by the GCD and store it
618     //back.
619     GMP_INTS_mpz_tdiv_qr(&quotient, &remainder,
620     &(rn->num), &gcd);
621     GMP_INTS_mpz_copy(&(rn->num), &quotient);
622    
623     //Divide the denominator by the GCD and store it
624     //back.
625     GMP_INTS_mpz_tdiv_qr(&quotient, &remainder,
626     &(rn->den), &gcd);
627     GMP_INTS_mpz_copy(&(rn->den), &quotient);
628    
629     //We now need to adjust the sign. Both the
630     //numerator and denominator are definitely
631     //positive. Need to make the numerator
632     //negative if either but not both of the
633     //original signs were negative.
634     if ((num_is_neg && !den_is_neg) || (!num_is_neg && den_is_neg))
635     {
636     GMP_INTS_mpz_negate(&(rn->num));
637     }
638    
639     //Deallocate space for the integers used.
640     GMP_INTS_mpz_clear(&gcd);
641     GMP_INTS_mpz_clear(&quotient);
642     GMP_INTS_mpz_clear(&remainder);
643    
644     return;
645     }
646     }
647    
648    
649     /******************************************************************/
650     /*** ARITHMETIC FUNCTIONS ***************************************/
651     /******************************************************************/
652     //08/08/01: Visual inspection OK.
653     void GMP_RATS_mpq_add( GMP_RATS_mpq_struct *result,
654     const GMP_RATS_mpq_struct *arg1,
655     const GMP_RATS_mpq_struct *arg2)
656     {
657     GMP_RATS_mpq_struct rv;
658     GMP_INTS_mpz_struct temp;
659    
660     //Eyeball the input parameters.
661     assert(result != NULL);
662     assert(arg1 != NULL);
663     assert(arg2 != NULL);
664    
665     //Generally speaking, we do not want to require that
666     //the arguments and the result be distinct, as this is
667     //too much of a restriction on the caller. The approach
668     //taken, somewhat wasteful, is to allocate a place for
669     //the return value.
670     //
671     //For addition, if we are adding a/b and c/d, the
672     //result is necessarily algebraically
673     //(ad + cb)/bd.
674     //
675     //If either rational number in the input is invalid,
676     //flag the result as invalid.
677     if (GMP_RATS_mpq_is_nan(arg1) || GMP_RATS_mpq_is_nan(arg2))
678     {
679     GMP_RATS_mpq_set_si(result, 1, 0);
680     }
681     else
682     {
683     //Both rational numbers are OK. Can simply stage the
684     //result by the algebraic identity and then
685     //normalize it. Only need one temporary variable.
686     //
687     //Initialize the rational number that we will use to
688     //hold return value in case it is the same as one
689     //or both of the arguments.
690     GMP_RATS_mpq_init(&rv);
691    
692     //Initialize the temporary integer.
693     GMP_INTS_mpz_init(&temp);
694    
695     //numerator = a * d
696     GMP_INTS_mpz_mul(&(rv.num), &(arg1->num), &(arg2->den));
697    
698     //temp = c * b
699     GMP_INTS_mpz_mul(&temp, &(arg2->num), &(arg1->den));
700    
701     //numerator = a * d + c * b
702     GMP_INTS_mpz_add(&(rv.num), &(rv.num), &temp);
703    
704     //denominator = b * d
705     GMP_INTS_mpz_mul(&(rv.den), &(arg1->den), &(arg2->den));
706    
707     //Copy the temporary result to the actual return value.
708     //Had to wait until now in case result was the same
709     //as either or both args.
710     GMP_RATS_mpq_copy(result, &rv);
711    
712     //Normalize the result.
713     GMP_RATS_mpq_normalize(result);
714    
715     //Free dynamic memory.
716     GMP_RATS_mpq_clear(&rv);
717     GMP_INTS_mpz_clear(&temp);
718     }
719     }
720    
721    
722     //08/08/01: Visual inspection OK.
723     void GMP_RATS_mpq_sub( GMP_RATS_mpq_struct *result,
724     const GMP_RATS_mpq_struct *arg1,
725     const GMP_RATS_mpq_struct *arg2)
726     {
727     GMP_RATS_mpq_struct negated_arg_2;
728    
729     //Eyeball the input parameters.
730     assert(result != NULL);
731     assert(arg1 != NULL);
732     assert(arg2 != NULL);
733    
734     //For the subtract function, we could do it directly,
735     //but might as well just define it recursively
736     //in terms of add. We can't modify the inputs,
737     //so copy the second off and negate it. All error
738     //flags and so forth will propagate automatically.
739     //
740     //Allocate space for the negated arg 2.
741     GMP_RATS_mpq_init(&negated_arg_2);
742    
743     //Copy from the original.
744     GMP_RATS_mpq_copy(&negated_arg_2, arg2);
745    
746     //Negate the copy. Negating the numerator will
747     //do it.
748     GMP_INTS_mpz_negate(&(negated_arg_2.num));
749    
750     //Make the add, which now is really a subtract.
751     GMP_RATS_mpq_add(result, arg1, &negated_arg_2);
752    
753     //Destroy the temporary variable.
754     GMP_RATS_mpq_clear(&negated_arg_2);
755     }
756    
757    
758     //08/16/01: Visual inspection OK.
759     void GMP_RATS_mpq_mul( GMP_RATS_mpq_struct *result,
760     const GMP_RATS_mpq_struct *arg1,
761     const GMP_RATS_mpq_struct *arg2)
762     {
763     //Eyeball the input parameters.
764     assert(result != NULL);
765     assert(arg1 != NULL);
766     assert(arg2 != NULL);
767    
768     //If either rational number in the input is invalid,
769     //flag the result as invalid.
770     if (GMP_RATS_mpq_is_nan(arg1) || GMP_RATS_mpq_is_nan(arg2))
771     {
772     GMP_RATS_mpq_set_si(result, 1, 0);
773     }
774     else
775     {
776     //Rational number multiplication is a simple matter.
777     //Just multiply components. Don't need to worry
778     //about rational numbers overlapping, as numerator
779     //operations and denominator operations are separate.
780     GMP_INTS_mpz_mul(&(result->num),
781     &(arg1->num),
782     &(arg2->num));
783     GMP_INTS_mpz_mul(&(result->den),
784     &(arg1->den),
785     &(arg2->den));
786    
787     //Normalize it.
788     GMP_RATS_mpq_normalize(result);
789     }
790     }
791    
792    
793     //08/16/01: Visual inspection OK.
794     void GMP_RATS_mpq_div( GMP_RATS_mpq_struct *result,
795     const GMP_RATS_mpq_struct *arg1,
796     const GMP_RATS_mpq_struct *arg2)
797     {
798     GMP_RATS_mpq_struct rv;
799    
800     //Eyeball the input parameters.
801     assert(result != NULL);
802     assert(arg1 != NULL);
803     assert(arg2 != NULL);
804    
805     //If either rational number in the input is invalid,
806     //flag the result as invalid.
807     if (GMP_RATS_mpq_is_nan(arg1) || GMP_RATS_mpq_is_nan(arg2))
808     {
809     GMP_RATS_mpq_set_si(result, 1, 0);
810     }
811     else
812     {
813     //Rational number division is a simple matter.
814     //Just multiply components. We do need to worry
815     //about rational numbers overlapping, so must
816     //make a copy of the return value. If denominator
817     //of return value is zero, it is NAN, but caller
818     //should detect this.
819     //
820     //Allocate return value.
821     GMP_RATS_mpq_init(&rv);
822    
823     //Calculate quotient.
824     GMP_INTS_mpz_mul(&(rv.num),
825     &(arg1->num),
826     &(arg2->den));
827     GMP_INTS_mpz_mul(&(rv.den),
828     &(arg1->den),
829     &(arg2->num));
830    
831     //Normalize quotient.
832     GMP_RATS_mpq_normalize(&rv);
833    
834     //Copy to its destination.
835     GMP_RATS_mpq_copy(result, &rv);
836    
837     //Deallocate temporary return value.
838     GMP_RATS_mpq_clear(&rv);
839     }
840     }
841    
842    
843     /******************************************************************/
844     /*** COMPARISON FUNCTIONS ***************************************/
845     /******************************************************************/
846     //08/16/01: Visual inspection OK.
847     int GMP_RATS_mpq_cmp(const GMP_RATS_mpq_struct *arg1,
848     const GMP_RATS_mpq_struct *arg2,
849     int *failure)
850     {
851     int arg1_sgn;
852     int arg2_sgn;
853     int rv, failure_rv;
854     GMP_INTS_mpz_struct prod1, prod2;
855    
856     //Eyeball the input parameters. Note that the third
857     //parameter may be NULL.
858     assert(arg1 != NULL);
859     assert(arg2 != NULL);
860    
861     //If either of the input arguments are NAN, we
862     //cannot compare arguments. We return 0, and it
863     //depends on the caller whether it is important
864     //that the comparison is bogus.
865     if (GMP_RATS_mpq_is_nan(arg1) || GMP_RATS_mpq_is_nan(arg2))
866     {
867     if (failure != NULL)
868     *failure = 1;
869     return(0);
870     }
871    
872     //Calculate the sign of the left argument. The encoding
873     //we'll use is -1 means negative, 0 means zero, and
874     //1 means positive.
875     if (GMP_INTS_mpz_is_zero(&(arg1->num)))
876     {
877     arg1_sgn = 0;
878     }
879     else if (GMP_INTS_mpz_is_neg(&(arg1->num)) && GMP_INTS_mpz_is_neg(&(arg1->den)))
880     {
881     arg1_sgn = 1;
882     }
883     else if (GMP_INTS_mpz_is_neg(&(arg1->num)) && GMP_INTS_mpz_is_pos(&(arg1->den)))
884     {
885     arg1_sgn = -1;
886     }
887     else if (GMP_INTS_mpz_is_pos(&(arg1->num)) && GMP_INTS_mpz_is_neg(&(arg1->den)))
888     {
889     arg1_sgn = -1;
890     }
891     else if (GMP_INTS_mpz_is_pos(&(arg1->num)) && GMP_INTS_mpz_is_pos(&(arg1->den)))
892     {
893     arg1_sgn = 1;
894     }
895    
896     //Calculate the sign of the right argument. The encoding
897     //we'll use is -1 means negative, 0 means zero, and
898     //1 means positive.
899     if (GMP_INTS_mpz_is_zero(&(arg2->num)))
900     {
901     arg2_sgn = 0;
902     }
903     else if (GMP_INTS_mpz_is_neg(&(arg2->num)) && GMP_INTS_mpz_is_neg(&(arg2->den)))
904     {
905     arg2_sgn = 1;
906     }
907     else if (GMP_INTS_mpz_is_neg(&(arg2->num)) && GMP_INTS_mpz_is_pos(&(arg2->den)))
908     {
909     arg2_sgn = -1;
910     }
911     else if (GMP_INTS_mpz_is_pos(&(arg2->num)) && GMP_INTS_mpz_is_neg(&(arg2->den)))
912     {
913     arg2_sgn = -1;
914     }
915     else if (GMP_INTS_mpz_is_pos(&(arg2->num)) && GMP_INTS_mpz_is_pos(&(arg2->den)))
916     {
917     arg2_sgn = 1;
918     }
919    
920     //OK, can handle some simple cases where the signs of the
921     //operands are different or both are zero.
922     if ((arg1_sgn == 0) && (arg2_sgn == 0))
923     {
924     if (failure != NULL)
925     *failure = 0;
926     return(0);
927     }
928     else if ((arg1_sgn == -1) && (arg2_sgn > -1))
929     {
930     if (failure != NULL)
931     *failure = 0;
932     return(-1);
933     }
934     else if ((arg1_sgn == 0) && (arg2_sgn < 0))
935     {
936     if (failure != NULL)
937     *failure = 0;
938     return(1);
939     }
940     else if ((arg1_sgn == 0) && (arg2_sgn > 0))
941     {
942     if (failure != NULL)
943     *failure = 0;
944     return(-1);
945     }
946     else if ((arg1_sgn == 1) && (arg2_sgn < 1))
947     {
948     if (failure != NULL)
949     *failure = 0;
950     return(1);
951     }
952    
953     //OK at this point, we cannot make a simple determination
954     //as to the relative ordering. The signs of arg1 and
955     //arg2 are both the same, either both positive or both
956     //negative. We have to do a multiplication to sort
957     //it out.
958     //
959     //Allocate the two integers to hold multiplication
960     //results.
961     GMP_INTS_mpz_init(&prod1);
962     GMP_INTS_mpz_init(&prod2);
963    
964     //Cross-multiply to get relative magnitudes.
965     GMP_INTS_mpz_mul(&prod1, &(arg1->num), &(arg2->den));
966     GMP_INTS_mpz_mul(&prod2, &(arg1->den), &(arg2->num));
967    
968     //Take absolute values.
969     GMP_INTS_mpz_abs(&prod1);
970     GMP_INTS_mpz_abs(&prod2);
971    
972     //If we overflowed either multiplication and generated
973     //a NAN, we cannot complete the compare.
974     if (GMP_INTS_mpz_get_flags(&prod1) || GMP_INTS_mpz_get_flags(&prod2))
975     {
976     failure_rv = 1;
977     rv = 0;
978     }
979     //If both rational numbers were effectively positive, we can
980     //use the relative ordering of the products as the relative
981     //ordering of the rational numbers.
982     else if (arg1_sgn == 1)
983     {
984     //Compare the integers.
985     rv = GMP_INTS_mpz_cmp(&prod1, &prod2);
986    
987     //Clamp the return value.
988     if (rv < 0)
989     rv = -1;
990     else if (rv == 0)
991     rv = 0;
992     else if (rv > 0)
993     rv = 1;
994    
995     //There was no error.
996     failure_rv = 0;
997     }
998     else
999     {
1000     //The only case that *should* allow us to be here is
1001     //if the sign of both numbers is neg.
1002     assert(arg1_sgn == -1);
1003    
1004     //Compare the integers.
1005     rv = GMP_INTS_mpz_cmp(&prod1, &prod2);
1006    
1007     //Invert and clamp the return value.
1008     if (rv < 0)
1009     rv = 1;
1010     else if (rv == 0)
1011     rv = 0;
1012     else if (rv > 0)
1013     rv = -1;
1014    
1015     //There was no error.
1016     failure_rv = 0;
1017     }
1018    
1019     //Deallocate the two integers.
1020     GMP_INTS_mpz_clear(&prod1);
1021     GMP_INTS_mpz_clear(&prod2);
1022    
1023     //Return the return values.
1024     if (failure != NULL)
1025     *failure = failure_rv;
1026     return(rv);
1027     }
1028    
1029    
1030     /******************************************************************/
1031     /*** VERSION CONTROL REPORTING FUNCTIONS ************************/
1032     /******************************************************************/
1033     //08/07/01: Visual inspection OK.
1034     const char *GMP_RATS_cvcinfo(void)
1035     {
1036     return("$Header$");
1037     }
1038    
1039    
1040     //08/07/01: Visual inspection OK.
1041     const char *GMP_RATS_hvcinfo(void)
1042     {
1043     return(GMP_RATS_H_VERSION);
1044     }
1045    
1046     //End of gmp_rats.c.

Properties

Name Value
svn:eol-style native
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25