#charset "us-ascii"
#pragma once

/* 
 *   Copyright (c) 2000, 2006 Michael J. Roberts
 *   
 *   This file is part of TADS 3.
 *   
 *   This header defines the BigNumber intrinsic class.  
 */

/* include our base class definition */
#include "systype.h"

/*
 *   The BigNumber intrinsic class lets you perform floating-point and
 *   integer arithmetic with (almost) any desired precision.  BigNumber uses
 *   a decimal representation, which means that decimal values can be
 *   represented exactly (i.e., with no rounding errors, as can happen with
 *   IEEE 'double' and 'float' values that languages like C typically
 *   support).  BigNumber combines a varying-length mantissa with an
 *   exponent; the length of the mantissa determines how many digits of
 *   precision a given BigNumber can store, and the exponent lets you
 *   represent very large or very small values with minimal storage.  You can
 *   specify the desired precision when you create a BigNumber explicitly;
 *   when BigNumber values are created implicitly by computations, the system
 *   chooses a precision based on the inputs to the calculations, typically
 *   equal to the largest of the precisions of the input values.
 *   
 *   The maximum precision for a BigNumber is about 64,000 digits, and the
 *   exponent can range from -32768 to +32767.  Since this is a decimal
 *   exponent, this implies an absolute value range from 1.0e-32768 to
 *   1.0e+32767.  The more digits of precision stored in a given BigNumber
 *   value, the more memory the object consumes, and the more time it takes
 *   to perform calculations using the value.  
 */
intrinsic class BigNumber 'bignumber/030001': Object
{
    /* format to a string */
    formatString(maxDigits?, flags?,
                 wholePlaces?, fracDigits?, expDigits?, leadFiller?);

    /* 
     *   compare for equality after rounding to the smaller of my
     *   precision and num's precision 
     */
    equalRound(num);

    /* 
     *   returns an integer giving the number of digits of precision that
     *   this number stores 
     */
    getPrecision();

    /* 
     *   Return a new number, with the same value as this number but with
     *   the given number of decimal digits of precision.  If the new
     *   precision is higher than the old precision, this will increase
     *   the precision to the requested new size and add trailing zeros
     *   to the value.  If the new precision is lower than the old
     *   precision, we'll round the number for the reduced precision.  
     */
    setPrecision(digits);

    /* get the fractional part */
    getFraction();

    /* get the whole part (truncates the fraction - doesn't round) */
    getWhole();

    /* 
     *   round to the given number of digits after the decimal point; if
     *   the value is zero, round to integer; if the value is negative,
     *   round to the given number of places before the decimal point 
     */
    roundToDecimal(places);

    /* return the absolute value */
    getAbs();

    /* least integer greater than or equal to this number */
    getCeil();

    /* greatest integer less than or equal to this number */
    getFloor();

    /* get the base-10 scale of the number */
    getScale();

    /* 
     *   scale by 10^x - if x is positive, this multiplies the number by
     *   ten the given number of times; if x is negative, this divides the
     *   number by ten the given number of times 
     */
    scaleTen(x);

    /* negate - invert the sign of the number */
    negate();

    /* 
     *   copySignFrom - combine the absolute value of self with the sign
     *   of x 
     */
    copySignFrom(x);

    /* determine if the value is negative */
    isNegative();

    /* 
     *   Calculate the integer quotient and the remainder; returns a list
     *   whose first element is the integer quotient (a BigNumber
     *   containing an integer value), and whose second element is the
     *   remainder (the value R such that dividend = quotient*x + R).
     *   
     *   Note that the quotient returned will not necessarily have the
     *   same value as the whole part of dividing self by x with the '/'
     *   operator, because this division handles rounding differently.  In
     *   particular, the '/' operator will perform the appropriate
     *   rounding on the quotient if the quotient has insufficient
     *   precision to represent the exact result.  This routine, in
     *   contrast, does NOT round the quotient, but merely truncates any
     *   trailing digits that cannot be represented in the result's
     *   precision.  The reason for this difference is that it ensures
     *   that the relation (dividend=quotient*x+remainder) holds, which
     *   would not always be the case if the quotient were rounded up.
     *   
     *   Note also that the remainder will not necessarily be less than
     *   the divisor.  If the quotient cannot be exactly represented
     *   (which occurs if the precision of the quotient is smaller than
     *   its scale), the remainder will be the correct value so that the
     *   relationship above holds, rather than the unique remainder that
     *   is smaller than the divisor.  In all cases where there is
     *   sufficient precision to represent the quotient exactly (to the
     *   units digit only, since the quotient returned from this method
     *   will always be an integer), the remainder will satisfy the
     *   relationship AND will be the unique remainder with absolute value
     *   less than the divisor.  
     */
    divideBy(x);

    /* 
     *   calculate and return the trigonometric sine of the value (taken
     *   as a radian value) 
     */
    sine();

    /* 
     *   calculate and return the trigonometric cosine of the value (taken
     *   as a radian value) 
     */
    cosine();

    /* 
     *   calculate and return the trigonometric tangent of the value
     *   (taken as a radian value) 
     */
    tangent();

    /* 
     *   interpreting this number as a number of degrees, convert the
     *   value to radians and return the result 
     */
    degreesToRadians();

    /* 
     *   interpreting this number as a number of radians, convert the
     *   value to degrees and return the result 
     */
    radiansToDegrees();

    /* 
     *   Calculate and return the arcsine (in radians) of the value.  Note
     *   that the value must be between -1 and +1 inclusive, since sine()
     *   never has a value outside of this range. 
     */
    arcsine();

    /* 
     *   Calculate and return the arccosine (in radians).  The value must
     *   be between -1 and +1 inclusive. 
     */
    arccosine();

    /* calculate and return the arctangent (in radians) */
    arctangent();

    /* calculate the square root and return the result */
    sqrt();

    /* 
     *   calculate the natural logarithm of this number and return the
     *   result 
     */
    logE();

    /* 
     *   raise e (the base of the natural logarithm) to the power of this
     *   value and return the result 
     */
    expE();

    /* calculate the base-10 logarithm of the number and return the result */
    log10();

    /* 
     *   raise this number to the power of the argument and return the
     *   result 
     */
    raiseToPower(x);

    /* calculate the hyperbolic sine, cosine, and tangent */
    sinh();
    cosh();
    tanh();

    /* class method: get the value of pi to a given precision */
    getPi(digits);

    /* class method: get the value of e to a given precision */
    getE(digits);

    /*
     *   Get the type of this number.  This returns a combination of
     *   NumTypeXxx flags, combined with the '|' operator.  This can be used
     *   to check for special values, such as infinites and "not a number"
     *   values.  
     */
    numType();
}

