123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- /*
- Name: imrat.h
- Purpose: Arbitrary precision rational arithmetic routines.
- Author: M. J. Fromberger
- Copyright (C) 2002-2007 Michael J. Fromberger, All Rights Reserved.
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
- #ifndef IMRAT_H_
- #define IMRAT_H_
- #include <stdbool.h>
- #include "imath.h"
- #ifdef __cplusplus
- extern "C" {
- #endif
- typedef struct {
- mpz_t num; /* Numerator */
- mpz_t den; /* Denominator, <> 0 */
- } mpq_t, *mp_rat;
- /* Return a pointer to the numerator. */
- static inline mp_int MP_NUMER_P(mp_rat Q) { return &(Q->num); }
- /* Return a pointer to the denominator. */
- static inline mp_int MP_DENOM_P(mp_rat Q) { return &(Q->den); }
- /* Rounding constants */
- typedef enum {
- MP_ROUND_DOWN,
- MP_ROUND_HALF_UP,
- MP_ROUND_UP,
- MP_ROUND_HALF_DOWN
- } mp_round_mode;
- /** Initializes `r` with 1-digit precision and sets it to zero. This function
- cannot fail unless `r` is NULL. */
- mp_result mp_rat_init(mp_rat r);
- /** Allocates a fresh zero-valued `mpq_t` on the heap, returning NULL in case
- of error. The only possible error is out-of-memory. */
- mp_rat mp_rat_alloc(void);
- /** Reduces `r` in-place to lowest terms and canonical form.
- Zero is represented as 0/1, one as 1/1, and signs are adjusted so that the
- sign of the value is carried by the numerator. */
- mp_result mp_rat_reduce(mp_rat r);
- /** Initializes `r` with at least `n_prec` digits of storage for the numerator
- and `d_prec` digits of storage for the denominator, and value zero.
- If either precision is zero, the default precision is used, rounded up to
- the nearest word size. */
- mp_result mp_rat_init_size(mp_rat r, mp_size n_prec, mp_size d_prec);
- /** Initializes `r` to be a copy of an already-initialized value in `old`. The
- new copy does not share storage with the original. */
- mp_result mp_rat_init_copy(mp_rat r, mp_rat old);
- /** Sets the value of `r` to the ratio of signed `numer` to signed `denom`. It
- returns `MP_UNDEF` if `denom` is zero. */
- mp_result mp_rat_set_value(mp_rat r, mp_small numer, mp_small denom);
- /** Sets the value of `r` to the ratio of unsigned `numer` to unsigned
- `denom`. It returns `MP_UNDEF` if `denom` is zero. */
- mp_result mp_rat_set_uvalue(mp_rat r, mp_usmall numer, mp_usmall denom);
- /** Releases the storage used by `r`. */
- void mp_rat_clear(mp_rat r);
- /** Releases the storage used by `r` and also `r` itself.
- This should only be used for `r` allocated by `mp_rat_alloc()`. */
- void mp_rat_free(mp_rat r);
- /** Sets `z` to a copy of the numerator of `r`. */
- mp_result mp_rat_numer(mp_rat r, mp_int z);
- /** Returns a pointer to the numerator of `r`. */
- mp_int mp_rat_numer_ref(mp_rat r);
- /** Sets `z` to a copy of the denominator of `r`. */
- mp_result mp_rat_denom(mp_rat r, mp_int z);
- /** Returns a pointer to the denominator of `r`. */
- mp_int mp_rat_denom_ref(mp_rat r);
- /** Reports the sign of `r`. */
- mp_sign mp_rat_sign(mp_rat r);
- /** Sets `c` to a copy of the value of `a`. No new memory is allocated unless a
- term of `a` has more significant digits than the corresponding term of `c`
- has allocated. */
- mp_result mp_rat_copy(mp_rat a, mp_rat c);
- /** Sets `r` to zero. The allocated storage of `r` is not changed. */
- void mp_rat_zero(mp_rat r);
- /** Sets `c` to the absolute value of `a`. */
- mp_result mp_rat_abs(mp_rat a, mp_rat c);
- /** Sets `c` to the absolute value of `a`. */
- mp_result mp_rat_neg(mp_rat a, mp_rat c);
- /** Sets `c` to the reciprocal of `a` if the reciprocal is defined.
- It returns `MP_UNDEF` if `a` is zero. */
- mp_result mp_rat_recip(mp_rat a, mp_rat c);
- /** Sets `c` to the sum of `a` and `b`. */
- mp_result mp_rat_add(mp_rat a, mp_rat b, mp_rat c);
- /** Sets `c` to the difference of `a` less `b`. */
- mp_result mp_rat_sub(mp_rat a, mp_rat b, mp_rat c);
- /** Sets `c` to the product of `a` and `b`. */
- mp_result mp_rat_mul(mp_rat a, mp_rat b, mp_rat c);
- /** Sets `c` to the ratio `a / b` if that ratio is defined.
- It returns `MP_UNDEF` if `b` is zero. */
- mp_result mp_rat_div(mp_rat a, mp_rat b, mp_rat c);
- /** Sets `c` to the sum of `a` and integer `b`. */
- mp_result mp_rat_add_int(mp_rat a, mp_int b, mp_rat c);
- /** Sets `c` to the difference of `a` less integer `b`. */
- mp_result mp_rat_sub_int(mp_rat a, mp_int b, mp_rat c);
- /** Sets `c` to the product of `a` and integer `b`. */
- mp_result mp_rat_mul_int(mp_rat a, mp_int b, mp_rat c);
- /** Sets `c` to the ratio `a / b` if that ratio is defined.
- It returns `MP_UNDEF` if `b` is zero. */
- mp_result mp_rat_div_int(mp_rat a, mp_int b, mp_rat c);
- /** Sets `c` to the value of `a` raised to the `b` power.
- It returns `MP_RANGE` if `b < 0`. */
- mp_result mp_rat_expt(mp_rat a, mp_small b, mp_rat c);
- /** Returns the comparator of `a` and `b`. */
- int mp_rat_compare(mp_rat a, mp_rat b);
- /** Returns the comparator of the magnitudes of `a` and `b`, disregarding their
- signs. Neither `a` nor `b` is modified by the comparison. */
- int mp_rat_compare_unsigned(mp_rat a, mp_rat b);
- /** Returns the comparator of `r` and zero. */
- int mp_rat_compare_zero(mp_rat r);
- /** Returns the comparator of `r` and the signed ratio `n / d`.
- It returns `MP_UNDEF` if `d` is zero. */
- int mp_rat_compare_value(mp_rat r, mp_small n, mp_small d);
- /** Reports whether `r` is an integer, having canonical denominator 1. */
- bool mp_rat_is_integer(mp_rat r);
- /** Reports whether the numerator and denominator of `r` can be represented as
- small signed integers, and if so stores the corresponding values to `num`
- and `den`. It returns `MP_RANGE` if either cannot be so represented. */
- mp_result mp_rat_to_ints(mp_rat r, mp_small *num, mp_small *den);
- /** Converts `r` to a zero-terminated string of the format `"n/d"` with `n` and
- `d` in the specified radix and writing no more than `limit` bytes to the
- given output buffer `str`. The output of the numerator includes a sign flag
- if `r` is negative. Requires `MP_MIN_RADIX <= radix <= MP_MAX_RADIX`. */
- mp_result mp_rat_to_string(mp_rat r, mp_size radix, char *str, int limit);
- /** Converts the value of `r` to a string in decimal-point notation with the
- specified radix, writing no more than `limit` bytes of data to the given
- output buffer. It generates `prec` digits of precision, and requires
- `MP_MIN_RADIX <= radix <= MP_MAX_RADIX`.
- Ratios usually must be rounded when they are being converted for output as
- a decimal value. There are four rounding modes currently supported:
- MP_ROUND_DOWN
- Truncates the value toward zero.
- Example: 12.009 to 2dp becomes 12.00
- MP_ROUND_UP
- Rounds the value away from zero:
- Example: 12.001 to 2dp becomes 12.01, but
- 12.000 to 2dp remains 12.00
- MP_ROUND_HALF_DOWN
- Rounds the value to nearest digit, half goes toward zero.
- Example: 12.005 to 2dp becomes 12.00, but
- 12.006 to 2dp becomes 12.01
- MP_ROUND_HALF_UP
- Rounds the value to nearest digit, half rounds upward.
- Example: 12.005 to 2dp becomes 12.01, but
- 12.004 to 2dp becomes 12.00
- */
- mp_result mp_rat_to_decimal(mp_rat r, mp_size radix, mp_size prec,
- mp_round_mode round, char *str, int limit);
- /** Reports the minimum number of characters required to represent `r` as a
- zero-terminated string in the given `radix`.
- Requires `MP_MIN_RADIX <= radix <= MP_MAX_RADIX`. */
- mp_result mp_rat_string_len(mp_rat r, mp_size radix);
- /** Reports the length in bytes of the buffer needed to convert `r` using the
- `mp_rat_to_decimal()` function with the specified `radix` and `prec`. The
- buffer size estimate may slightly exceed the actual required capacity. */
- mp_result mp_rat_decimal_len(mp_rat r, mp_size radix, mp_size prec);
- /** Sets `r` to the value represented by a zero-terminated string `str` in the
- format `"n/d"` including a sign flag. It returns `MP_UNDEF` if the encoded
- denominator has value zero. */
- mp_result mp_rat_read_string(mp_rat r, mp_size radix, const char *str);
- /** Sets `r` to the value represented by a zero-terminated string `str` in the
- format `"n/d"` including a sign flag. It returns `MP_UNDEF` if the encoded
- denominator has value zero. If `end` is not NULL then `*end` is set to
- point to the first unconsumed character in the string, after parsing.
- */
- mp_result mp_rat_read_cstring(mp_rat r, mp_size radix, const char *str,
- char **end);
- /** Sets `r` to the value represented by a zero-terminated string `str` having
- one of the following formats, each with an optional leading sign flag:
- n : integer format, e.g. "123"
- n/d : ratio format, e.g., "-12/5"
- z.ffff : decimal format, e.g., "1.627"
- It returns `MP_UNDEF` if the effective denominator is zero. If `end` is not
- NULL then `*end` is set to point to the first unconsumed character in the
- string, after parsing.
- */
- mp_result mp_rat_read_ustring(mp_rat r, mp_size radix, const char *str,
- char **end);
- /** Sets `r` to the value represented by a zero-terminated string `str` in the
- format `"z.ffff"` including a sign flag. It returns `MP_UNDEF` if the
- effective denominator. */
- mp_result mp_rat_read_decimal(mp_rat r, mp_size radix, const char *str);
- /** Sets `r` to the value represented by a zero-terminated string `str` in the
- format `"z.ffff"` including a sign flag. It returns `MP_UNDEF` if the
- effective denominator. If `end` is not NULL then `*end` is set to point to
- the first unconsumed character in the string, after parsing. */
- mp_result mp_rat_read_cdecimal(mp_rat r, mp_size radix, const char *str,
- char **end);
- #ifdef __cplusplus
- }
- #endif
- #endif /* IMRAT_H_ */
|