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 | |