brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.5 KiB · 87e167f Raw
271 lines · c
1/*2  Name:     imrat.h3  Purpose:  Arbitrary precision rational arithmetic routines.4  Author:   M. J. Fromberger5 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 copy9  of this software and associated documentation files (the "Software"), to deal10  in the Software without restriction, including without limitation the rights11  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell12  copies of the Software, and to permit persons to whom the Software is13  furnished to do so, subject to the following conditions:14 15  The above copyright notice and this permission notice shall be included in16  all copies or substantial portions of the Software.17 18  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR19  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,20  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE21  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER22  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 THE24  SOFTWARE.25 */26 27#ifndef IMRAT_H_28#define IMRAT_H_29 30#include <stdbool.h>31 32#include "imath.h"33 34#ifdef __cplusplus35extern "C" {36#endif37 38typedef 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. */44static inline mp_int MP_NUMER_P(mp_rat Q) { return &(Q->num); }45 46/* Return a pointer to the denominator. */47static inline mp_int MP_DENOM_P(mp_rat Q) { return &(Q->den); }48 49/* Rounding constants */50typedef enum {51  MP_ROUND_DOWN,52  MP_ROUND_HALF_UP,53  MP_ROUND_UP,54  MP_ROUND_HALF_DOWN55} mp_round_mode;56 57/** Initializes `r` with 1-digit precision and sets it to zero. This function58    cannot fail unless `r` is NULL. */59mp_result mp_rat_init(mp_rat r);60 61/** Allocates a fresh zero-valued `mpq_t` on the heap, returning NULL in case62    of error. The only possible error is out-of-memory. */63mp_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 the68    sign of the value is carried by the numerator. */69mp_result mp_rat_reduce(mp_rat r);70 71/** Initializes `r` with at least `n_prec` digits of storage for the numerator72    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 to75    the nearest word size. */76mp_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`. The79    new copy does not share storage with the original. */80mp_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`.  It83    returns `MP_UNDEF` if `denom` is zero. */84mp_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 unsigned87    `denom`. It returns `MP_UNDEF` if `denom` is zero. */88mp_result mp_rat_set_uvalue(mp_rat r, mp_usmall numer, mp_usmall denom);89 90/** Releases the storage used by `r`. */91void 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()`. */95void mp_rat_free(mp_rat r);96 97/** Sets `z` to a copy of the numerator of `r`. */98mp_result mp_rat_numer(mp_rat r, mp_int z);99 100/** Returns a pointer to the numerator of `r`. */101mp_int mp_rat_numer_ref(mp_rat r);102 103/** Sets `z` to a copy of the denominator of `r`. */104mp_result mp_rat_denom(mp_rat r, mp_int z);105 106/** Returns a pointer to the denominator of `r`. */107mp_int mp_rat_denom_ref(mp_rat r);108 109/** Reports the sign of `r`. */110mp_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 a113    term of `a` has more significant digits than the corresponding term of `c`114    has allocated. */115mp_result mp_rat_copy(mp_rat a, mp_rat c);116 117/** Sets `r` to zero. The allocated storage of `r` is not changed. */118void mp_rat_zero(mp_rat r);119 120/** Sets `c` to the absolute value of `a`. */121mp_result mp_rat_abs(mp_rat a, mp_rat c);122 123/** Sets `c` to the absolute value of `a`. */124mp_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. */128mp_result mp_rat_recip(mp_rat a, mp_rat c);129 130/** Sets `c` to the sum of `a` and `b`. */131mp_result mp_rat_add(mp_rat a, mp_rat b, mp_rat c);132 133/** Sets `c` to the difference of `a` less `b`. */134mp_result mp_rat_sub(mp_rat a, mp_rat b, mp_rat c);135 136/** Sets `c` to the product of `a` and `b`. */137mp_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. */141mp_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`. */144mp_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`. */147mp_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`. */150mp_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. */154mp_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`. */158mp_result mp_rat_expt(mp_rat a, mp_small b, mp_rat c);159 160/** Returns the comparator of `a` and `b`. */161int mp_rat_compare(mp_rat a, mp_rat b);162 163/** Returns the comparator of the magnitudes of `a` and `b`, disregarding their164    signs. Neither `a` nor `b` is modified by the comparison. */165int mp_rat_compare_unsigned(mp_rat a, mp_rat b);166 167/** Returns the comparator of `r` and zero. */168int 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. */172int 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. */175bool mp_rat_is_integer(mp_rat r);176 177/** Reports whether the numerator and denominator of `r` can be represented as178    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. */180mp_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` and183    `d` in the specified radix and writing no more than `limit` bytes to the184    given output buffer `str`. The output of the numerator includes a sign flag185    if `r` is negative.  Requires `MP_MIN_RADIX <= radix <= MP_MAX_RADIX`. */186mp_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 the189    specified radix, writing no more than `limit` bytes of data to the given190    output buffer.  It generates `prec` digits of precision, and requires191    `MP_MIN_RADIX <= radix <= MP_MAX_RADIX`.192 193    Ratios usually must be rounded when they are being converted for output as194    a decimal value.  There are four rounding modes currently supported:195 196      MP_ROUND_DOWN197        Truncates the value toward zero.198        Example:  12.009 to 2dp becomes 12.00199 200      MP_ROUND_UP201        Rounds the value away from zero:202        Example:  12.001 to 2dp becomes 12.01, but203                  12.000 to 2dp remains 12.00204 205      MP_ROUND_HALF_DOWN206         Rounds the value to nearest digit, half goes toward zero.207         Example:  12.005 to 2dp becomes 12.00, but208                   12.006 to 2dp becomes 12.01209 210      MP_ROUND_HALF_UP211         Rounds the value to nearest digit, half rounds upward.212         Example:  12.005 to 2dp becomes 12.01, but213                   12.004 to 2dp becomes 12.00214*/215mp_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 a219    zero-terminated string in the given `radix`.220    Requires `MP_MIN_RADIX <= radix <= MP_MAX_RADIX`. */221mp_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 the224    `mp_rat_to_decimal()` function with the specified `radix` and `prec`. The225    buffer size estimate may slightly exceed the actual required capacity. */226mp_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 the229    format `"n/d"` including a sign flag. It returns `MP_UNDEF` if the encoded230    denominator has value zero. */231mp_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 the234    format `"n/d"` including a sign flag. It returns `MP_UNDEF` if the encoded235    denominator has value zero. If `end` is not NULL then `*end` is set to236    point to the first unconsumed character in the string, after parsing.237*/238mp_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` having242    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 not249    NULL then `*end` is set to point to the first unconsumed character in the250    string, after parsing.251*/252mp_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 the256    format `"z.ffff"` including a sign flag. It returns `MP_UNDEF` if the257    effective denominator. */258mp_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 the261    format `"z.ffff"` including a sign flag. It returns `MP_UNDEF` if the262    effective denominator. If `end` is not NULL then `*end` is set to point to263    the first unconsumed character in the string, after parsing. */264mp_result mp_rat_read_cdecimal(mp_rat r, mp_size radix, const char *str,265			       char **end);266 267#ifdef __cplusplus268}269#endif270#endif /* IMRAT_H_ */271