Home | History | Annotate | Line # | Download | only in imath
      1  1.1  mrg /*
      2  1.1  mrg   Name:     imrat.h
      3  1.1  mrg   Purpose:  Arbitrary precision rational arithmetic routines.
      4  1.1  mrg   Author:   M. J. Fromberger
      5  1.1  mrg 
      6  1.1  mrg   Copyright (C) 2002-2007 Michael J. Fromberger, All Rights Reserved.
      7  1.1  mrg 
      8  1.1  mrg   Permission is hereby granted, free of charge, to any person obtaining a copy
      9  1.1  mrg   of this software and associated documentation files (the "Software"), to deal
     10  1.1  mrg   in the Software without restriction, including without limitation the rights
     11  1.1  mrg   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     12  1.1  mrg   copies of the Software, and to permit persons to whom the Software is
     13  1.1  mrg   furnished to do so, subject to the following conditions:
     14  1.1  mrg 
     15  1.1  mrg   The above copyright notice and this permission notice shall be included in
     16  1.1  mrg   all copies or substantial portions of the Software.
     17  1.1  mrg 
     18  1.1  mrg   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     19  1.1  mrg   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     20  1.1  mrg   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     21  1.1  mrg   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     22  1.1  mrg   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     23  1.1  mrg   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     24  1.1  mrg   SOFTWARE.
     25  1.1  mrg  */
     26  1.1  mrg 
     27  1.1  mrg #ifndef IMRAT_H_
     28  1.1  mrg #define IMRAT_H_
     29  1.1  mrg 
     30  1.1  mrg #include <stdbool.h>
     31  1.1  mrg 
     32  1.1  mrg #include "imath.h"
     33  1.1  mrg 
     34  1.1  mrg #ifdef __cplusplus
     35  1.1  mrg extern "C" {
     36  1.1  mrg #endif
     37  1.1  mrg 
     38  1.1  mrg typedef struct {
     39  1.1  mrg   mpz_t   num;    /* Numerator         */
     40  1.1  mrg   mpz_t   den;    /* Denominator, <> 0 */
     41  1.1  mrg } mpq_t, *mp_rat;
     42  1.1  mrg 
     43  1.1  mrg /* Return a pointer to the numerator. */
     44  1.1  mrg static inline mp_int MP_NUMER_P(mp_rat Q) { return &(Q->num); }
     45  1.1  mrg 
     46  1.1  mrg /* Return a pointer to the denominator. */
     47  1.1  mrg static inline mp_int MP_DENOM_P(mp_rat Q) { return &(Q->den); }
     48  1.1  mrg 
     49  1.1  mrg /* Rounding constants */
     50  1.1  mrg typedef enum {
     51  1.1  mrg   MP_ROUND_DOWN,
     52  1.1  mrg   MP_ROUND_HALF_UP,
     53  1.1  mrg   MP_ROUND_UP,
     54  1.1  mrg   MP_ROUND_HALF_DOWN
     55  1.1  mrg } mp_round_mode;
     56  1.1  mrg 
     57  1.1  mrg /** Initializes `r` with 1-digit precision and sets it to zero. This function
     58  1.1  mrg     cannot fail unless `r` is NULL. */
     59  1.1  mrg mp_result mp_rat_init(mp_rat r);
     60  1.1  mrg 
     61  1.1  mrg /** Allocates a fresh zero-valued `mpq_t` on the heap, returning NULL in case
     62  1.1  mrg     of error. The only possible error is out-of-memory. */
     63  1.1  mrg mp_rat mp_rat_alloc(void);
     64  1.1  mrg 
     65  1.1  mrg /** Reduces `r` in-place to lowest terms and canonical form.
     66  1.1  mrg 
     67  1.1  mrg     Zero is represented as 0/1, one as 1/1, and signs are adjusted so that the
     68  1.1  mrg     sign of the value is carried by the numerator. */
     69  1.1  mrg mp_result mp_rat_reduce(mp_rat r);
     70  1.1  mrg 
     71  1.1  mrg /** Initializes `r` with at least `n_prec` digits of storage for the numerator
     72  1.1  mrg     and `d_prec` digits of storage for the denominator, and value zero.
     73  1.1  mrg 
     74  1.1  mrg     If either precision is zero, the default precision is used, rounded up to
     75  1.1  mrg     the nearest word size. */
     76  1.1  mrg mp_result mp_rat_init_size(mp_rat r, mp_size n_prec, mp_size d_prec);
     77  1.1  mrg 
     78  1.1  mrg /** Initializes `r` to be a copy of an already-initialized value in `old`. The
     79  1.1  mrg     new copy does not share storage with the original. */
     80  1.1  mrg mp_result mp_rat_init_copy(mp_rat r, mp_rat old);
     81  1.1  mrg 
     82  1.1  mrg /** Sets the value of `r` to the ratio of signed `numer` to signed `denom`.  It
     83  1.1  mrg     returns `MP_UNDEF` if `denom` is zero. */
     84  1.1  mrg mp_result mp_rat_set_value(mp_rat r, mp_small numer, mp_small denom);
     85  1.1  mrg 
     86  1.1  mrg /** Sets the value of `r` to the ratio of unsigned `numer` to unsigned
     87  1.1  mrg     `denom`. It returns `MP_UNDEF` if `denom` is zero. */
     88  1.1  mrg mp_result mp_rat_set_uvalue(mp_rat r, mp_usmall numer, mp_usmall denom);
     89  1.1  mrg 
     90  1.1  mrg /** Releases the storage used by `r`. */
     91  1.1  mrg void mp_rat_clear(mp_rat r);
     92  1.1  mrg 
     93  1.1  mrg /** Releases the storage used by `r` and also `r` itself.
     94  1.1  mrg     This should only be used for `r` allocated by `mp_rat_alloc()`. */
     95  1.1  mrg void mp_rat_free(mp_rat r);
     96  1.1  mrg 
     97  1.1  mrg /** Sets `z` to a copy of the numerator of `r`. */
     98  1.1  mrg mp_result mp_rat_numer(mp_rat r, mp_int z);
     99  1.1  mrg 
    100  1.1  mrg /** Returns a pointer to the numerator of `r`. */
    101  1.1  mrg mp_int mp_rat_numer_ref(mp_rat r);
    102  1.1  mrg 
    103  1.1  mrg /** Sets `z` to a copy of the denominator of `r`. */
    104  1.1  mrg mp_result mp_rat_denom(mp_rat r, mp_int z);
    105  1.1  mrg 
    106  1.1  mrg /** Returns a pointer to the denominator of `r`. */
    107  1.1  mrg mp_int mp_rat_denom_ref(mp_rat r);
    108  1.1  mrg 
    109  1.1  mrg /** Reports the sign of `r`. */
    110  1.1  mrg mp_sign mp_rat_sign(mp_rat r);
    111  1.1  mrg 
    112  1.1  mrg /** Sets `c` to a copy of the value of `a`. No new memory is allocated unless a
    113  1.1  mrg     term of `a` has more significant digits than the corresponding term of `c`
    114  1.1  mrg     has allocated. */
    115  1.1  mrg mp_result mp_rat_copy(mp_rat a, mp_rat c);
    116  1.1  mrg 
    117  1.1  mrg /** Sets `r` to zero. The allocated storage of `r` is not changed. */
    118  1.1  mrg void mp_rat_zero(mp_rat r);
    119  1.1  mrg 
    120  1.1  mrg /** Sets `c` to the absolute value of `a`. */
    121  1.1  mrg mp_result mp_rat_abs(mp_rat a, mp_rat c);
    122  1.1  mrg 
    123  1.1  mrg /** Sets `c` to the absolute value of `a`. */
    124  1.1  mrg mp_result mp_rat_neg(mp_rat a, mp_rat c);
    125  1.1  mrg 
    126  1.1  mrg /** Sets `c` to the reciprocal of `a` if the reciprocal is defined.
    127  1.1  mrg     It returns `MP_UNDEF` if `a` is zero. */
    128  1.1  mrg mp_result mp_rat_recip(mp_rat a, mp_rat c);
    129  1.1  mrg 
    130  1.1  mrg /** Sets `c` to the sum of `a` and `b`. */
    131  1.1  mrg mp_result mp_rat_add(mp_rat a, mp_rat b, mp_rat c);
    132  1.1  mrg 
    133  1.1  mrg /** Sets `c` to the difference of `a` less `b`. */
    134  1.1  mrg mp_result mp_rat_sub(mp_rat a, mp_rat b, mp_rat c);
    135  1.1  mrg 
    136  1.1  mrg /** Sets `c` to the product of `a` and `b`. */
    137  1.1  mrg mp_result mp_rat_mul(mp_rat a, mp_rat b, mp_rat c);
    138  1.1  mrg 
    139  1.1  mrg /** Sets `c` to the ratio `a / b` if that ratio is defined.
    140  1.1  mrg     It returns `MP_UNDEF` if `b` is zero. */
    141  1.1  mrg mp_result mp_rat_div(mp_rat a, mp_rat b, mp_rat c);
    142  1.1  mrg 
    143  1.1  mrg /** Sets `c` to the sum of `a` and integer `b`. */
    144  1.1  mrg mp_result mp_rat_add_int(mp_rat a, mp_int b, mp_rat c);
    145  1.1  mrg 
    146  1.1  mrg /** Sets `c` to the difference of `a` less integer `b`. */
    147  1.1  mrg mp_result mp_rat_sub_int(mp_rat a, mp_int b, mp_rat c);
    148  1.1  mrg 
    149  1.1  mrg /** Sets `c` to the product of `a` and integer `b`. */
    150  1.1  mrg mp_result mp_rat_mul_int(mp_rat a, mp_int b, mp_rat c);
    151  1.1  mrg 
    152  1.1  mrg /** Sets `c` to the ratio `a / b` if that ratio is defined.
    153  1.1  mrg     It returns `MP_UNDEF` if `b` is zero. */
    154  1.1  mrg mp_result mp_rat_div_int(mp_rat a, mp_int b, mp_rat c);
    155  1.1  mrg 
    156  1.1  mrg /** Sets `c` to the value of `a` raised to the `b` power.
    157  1.1  mrg     It returns `MP_RANGE` if `b < 0`. */
    158  1.1  mrg mp_result mp_rat_expt(mp_rat a, mp_small b, mp_rat c);
    159  1.1  mrg 
    160  1.1  mrg /** Returns the comparator of `a` and `b`. */
    161  1.1  mrg int mp_rat_compare(mp_rat a, mp_rat b);
    162  1.1  mrg 
    163  1.1  mrg /** Returns the comparator of the magnitudes of `a` and `b`, disregarding their
    164  1.1  mrg     signs. Neither `a` nor `b` is modified by the comparison. */
    165  1.1  mrg int mp_rat_compare_unsigned(mp_rat a, mp_rat b);
    166  1.1  mrg 
    167  1.1  mrg /** Returns the comparator of `r` and zero. */
    168  1.1  mrg int mp_rat_compare_zero(mp_rat r);
    169  1.1  mrg 
    170  1.1  mrg /** Returns the comparator of `r` and the signed ratio `n / d`.
    171  1.1  mrg     It returns `MP_UNDEF` if `d` is zero. */
    172  1.1  mrg int mp_rat_compare_value(mp_rat r, mp_small n, mp_small d);
    173  1.1  mrg 
    174  1.1  mrg /** Reports whether `r` is an integer, having canonical denominator 1. */
    175  1.1  mrg bool mp_rat_is_integer(mp_rat r);
    176  1.1  mrg 
    177  1.1  mrg /** Reports whether the numerator and denominator of `r` can be represented as
    178  1.1  mrg     small signed integers, and if so stores the corresponding values to `num`
    179  1.1  mrg     and `den`. It returns `MP_RANGE` if either cannot be so represented. */
    180  1.1  mrg mp_result mp_rat_to_ints(mp_rat r, mp_small *num, mp_small *den);
    181  1.1  mrg 
    182  1.1  mrg /** Converts `r` to a zero-terminated string of the format `"n/d"` with `n` and
    183  1.1  mrg     `d` in the specified radix and writing no more than `limit` bytes to the
    184  1.1  mrg     given output buffer `str`. The output of the numerator includes a sign flag
    185  1.1  mrg     if `r` is negative.  Requires `MP_MIN_RADIX <= radix <= MP_MAX_RADIX`. */
    186  1.1  mrg mp_result mp_rat_to_string(mp_rat r, mp_size radix, char *str, int limit);
    187  1.1  mrg 
    188  1.1  mrg /** Converts the value of `r` to a string in decimal-point notation with the
    189  1.1  mrg     specified radix, writing no more than `limit` bytes of data to the given
    190  1.1  mrg     output buffer.  It generates `prec` digits of precision, and requires
    191  1.1  mrg     `MP_MIN_RADIX <= radix <= MP_MAX_RADIX`.
    192  1.1  mrg 
    193  1.1  mrg     Ratios usually must be rounded when they are being converted for output as
    194  1.1  mrg     a decimal value.  There are four rounding modes currently supported:
    195  1.1  mrg 
    196  1.1  mrg       MP_ROUND_DOWN
    197  1.1  mrg         Truncates the value toward zero.
    198  1.1  mrg         Example:  12.009 to 2dp becomes 12.00
    199  1.1  mrg 
    200  1.1  mrg       MP_ROUND_UP
    201  1.1  mrg         Rounds the value away from zero:
    202  1.1  mrg         Example:  12.001 to 2dp becomes 12.01, but
    203  1.1  mrg                   12.000 to 2dp remains 12.00
    204  1.1  mrg 
    205  1.1  mrg       MP_ROUND_HALF_DOWN
    206  1.1  mrg          Rounds the value to nearest digit, half goes toward zero.
    207  1.1  mrg          Example:  12.005 to 2dp becomes 12.00, but
    208  1.1  mrg                    12.006 to 2dp becomes 12.01
    209  1.1  mrg 
    210  1.1  mrg       MP_ROUND_HALF_UP
    211  1.1  mrg          Rounds the value to nearest digit, half rounds upward.
    212  1.1  mrg          Example:  12.005 to 2dp becomes 12.01, but
    213  1.1  mrg                    12.004 to 2dp becomes 12.00
    214  1.1  mrg */
    215  1.1  mrg mp_result mp_rat_to_decimal(mp_rat r, mp_size radix, mp_size prec,
    216  1.1  mrg                             mp_round_mode round, char *str, int limit);
    217  1.1  mrg 
    218  1.1  mrg /** Reports the minimum number of characters required to represent `r` as a
    219  1.1  mrg     zero-terminated string in the given `radix`.
    220  1.1  mrg     Requires `MP_MIN_RADIX <= radix <= MP_MAX_RADIX`. */
    221  1.1  mrg mp_result mp_rat_string_len(mp_rat r, mp_size radix);
    222  1.1  mrg 
    223  1.1  mrg /** Reports the length in bytes of the buffer needed to convert `r` using the
    224  1.1  mrg     `mp_rat_to_decimal()` function with the specified `radix` and `prec`. The
    225  1.1  mrg     buffer size estimate may slightly exceed the actual required capacity. */
    226  1.1  mrg mp_result mp_rat_decimal_len(mp_rat r, mp_size radix, mp_size prec);
    227  1.1  mrg 
    228  1.1  mrg /** Sets `r` to the value represented by a zero-terminated string `str` in the
    229  1.1  mrg     format `"n/d"` including a sign flag. It returns `MP_UNDEF` if the encoded
    230  1.1  mrg     denominator has value zero. */
    231  1.1  mrg mp_result mp_rat_read_string(mp_rat r, mp_size radix, const char *str);
    232  1.1  mrg 
    233  1.1  mrg /** Sets `r` to the value represented by a zero-terminated string `str` in the
    234  1.1  mrg     format `"n/d"` including a sign flag. It returns `MP_UNDEF` if the encoded
    235  1.1  mrg     denominator has value zero. If `end` is not NULL then `*end` is set to
    236  1.1  mrg     point to the first unconsumed character in the string, after parsing.
    237  1.1  mrg */
    238  1.1  mrg mp_result mp_rat_read_cstring(mp_rat r, mp_size radix, const char *str,
    239  1.1  mrg 			      char **end);
    240  1.1  mrg 
    241  1.1  mrg /** Sets `r` to the value represented by a zero-terminated string `str` having
    242  1.1  mrg     one of the following formats, each with an optional leading sign flag:
    243  1.1  mrg 
    244  1.1  mrg        n         : integer format, e.g. "123"
    245  1.1  mrg        n/d       : ratio format, e.g., "-12/5"
    246  1.1  mrg        z.ffff    : decimal format, e.g., "1.627"
    247  1.1  mrg 
    248  1.1  mrg     It returns `MP_UNDEF` if the effective denominator is zero. If `end` is not
    249  1.1  mrg     NULL then `*end` is set to point to the first unconsumed character in the
    250  1.1  mrg     string, after parsing.
    251  1.1  mrg */
    252  1.1  mrg mp_result mp_rat_read_ustring(mp_rat r, mp_size radix, const char *str,
    253  1.1  mrg 			      char **end);
    254  1.1  mrg 
    255  1.1  mrg /** Sets `r` to the value represented by a zero-terminated string `str` in the
    256  1.1  mrg     format `"z.ffff"` including a sign flag. It returns `MP_UNDEF` if the
    257  1.1  mrg     effective denominator. */
    258  1.1  mrg mp_result mp_rat_read_decimal(mp_rat r, mp_size radix, const char *str);
    259  1.1  mrg 
    260  1.1  mrg /** Sets `r` to the value represented by a zero-terminated string `str` in the
    261  1.1  mrg     format `"z.ffff"` including a sign flag. It returns `MP_UNDEF` if the
    262  1.1  mrg     effective denominator. If `end` is not NULL then `*end` is set to point to
    263  1.1  mrg     the first unconsumed character in the string, after parsing. */
    264  1.1  mrg mp_result mp_rat_read_cdecimal(mp_rat r, mp_size radix, const char *str,
    265  1.1  mrg 			       char **end);
    266  1.1  mrg 
    267  1.1  mrg #ifdef __cplusplus
    268  1.1  mrg }
    269  1.1  mrg #endif
    270  1.1  mrg #endif /* IMRAT_H_ */
    271