char _floatnum2logic( t_longint* longint, cfloatnum x) { floatstruct tmp; int digits; digits = float_getexponent(x)+1; if (float_iszero(x) || digits <= 0) { longint->length = 1; longint->value[0] = 0; } else { if (digits > MATHPRECISION) return 0; float_create(&tmp); /* floatnum2longint rounds, we have to truncate first */ float_copy(&tmp, x, digits); if (float_getsign(x) < 0) float_add(&tmp, &tmp, &c1, EXACT); _floatnum2longint(longint, &tmp); float_free(&tmp); if (_bitlength(longint) > LOGICRANGE) return 0; } _zeroextend(longint); if (float_getsign(x) < 0) _not(longint); return 1; }
char float_gamma( floatnum x, int digits) { signed char sign; char result; if (!chckmathparam(x, digits)) return 0; sign = float_getsign(x); if (float_isinteger(x)) { if (sign <= 0) return _seterror(x, ZeroDivide); result = _gammaint(x, digits); } else if (float_getlength(x) - float_getexponent(x) == 2 && float_getdigit(x, float_getlength(x) - 1) == 5) result = _gamma0_5(x, digits); else result = _gamma(x, digits); if (!result) { if (sign < 0) float_seterror(Underflow); else float_seterror(Overflow); float_setnan(x); } return result; }
char _doshift( floatnum dest, cfloatnum x, cfloatnum shift, char right) { int ishift; t_longint lx; if (float_isnan(shift)) return _seterror(dest, NoOperand); if (!float_isinteger(shift)) return _seterror(dest, OutOfDomain); if(!_cvtlogic(&lx, x)) return 0; if (float_iszero(shift)) { float_copy(dest, x, EXACT); return 1; } ishift = float_asinteger(shift); if (ishift == 0) ishift = (3*LOGICRANGE) * float_getsign(shift); if (!right) ishift = -ishift; if (ishift > 0) _shr(&lx, ishift); else _shl(&lx, -ishift); _logic2floatnum(dest, &lx); return 1; }
char _trigreduce( floatnum x, int digits) { floatstruct tmp; int expx, save; signed char sgn; char odd; if (float_abscmp(x, &cPi) <= 0) return 1; expx = float_getexponent(x); if (expx > float_getlength(&cPi) - digits) return 0; save = float_setprecision(MAXDIGITS); float_create(&tmp); sgn = float_getsign(x); float_abs(x); float_divmod(&tmp, x, x, &cPi, INTQUOT); float_setprecision(save); odd = float_isodd(&tmp); if (odd) float_sub(x, x, &cPi, digits+1); if (sgn < 0) float_neg(x); float_free(&tmp); return 1; }
/* evaluates tan x for |x| <= pi. A return value of 0 indicates that x = +/- pi/2 within small tolerances, so that tan x cannot be reliable computed */ char _tan( floatnum x, int digits) { signed char sgn; sgn = float_getsign(x); float_abs(x); if (float_cmp(x, &cPiDiv2) > 0) { float_sub(x, &cPi, x, digits+1); sgn = -sgn; } if (float_cmp(x, &cPiDiv4) <= 0) _tanltPiDiv4(x, digits); else { float_sub(x, &cPiDiv2, x, digits+1); if (float_iszero(x) || float_getexponent(x) < -digits) return 0; _tanltPiDiv4(x, digits); float_reciprocal(x, digits); } float_setsign(x, sgn); return 1; }
Error float_out( p_otokens tokens, floatnum x, int scale, signed char base, char outmode) { t_number_desc n; _emptytokens(tokens); /* do some sanity checks first */ if (!_validmode(outmode) || scale < 0 || !_isvalidbase(base)) return InvalidParam; _clearnumber(&n); if (float_iszero(x)) n.prefix.base = IO_BASE_ZERO; else if (!float_isnan(x)) n.prefix.base = base; if (!_isvalidbase(n.prefix.base)) /* NaN and 0 are handled here */ return desc2str(tokens, &n, 0); n.prefix.sign = float_getsign(x); float_abs(x); switch (outmode) { case IO_MODE_FIXPOINT: return _outfixp(tokens, x, &n, scale); case IO_MODE_ENG: return _outeng(tokens, x, &n, scale); case IO_MODE_COMPLEMENT: return _outcompl(tokens, x, &n, 0); default: return _outsci(tokens, x, &n, scale); } }
static char _lngamma_prim( floatnum x, floatnum revfactor, int* infinity, int digits) { floatstruct tmp; char result; char odd; *infinity = 0; if (float_getsign(x) > 0) return _lngamma_prim_xgt0(x, revfactor, digits); float_copy(revfactor, x, digits + 2); float_sub(x, &c1, x, digits+2); float_create(&tmp); result = _lngamma_prim_xgt0(x, &tmp, digits); if (result) { float_neg(x); odd = float_isodd(revfactor); _sinpix(revfactor, digits); if (float_iszero(revfactor)) { *infinity = 1; float_setinteger(revfactor, odd? -1 : 1); } else float_mul(&tmp, &tmp, &cPi, digits+2); float_div(revfactor, revfactor, &tmp, digits+2); } float_free(&tmp); return result; }
char float_raise( floatnum power, cfloatnum base, cfloatnum exponent, int digits) { signed char sgn; if (float_isnan(exponent) || float_isnan(base)) return _seterror(power, NoOperand); if (digits <= 0 || digits > MATHPRECISION) return _seterror(power, InvalidPrecision); if (float_iszero(base)) { switch(float_getsign(exponent)) { case 0: return _seterror(power, OutOfDomain); case -1: return _seterror(power, ZeroDivide); } return _setzero(power); } sgn = float_getsign(base); if (sgn < 0) { if (!float_isinteger(exponent)) return _seterror(power, OutOfDomain); if ((float_getdigit(exponent, float_getexponent(exponent)) & 1) == 0) sgn = 1; } float_copy(power, base, digits+1); float_abs(power); if (!_raise(power, exponent, digits)) { float_seterror(Overflow); if (float_getexponent(base) * float_getsign(exponent) < 0) float_seterror(Underflow); return _setnan(power); } float_setsign(power, sgn); return 1; }
char float_ln(floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; if (float_getsign(x) <= 0) return _seterror(x, OutOfDomain); _ln(x, digits); return 1; }
char float_lnxplus1( floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; if (float_getsign(x) < 0 && float_getexponent(x) >= 0) return _seterror(x, OutOfDomain); _lnxplus1(x, digits); return 1; }
char float_arcoshxplus1( floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; if (float_getsign(x) < 0) return _seterror(x, OutOfDomain); _arcoshxplus1(x, digits); return 1; }
char float_arccosxplus1( floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; if (float_getsign(x) > 0 || float_abscmp(x, &c2) > 0) return _seterror(x, OutOfDomain); _arccosxplus1(x, digits); return 1; }
static char _pochhammer_i( floatnum x, cfloatnum n, int digits) { /* do not use the expensive Gamma function when a few multiplications do the same */ /* pre: n is an integer */ int ni; signed char result; if (float_iszero(n)) return float_copy(x, &c1, EXACT); if (float_isinteger(x)) { result = -1; float_neg((floatnum)n); if (float_getsign(x) <= 0 && float_cmp(x, n) > 0) /* x and x+n have opposite signs, meaning 0 is among the factors */ result = _setzero(x); else if (float_getsign(x) > 0 && float_cmp(x, n) <= 0) /* x and x+n have opposite signs, meaning at one point you have to divide by 0 */ result = _seterror(x, ZeroDivide); float_neg((floatnum)n); if (result >= 0) return result; } if (float_getexponent(x) < EXPMAX/100) { ni = float_asinteger(n); if (ni != 0 && ni < 50 && ni > -50) return _pochhammer_si(x, ni, digits+2); } return _pochhammer_g(x, n, digits); }
char float_power10( floatnum x, int digits) { signed char sign; if (!chckmathparam(x, digits)) return 0; sign = float_getsign(x); if (_power10(x, digits)) return 1; return sign > 0? _seterror(x, Overflow) : _seterror(x, Underflow); }
char float_exp( floatnum x, int digits) { signed char sgn; if (!chckmathparam(x, digits)) return 0; sgn = float_getsign(x); if (_exp(x, digits)) return 1; if (sgn < 0) return _seterror(x, Underflow); return _seterror(x, Overflow); }
char float_tanh( floatnum x, int digits) { signed char sgn; if (!chckmathparam(x, digits)) return 0; sgn = float_getsign(x); float_abs(x); if (float_cmp(x, &c1Div2) >= 0) _tanhgt0_5(x, digits); else _tanhlt0_5(x, digits); float_setsign(x, sgn); return 1; }
/* evaluates arcsin x for -1 <= x <= 1. The result is in the range -pi/2 <= result <= pi/2 The relative error for a 100 digit result is < 8e-100 */ void _arcsin( floatnum x, int digits) { signed char sgn; if (float_abscmp(x, &c1Div2) <= 0) _arcsinlt0_5(x, digits); else { sgn = float_getsign(x); float_abs(x); _arccos(x, digits); float_sub(x, &cPiDiv2, x, digits); float_setsign(x, sgn); } }
/* evaluates arctan x for all x. The result is in the range -pi/2 < result < pi/2 relative error for a 100 digit result is 9e-100 */ void _arctan( floatnum x, int digits) { signed char sgn; if (float_abscmp(x, &c1) > 0) { sgn = float_getsign(x); float_abs(x); float_reciprocal(x, digits); _arctanlt1(x, digits); float_sub(x, &cPiDiv2, x, digits+1); float_setsign(x, sgn); } else _arctanlt1(x, digits); }
/* evaluate sin x for |x| <= pi/4, using |sin x| = sqrt((1-cos x)*(2 + cos x-1)) relative error for 100 digit results is < 6e-100*/ void _sinltPiDiv4( floatnum x, int digits) { floatstruct tmp; signed char sgn; if (2*float_getexponent(x)+2 < -digits) /* for small x: sin x approx.== x */ return; float_create(&tmp); sgn = float_getsign(x); _cosminus1ltPiDiv4(x, digits); float_add(&tmp, x, &c2, digits+1); float_mul(x, x, &tmp, digits+1); float_abs(x); float_sqrt(x, digits); float_setsign(x, sgn); float_free(&tmp); }
char float_artanhxplus1( floatnum x, int digits) { if (!chckmathparam(x, digits)) return 0; if (float_getsign(x) >= 0 || float_abscmp(x, &c2) >= 0) return _seterror(x, OutOfDomain); if (float_cmp(x, &c1Div2) < 0) { float_neg(x); _artanh1minusx(x, digits); } else { float_sub(x, &c1, x, digits+1); _artanh(x, digits); } return 1; }
/* evaluates arccos x for -1 <= x <= 1. The result is in the range 0 <= result <= pi. The relative error for a 100 digit result is < 5e-100 */ void _arccos( floatnum x, int digits) { signed char sgn; sgn = float_getsign(x); float_abs(x); if (float_cmp(x, &c1Div2) > 0) { float_sub(x, x, &c1, digits+1); _arccosxplus1lt0_5(x, digits); } else { _arcsinlt0_5(x, digits); float_sub(x, &cPiDiv2, x, digits+1); } if (sgn < 0) float_sub(x, &cPi, x, digits+1); }
char float_lg( floatnum x, int digits) { floatstruct tmp; int expx; if (!chckmathparam(x, digits)) return 0; if (float_getsign(x) <= 0) return _seterror(x, OutOfDomain); float_create(&tmp); expx = float_getexponent(x); float_setexponent(x, 0); _ln(x, digits); float_div(x, x, &cLn10, digits); float_setinteger(&tmp, expx); float_add(x, x, &tmp, digits); float_free(&tmp); return 1; }
/* evaluates sin x for |x| <= pi. */ void _sin( floatnum x, int digits) { signed char sgn; sgn = float_getsign(x); float_abs(x); if (float_cmp(x, &cPiDiv2) > 0) float_sub(x, &cPi, x, digits+1); if (float_cmp(x, &cPiDiv4) <= 0) _sinltPiDiv4(x, digits); else { float_sub(x, &cPiDiv2, x, digits+1); if (2*float_getexponent(x)+2 < - digits) float_setzero(x); else _cosminus1ltPiDiv4(x, digits); float_add(x, x, &c1, digits); } float_setsign(x, sgn); }