File indexing completed on 2024-05-12 05:55:14

0001 /* floatnum.h: Arbitrary precision floating point numbers header file. */
0002 /*
0003     Copyright (C) 2007, 2008 Wolf Lammen.
0004 
0005     This program is free software; you can redistribute it and/or modify
0006     it under the terms of the GNU General Public License as published by
0007     the Free Software Foundation; either version 2 of the License , or
0008     (at your option) any later version.
0009 
0010     This program is distributed in the hope that it will be useful,
0011     but WITHOUT ANY WARRANTY; without even the implied warranty of
0012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013     GNU General Public License for more details.
0014 
0015     You should have received a copy of the GNU General Public License
0016     along with this program; see the file COPYING.  If not, write to:
0017 
0018       The Free Software Foundation, Inc.
0019       59 Temple Place, Suite 330
0020       Boston, MA 02111-1307 USA.
0021 
0022 
0023     You may contact the author by:
0024        e-mail:  ookami1 <at> gmx <dot> de
0025        mail:  Wolf Lammen
0026               Oertzweg 45
0027               22307 Hamburg
0028               Germany
0029 
0030 *************************************************************************/
0031 #ifndef FLOATNUM_H
0032 # define FLOATNUM_H
0033 
0034 #include "number.h"
0035 #include "floatconfig.h"
0036 #include "floatio.h"
0037 
0038 #define NULLTERMINATED (-20)
0039 #define UNORDERED (-2)
0040 
0041 #define EXACT (-101)
0042 #define INTQUOT (-102)
0043 
0044 #define float_free(f) float_setnan(f)
0045 
0046 #ifdef __cplusplus
0047 extern "C" {
0048 #endif
0049 
0050 extern int maxdigits;
0051 
0052 typedef struct {
0053   bc_num significand;
0054   int exponent;
0055 #ifdef FLOATDEBUG
0056   char value[110];
0057 #endif /* FLOATDEBUG */
0058 } floatstruct;
0059 
0060 typedef floatstruct* floatnum;
0061 typedef const floatstruct* cfloatnum;
0062 
0063 typedef enum {TONEAREST, TOZERO, TOINFINITY, TOPLUSINFINITY, TOMINUSINFINITY} roundmode;
0064 
0065 /* initializes this module. Has to be called prior to the first
0066    use of any of the following functions */
0067 void floatnum_init();
0068 
0069 /* sets the error to `code' unless it is already set */
0070 void float_seterror(Error code);
0071 
0072 /* gets the last error and clears the error afterwards */
0073 Error float_geterror();
0074 
0075 /* returns the current overflow limit. It is the maximum possible
0076    exponent. The smallest exponent is -`return value' - 1.
0077    This function never reports an error */
0078 int float_getrange();
0079 
0080 /* sets the overflow/underflow limit. Subsequent arithmetic results with exponents
0081    between `maxexp' >= exponent >= -`maxexp'-1 are considered valid, all others
0082    trigger overflow/underflow errors.
0083    `maxexp' cannot be greater than MAXEXP and not less than 1. Exceeding
0084    arguments are replaced by the respective limit.
0085    The return value is the old overflow limit.
0086    This function affects future results only. Current stored values are
0087    not subject to overflow/underflow checking, even when they are used as
0088    parameters to an operation.
0089    This function never reports an error */
0090 int float_setrange(int maxexp);
0091 
0092 /* returns the current precision limit. Arithmetic results may be cut off
0093    after this number of decimal digits */
0094 int float_getprecision();
0095 
0096 /* sets the current maximum precision (in decimal digits) that is used by basic
0097    arithmetic operations. The precision is at least 1 and at most MAXDIGITS.
0098    An exceeding argument is replaced by the respective limit.
0099    Setting a new precision affects future operations only; currently set
0100    variables are kept unmodified.
0101    The return value is the old precision limit.
0102    This function never reports an error */
0103 int float_setprecision(int digits);
0104 
0105 /* checks whether the submitted exponent is within the current overflow and
0106    underflow limits.
0107    This function never reports an error */
0108 char float_isvalidexp(int exp);
0109 
0110 /* initializes a new floatnum to NaN. Call this before
0111    the first use of a floatnum variable.
0112    The destructing function is float_setnan or its alias, float_free.
0113    This function never reports an error. */
0114 void float_create(floatnum f);
0115 
0116 /* finalizes a variable. To avoid memory leaks, call this before a floatnum
0117    is freed. A special value (NaN = not a number) is loaded into `f', so
0118    any subsequent arithmetic operation on this variable will fail.
0119    However, a variable such finalized can still be re-used without prior
0120    initialization, by making it the destination of an operation.
0121    If you wish to deliberately "empty" a variable, without detroying it,
0122    call this function.
0123    An alias "float_free" to this function is defined that you
0124    may use anywhere as a replacement for float_setnan.
0125    This function never reports an error. */
0126 void float_setnan(floatnum f);
0127 
0128 /* returns the base 10 exponent of the value in `f'. If `f' is zero or
0129    NaN, the returned exponent is 0.
0130    This function never reports an error. */
0131 int float_getexponent(cfloatnum f);
0132 
0133 /* fills the buffer `buf' of size `bufsz' with an ASCII string
0134    representing the significand of `f'.
0135    No zeros are padded to the right to fill the buffer in case
0136    of a short significand.
0137    If `bufsz' <= 0, the function returns immediately with result 0.
0138    If the significand does not fit completely into the buffer,
0139    the output is stopped when the last buffer byte is written to.
0140    A non-zero significand yields a sequence of digits, without
0141    a decimal point; zero yields "0" and NaN "N".
0142    On truncation, no trailing zeros are removed.
0143    Exponent and sign are ignored, and no decimal point is written.
0144    No '\0' character is appended to the right.
0145    The return value are the number of characters written to the buffer.
0146    This function never reports an error. */
0147 int float_getsignificand(char* buf, int bufsz, cfloatnum f);
0148 
0149 /* returns the number of digits in the significand, or 0 for NaN and zero.
0150    This function never reports an error. */
0151 int float_getlength(cfloatnum f);
0152 
0153 /* returns 1, if `f' is positive, -1, if `f' is negative, and 0 if `f' is
0154    zero or NaN.
0155    This function never reports an error. */
0156 signed char float_getsign(cfloatnum f);
0157 
0158 /* writes the value stored in `f' as an ASCIIZ string into a buffer of
0159    size `bufsz'. If the buffer is too small to hold the full value,
0160    the significand is truncated appropriately. If the buffer is too small
0161    to even store the most significant digit of the significand besides
0162    exponent and sign, nothing is stored at all, and -1 is returned.
0163    Else, the length of the output, but without the trailing \0
0164    character, is returned.
0165    The output format is the usual scientific format. On truncation,
0166    no trailing zeros are removed from the output of the significand.
0167    Examples of an output:
0168 
0169    value  output
0170    -----  ------
0171    NaN    NaN\0
0172    0      0\0
0173    1      1.e0\0
0174    1.2    1.2e0\0
0175    0.5    5.e-1\0
0176    -1     -1.e0\0
0177    1.009  1.00e0\0 (truncated to 3 digits)
0178    10^10  1.e10\0
0179 
0180    This function does not touch the adjacent bytes of the final
0181    output. If no reasonable output is possible, the complete buffer
0182    is left unchanged, not even the final \0 character is written.
0183    This function never reports an error. */
0184 int float_getscientific(char* buf, int bufsz, cfloatnum f);
0185 
0186 /* gets the `ofs'-th digit from the decimal representation
0187    of the significand of `f'. If `ofs' is negative or greater
0188    equal to the length of the significand, 0 is returned.
0189    The return value is between 0 and 9 (not the ASCII representation
0190    of these digits (0x30 - 0x39)).
0191    This function never returns an error */
0192 char float_getdigit(cfloatnum f, int ofs);
0193 
0194 /* sets the significand according to the the ASCII text in buffer buf
0195    of size `bufsz'.
0196    The buffer must contain digits '0' -'9' only, with one possible
0197    exception: A single decimal point ('.') may be placed anywhere in
0198    the buffer. It is skipped while encoding the significand.
0199    The function searches the buffer for the first non-zero digit,
0200    and starts the encoding from there.
0201    `f' is set to NaN, if the buffer fails to fulfill the above conditions.
0202    If the resulting significand exceeds <maxdigits> digits, it is truncated.
0203    The exponent of `f' is set to 0, so the result is always NaN, 0 or a
0204    number between 1 and 9.99...
0205    If you want to set both the significand and the exponent of f,
0206    set the significand first.
0207    If `leadingzeros' is not NULL, and the result in `f' is neither zero nor
0208    NaN, the number of leading (and skipped) zeros are stored here.
0209    In case of NaN or zero, this value is 0.
0210    All trailing zeros in the significand of `f' are removed.
0211    The result is the position of the decimal point in `buf', or -1
0212    if either none was found, or if it is not relevant (NaN or 0.0).
0213    This function never reports an error. */
0214 int float_setsignificand(floatnum f, int* leadingzeros, const char* buf,
0215                          int bufsz);
0216 
0217 /* sets the base 10 exponent of f to exponent. The significand is
0218    only changed when this operation fails.
0219    Integers greater than EXPMAX or smaller than EXPMIN are not accepted as
0220    exponent and let the operation fail, setting `f' to NaN.
0221    You cannot change the exponent of 0 or NaN, this is ignored.
0222    If you want to set both the significand and the exponent of `f',
0223    set the significand first.
0224    This function never reports an error. */
0225 void float_setexponent(floatnum f, int exponent);
0226 
0227 /* converts an ASCII string of length `bufsz' in `buf' to `f'.
0228    `bufsz' may assume the special value NULLTERMINATED, in which case
0229    the first found \0 character terminates the input.
0230    The input format is
0231    [+|-][digit...][.[digit...][(e|E)[+|-]digit...]]
0232    At least one digit of the significand has to be present.
0233    Any non-valid input is converted into a NaN.
0234    This function never reports an error. */
0235 void float_setscientific(floatnum f, const char* buf, int bufsz);
0236 
0237 /* if `s' is 1 or -1, the sign of `f' is set accordingly. Has no effect, if
0238    `f' == NaN or zero, or `s' == 0. `f' is set to NaN, if |s| > 1.
0239    This function never reports an error. */
0240 void float_setsign(floatnum f, signed char s);
0241 
0242 /* sets dest to the value in `value'.
0243    This function never reports an error. */
0244 void float_setinteger(floatnum dest, int value);
0245 
0246 /* sets a variable to the numerical value zero.
0247    This function never reports an error. */
0248 void float_setzero (floatnum f);
0249 
0250 /* returns 1, if f contains the special NaN value, 0 otherwise.
0251    This function never reports an error. */
0252 char float_isnan(cfloatnum f);
0253 
0254 /* returns 1, if f contains the value zero, 0 otherwise.
0255    This function never reports an error. */
0256 char float_iszero(cfloatnum f);
0257 
0258 /* copies source to dest, limiting the significand to at most `digits' digits.
0259    The parameter `digits' may assume the value EXACT, in which case a full
0260    copy is made.
0261    If source and dest coincide, float_copy tries to re-use the significand.
0262    This prevents unnecessary copying.
0263    If a copy has to be made, the allocated space is just big enough to hold
0264    the significand, so no memory is wasted.
0265    A return value of 0 indicates an error.
0266    errors: InvalidPrecision,   if `digits', or the length of the copy,
0267                                exceeds `maxdigits' */
0268 char float_copy(floatnum dest, cfloatnum source, int digits);
0269 
0270 /* transfers the contents of source to dest. source is assigned NaN
0271    afterwards.
0272    In contrast to float_copy, float_move does not create a copy of
0273    the significand (which employs memory allocation and copying),
0274    but transfers simply the data from the source to the destination.
0275    This function has been designed to implement, for example, swapping
0276    of variables in a fast way.
0277    If dest == source, nothing happens.
0278    This function never reports an error */
0279 void float_move(floatnum dest, floatnum source);
0280 
0281 /* changes the value of `f' to -`f'. Has no effect on zero or NaN.
0282    A return value of 0 indicates an error.
0283    errors: NaNOperand  */
0284 char float_neg(floatnum f);
0285 
0286 /* changes the sign of `f', if `f' is negative. Has no effect on a NaN.
0287    A return value of 0 indicates an error.
0288    errors: NaNOperand */
0289 char float_abs(floatnum f);
0290 
0291 /* compares two values and returns +1 if val1 > val2, 0 if val1 == val2
0292    and -1 if val1 < val2.
0293    This function is not intended to be used with NaN's. If you
0294    pass it as an argument, UNORDERED is returned to indicate an error.
0295    errors: NaNOperand */
0296 signed char float_cmp(cfloatnum val1, cfloatnum val2);
0297 
0298 /* rounds `f' to `digits' digits according to the submitted mode.
0299    If `digits' <= 0 or mode is not recognized, `f' is changed into a NaN.
0300    The same holds should the rounding operation overflow.
0301    mode == TONEAREST: checks whether the first cut off digit
0302                       is a '5' or greater. In this case, the
0303                       absolute value of the significand is rounded up,
0304                       otherwise rounded down. If the part cut off
0305                       is a single digit '5', the significand is
0306                       rounded such that its last digit is even.
0307    mode == TOZERO: cuts off all digits after the `digits'th digit.
0308                    This mode never overflows.
0309    mode = TOINFINITY: rounds positive numbers up, negative numbers down
0310                       (towards greater magnitude).
0311    mode == TOPLUSINFINITY: always rounds up. So, negative values
0312                            are effectively truncated.
0313    mode == TOMINUSINFINITY: always rounds down. So, negative values
0314                             usually increase in magnitude.
0315    A return value of 0 indicates an error.
0316    errors: NaNOperand
0317            InvalidParam
0318            InvalidPrecision
0319            Overflow */
0320 char float_round(floatnum dest, cfloatnum src, int digits, roundmode mode);
0321 
0322 /* cuts off the fractional part of `f'. The result is always less
0323    or equal in magnitude to the passed argument.
0324    A NaN yields a NaN.
0325    A return value of 0 indicates an error.
0326    errors: NaNOperand */
0327 char float_int(floatnum f);
0328 
0329 /* cuts off the integer part of `f'. If the result is not equal to 0,
0330    it has the same sign as the argument.
0331    NaN yields NaN.
0332    A return value of 0 indicates an error.
0333    errors: NaNOperand */
0334 char float_frac(floatnum f);
0335 
0336 /* adds the values in `summand1' and `summand2' and stores the result in
0337    `dest'. `dest' may coincide with either summand (or even both).
0338    The result is evaluated to `digits' or `digits'+1 digits. If `digits'
0339    is EXACT, the sum is evaluated to full scale (if possible).
0340    NaN is returned, if
0341    - (at least) one operand is NaN;
0342    - the result overflows or underflows;
0343    - `digits' is invalid, or the resulting digits exceed `maxdigits'.
0344    A return value of 0 indicates an error.
0345    errors: NaNOperand
0346            InvalidPrecision
0347            Overflow
0348            Underflow */
0349 char float_add(floatnum dest, cfloatnum summand1, cfloatnum summand2,
0350   int digits);
0351 
0352 /* subtracts `subtrahend' from `minuend' and stores the result in
0353    `dest'. `dest' may coincide with either operand (or even both).
0354    The result is evaluated to `digits' or `digits'+1 digits. If `digits'
0355    is EXACT, the difference is evaluated to full scale (if possible).
0356    NaN is returned, if
0357    - (at least) one operand is NaN;
0358    - the result overflows or underflows;
0359    - `digits' is invalid, or the resulting digits exceed `maxdigits'.
0360    A return value of 0 indicates an error.
0361    errors: NaNOperand
0362            InvalidPrecision
0363            Overflow
0364            Underflow */
0365 char float_sub(floatnum dest, cfloatnum minuend, cfloatnum subtrahend,
0366   int digits);
0367 
0368 /* multiplies both factors and stores the result in `dest'. `dest' may
0369    coincide with either factor (or even both). The result is
0370    evaluated to `digits' or `digits'+1 digits, or, if `digits' ==
0371    EXACT, to full scale (if possible).
0372    NaN is returned, if
0373    - (at least) one operand is NaN;
0374    - the result overflows or underflows;
0375    - `digits' is invalid, or the resulting scale exceeds `maxdigits'.
0376    A return value of 0 indicates an error.
0377    errors: NaNOperand
0378            InvalidPrecision
0379            Overflow
0380            Underflow */
0381 char float_mul(floatnum dest, cfloatnum factor1, cfloatnum factor2,
0382   int digits);
0383 
0384 /* divides `dividend' by `divisor' and stores the result in `dest'. `dest'
0385    may coincide with either operand (or even both). The result is
0386    evaluated to `digits' or `digits'+1 digits, or, if `digits' == INTQUOT,
0387    to the size of the integer part of the quotient.
0388    EXACT is not allowed, even in cases where the dividend is divisible
0389    by the divisor.
0390    NaN is returned, if
0391    - (at least) one operand is NaN;
0392    - the result overflows or underflows;
0393    - the divisor is zero;
0394    - `digits' is invalid, or the effective scale exceeds `maxdigits'.
0395    A return value of 0 indicates an error.
0396    errors: NaNOperand
0397            InvalidPrecision
0398            Overflow
0399            Underflow
0400            ZeroDivide */
0401 char float_div(floatnum dest, cfloatnum dividend, cfloatnum divisor,
0402   int digits);
0403 
0404 /* evaluates the quotient, using `digits' steps of the schoolbook
0405    division algorithm. The quotient, thus, has `digits' or `digits'-1 digits,
0406    and is always truncated towards zero.
0407    The remainder fulfills the equation:
0408      remainder = dividend - quotient * divisor.
0409    `digits' may assume the special value INTQUOT, in which case the integer
0410    part of the quotient is calculated.
0411    This function is an exact operation anyway, so EXACT is not allowed
0412    here.
0413    `digits' is subject to the `maxdigits' limit.
0414    `remainder' and `quotient' have to be different variables, but apart from
0415    this, there are no other restrictions on the passed variables.
0416    If this function fails, both result variables are set to NaN.
0417    A return value of 0 indicates an error.
0418    errors: NaNOperand
0419            InvalidParam
0420            InvalidPrecision
0421            TooExpensive
0422            Overflow
0423            Underflow
0424            ZeroDivide */
0425 char float_divmod(floatnum quotient, floatnum remainder, cfloatnum dividend,
0426   cfloatnum divisor, int digits);
0427 
0428 /* computes the sqare root of `value' to `digits' or `digits'+1 digits.
0429    `digits' == EXACT is not allowed, even if the argument is a square.
0430    NaN is returned, if
0431    - the operand is NaN,
0432    - `digits' exceeds `maxdigits'
0433    - the operand is negative.
0434    A return value 0 indicates an error.
0435    errors: NaNOperand
0436            InvalidPrecision
0437            OutOfDomain */
0438 char float_sqrt(floatnum value, int digits);
0439 
0440 /* a few convenience functions used everywhere */
0441 
0442 char _setnan(floatnum result);
0443 char _seterror(floatnum result, Error code);
0444 char _checknan(cfloatnum f);
0445 char _setzero(floatnum x);
0446 
0447 #ifdef __cplusplus
0448 }
0449 #endif
0450 
0451 #endif /* FLOATNUM_H */