/* ------------------------------------------------------------------------ */
/*
 *   flags for formatString 
 */

/* always show a sign, even if positive */
#define BignumSign          0x0001

/* always show in exponential format (scientific notation, as in "1.0e20") */
#define BignumExp           0x0002

/* always show a sign in the exponent, even if positive */
#define BignumExpSign      0x0004

/* 
 *   show a zero before the decimal point - this is only relevant in
 *   non-exponential format when the number is between -1 and +1 
 */
#define BignumLeadingZero  0x0008

/* always show a decimal point */
#define BignumPoint         0x0010

/* insert commas to denote thousands, millions, etc */
#define BignumCommas        0x0020

/* show a leading space if the number is positive */
#define BignumPosSpace     0x0040

/* 
 *   use European-style formatting: use a comma instead of a period for
 *   the decimal point, and use periods instead of commas to set off
 *   thousands, millions, etc 
 */
#define BignumEuroStyle     0x0080

/* 
 *   "Compact" format: use the shorter of the regular format and scientific
 *   notation.  If the scientific notation exponent is less than -4 or
 *   greater than or equal to the number of digits after the decimal point,
 *   we'll use scientific notation; otherwise we'll use the plain format. 
 */
#define BignumCompact      0x0100

/* 
 *   maxDigits counts only significant digits; leading zeros aren't counted
 *   against the maximum. 
 */
#define BignumMaxSigDigits 0x0200

/* 
 *   Keep trailing zeros.  If there's a maxDigits value, this keeps enough
 *   trailing zeros so that the number of digits shown equals maxDigits.  By
 *   default, trailing zeros after the decimal point are removed. 
 */
#define BignumKeepTrailingZeros 0x0400


/* ------------------------------------------------------------------------ */
/*
 *   Number type flags, for numType() 
 */

/*
 *   Number type: ordinary number. 
 */
#define NumTypeNum  0x0001

/* 
 *   Number type: "Not a number" (NaN).  This indicates that the value is the
 *   result of a calculation with invalid input(s).  Currently there are no
 *   BigNumber calculations that return NaNs, as all functions on invalid
 *   inputs throw errors instead.  But it's possible to construct NaN value,
 *   such as by reading an IEEE 754-2008 NaN value from a file via
 *   unpackBytes().  
 */
#define NumTypeNAN  0x0002

/* 
 *   Number type: positive infinity, negative infinity.  These indicate a
 *   value that overflowed the capacity of the BigNumber type, or a
 *   calculation that yields infinity (e.g., tan(pi/2)).  Currently there are
 *   no BigNumber calculations that return Infinities, as all functions where
 *   an overflow is possible throw errors instead.  But it's possible to
 *   construct an Infinity value, such as by reading an IEEE 754-2008
 *   Infinity value from a file via unpackBytes().  
 */
#define NumTypePInf 0x0004
#define NumTypeNInf 0x0008
#define NumTypeInf  (NumTypePInf | NumTypeNInf)

/*
 *   Number type: zero, positive or negative.  Mathematically, zero is
 *   neither positive nor negative, but the BigNumber type retains a sign for
 *   all values, even zeros.  Negative zeros can come from calculations
 *   that yield negative results with absolute values too small for the
 *   internal representation.  It's also possible to construct a negative
 *   zero, such as by reading an IEEE 754-2008 negative zero value from a
 *   file via unpackBytes().  
 */
#define NumTypePZero  0x0010
#define NumTypeNZero  0x0020
#define NumTypeZero (NumTypePZero | NumTypeNZero)


