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