File indexing completed on 2024-05-12 17:22:34

0001 /* floathmath.c: higher mathematical functions, based on floatnum. */
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 
0032 #include "floathmath.h"
0033 #include "floatconst.h"
0034 #include "floatcommon.h"
0035 #include "floatlog.h"
0036 #include "floatexp.h"
0037 #include "floattrig.h"
0038 #include "floatpower.h"
0039 #include "floatipower.h"
0040 #include "floatgamma.h"
0041 #include "floaterf.h"
0042 #include "floatlogic.h"
0043 
0044 static char
0045 _cvtlogic(
0046   t_longint* lx,
0047   cfloatnum x)
0048 {
0049   if (float_isnan(x))
0050   {
0051     float_seterror(NoOperand);
0052     return 0;
0053   }
0054   if (_floatnum2logic(lx, x))
0055     return 1;
0056   float_seterror(OutOfLogicRange);
0057   return 0;
0058 }
0059 
0060 char
0061 float_lnxplus1(
0062   floatnum x,
0063   int digits)
0064 {
0065   if (!chckmathparam(x, digits))
0066     return 0;
0067   if (float_getsign(x) < 0 && float_getexponent(x) >= 0)
0068     return _seterror(x, OutOfDomain);
0069   _lnxplus1(x, digits);
0070   return 1;
0071 }
0072 
0073 char
0074 float_ln(floatnum x, int digits)
0075 {
0076   if (!chckmathparam(x, digits))
0077     return 0;
0078   if (float_getsign(x) <= 0)
0079     return _seterror(x, OutOfDomain);
0080   _ln(x, digits);
0081   return 1;
0082 }
0083 
0084 char
0085 float_artanh(
0086   floatnum x,
0087   int digits)
0088 {
0089   if (!chckmathparam(x, digits))
0090     return 0;
0091   if (float_getexponent(x) >= 0)
0092     return _seterror(x, OutOfDomain);
0093   _artanh(x, digits);
0094   return 1;
0095 }
0096 
0097 char
0098 float_artanhxplus1(
0099   floatnum x,
0100   int digits)
0101 {
0102   if (!chckmathparam(x, digits))
0103     return 0;
0104   if (float_getsign(x) >= 0 || float_abscmp(x, &c2) >= 0)
0105     return _seterror(x, OutOfDomain);
0106   if (float_cmp(x, &c1Div2) < 0)
0107   {
0108     float_neg(x);
0109     _artanh1minusx(x, digits);
0110   }
0111   else
0112   {
0113     float_sub(x, &c1, x, digits+1);
0114     _artanh(x, digits);
0115   }
0116   return 1;
0117 }
0118 
0119 char
0120 float_arsinh(
0121   floatnum x,
0122   int digits)
0123 {
0124   if (!chckmathparam(x, digits))
0125     return 0;
0126   _arsinh(x, digits);
0127   return 1;
0128 }
0129 
0130 char
0131 float_arcoshxplus1(
0132   floatnum x,
0133   int digits)
0134 {
0135   if (!chckmathparam(x, digits))
0136     return 0;
0137   if (float_getsign(x) < 0)
0138     return _seterror(x, OutOfDomain);
0139   _arcoshxplus1(x, digits);
0140   return 1;
0141 }
0142 
0143 char
0144 float_arcosh(
0145   floatnum x,
0146   int digits)
0147 {
0148   if (!chckmathparam(x, digits))
0149     return 0;
0150   float_sub(x, x, &c1, digits+1);
0151   return float_arcoshxplus1(x, digits);
0152 }
0153 
0154 char
0155 float_lg(
0156   floatnum x,
0157   int digits)
0158 {
0159   floatstruct tmp;
0160   int expx;
0161 
0162   if (!chckmathparam(x, digits))
0163     return 0;
0164   if (float_getsign(x) <= 0)
0165     return _seterror(x, OutOfDomain);
0166   float_create(&tmp);
0167   expx = float_getexponent(x);
0168   float_setexponent(x, 0);
0169   _ln(x, digits);
0170   float_div(x, x, &cLn10, digits);
0171   float_setinteger(&tmp, expx);
0172   float_add(x, x, &tmp, digits);
0173   float_free(&tmp);
0174   return 1;
0175 }
0176 
0177 char
0178 float_lb(
0179   floatnum x,
0180   int digits)
0181 {
0182   if (!chckmathparam(x, digits))
0183     return 0;
0184   if (float_getsign(x) <= 0)
0185     return _seterror(x, OutOfDomain);
0186   _ln(x, digits);
0187   float_div(x, x, &cLn2, digits);
0188   return 1;
0189 }
0190 
0191 char
0192 float_exp(
0193   floatnum x,
0194   int digits)
0195 {
0196   signed char sgn;
0197 
0198   if (!chckmathparam(x, digits))
0199     return 0;
0200   sgn = float_getsign(x);
0201   if (_exp(x, digits))
0202     return 1;
0203   if (sgn < 0)
0204     return _seterror(x, Underflow);
0205   return _seterror(x, Overflow);
0206 }
0207 
0208 char
0209 float_expminus1(
0210   floatnum x,
0211   int digits)
0212 {
0213   if (!chckmathparam(x, digits))
0214     return 0;
0215   if (_expminus1(x, digits))
0216     return 1;
0217   return _seterror(x, Overflow);
0218 }
0219 
0220 char
0221 float_cosh(
0222   floatnum x,
0223   int digits)
0224 {
0225   int expx;
0226 
0227   if (!chckmathparam(x, digits))
0228     return 0;
0229   expx = float_getexponent(x);
0230   if (2*expx+2 <= -digits || !_coshminus1(x, digits+2*expx))
0231   {
0232     if (expx > 0)
0233       return _seterror(x, Overflow);
0234     float_setzero(x);
0235   }
0236   return float_add(x, x, &c1, digits);
0237 }
0238 
0239 char
0240 float_coshminus1(
0241   floatnum x,
0242   int digits)
0243 {
0244   int expx;
0245 
0246   if (!chckmathparam(x, digits))
0247     return 0;
0248   expx = float_getexponent(x);
0249   if (_coshminus1(x, digits))
0250     return 1;
0251   if (expx < 0)
0252     return _seterror(x, Underflow);
0253   return _seterror(x, Overflow);
0254 }
0255 
0256 char
0257 float_sinh(
0258   floatnum x,
0259   int digits)
0260 {
0261   if (!chckmathparam(x, digits))
0262     return 0;
0263   if (_sinh(x, digits))
0264     return 1;
0265   return _seterror(x, Overflow);
0266 }
0267 
0268 char
0269 float_tanh(
0270   floatnum x,
0271   int digits)
0272 {
0273   signed char sgn;
0274 
0275   if (!chckmathparam(x, digits))
0276     return 0;
0277   sgn = float_getsign(x);
0278   float_abs(x);
0279   if (float_cmp(x, &c1Div2) >= 0)
0280     _tanhgt0_5(x, digits);
0281   else
0282     _tanhlt0_5(x, digits);
0283   float_setsign(x, sgn);
0284   return 1;
0285 }
0286 
0287 char
0288 float_tanhminus1(
0289   floatnum x,
0290   int digits)
0291 {
0292   if (!chckmathparam(x, digits))
0293     return 0;
0294   if (float_cmp(x, &c1Div2) >= 0)
0295     return _tanhminus1gt0(x, digits)? 1 : _seterror(x, Underflow);
0296   if (!float_iszero(x))
0297   {
0298     if (float_abscmp(x, &c1Div2) <= 0)
0299       _tanhlt0_5(x, digits);
0300     else
0301     {
0302       float_setsign(x, 1);
0303       _tanhgt0_5(x, digits);
0304       float_setsign(x, -1);
0305     }
0306   }
0307   return float_sub(x, x, &c1, digits);
0308 }
0309 
0310 char
0311 float_arctan(
0312   floatnum x,
0313   int digits)
0314 {
0315   if (!chckmathparam(x, digits))
0316     return 0;
0317   _arctan(x, digits);
0318   return 1;
0319 }
0320 
0321 char
0322 float_arcsin(
0323   floatnum x,
0324   int digits)
0325 {
0326   if (!chckmathparam(x, digits))
0327     return 0;
0328   if (float_abscmp(x, &c1) > 0)
0329     return _seterror(x, OutOfDomain);
0330   _arcsin(x, digits);
0331   return 1;
0332 }
0333 
0334 char
0335 float_arccos(
0336   floatnum x,
0337   int digits)
0338 {
0339   if (!chckmathparam(x, digits))
0340     return 0;
0341   if (float_abscmp(x, &c1) > 0)
0342     return _seterror(x, OutOfDomain);
0343   _arccos(x, digits);
0344   return 1;
0345 }
0346 
0347 char
0348 float_arccosxplus1(
0349   floatnum x,
0350   int digits)
0351 {
0352   if (!chckmathparam(x, digits))
0353     return 0;
0354   if (float_getsign(x) > 0 || float_abscmp(x, &c2) > 0)
0355     return _seterror(x, OutOfDomain);
0356   _arccosxplus1(x, digits);
0357   return 1;
0358 }
0359 
0360 char
0361 float_cos(
0362   floatnum x,
0363   int digits)
0364 {
0365   if (!chckmathparam(x, digits))
0366     return 0;
0367   if (float_getexponent(x) >= DECPRECISION - 1 || !_trigreduce(x, digits))
0368     return _seterror(x, EvalUnstable);
0369   _cos(x, digits);
0370   return 1;
0371 }
0372 
0373 char
0374 float_cosminus1(
0375   floatnum x,
0376   int digits)
0377 {
0378   if (!chckmathparam(x, digits))
0379     return 0;
0380   if (!_trigreduce(x, digits))
0381     return _seterror(x, EvalUnstable);
0382   return _cosminus1(x, digits)? 1 : _seterror(x, Underflow);
0383 }
0384 
0385 char
0386 float_sin(
0387   floatnum x,
0388   int digits)
0389 {
0390   if (!chckmathparam(x, digits))
0391     return 0;
0392   if (float_getexponent(x) >= DECPRECISION - 1 || !_trigreduce(x, digits))
0393     return _seterror(x, EvalUnstable);
0394   _sin(x, digits);
0395   return 1;
0396 }
0397 
0398 char
0399 float_tan(
0400   floatnum x,
0401   int digits)
0402 {
0403   if (!chckmathparam(x, digits))
0404     return 0;
0405   return float_getexponent(x) >= DECPRECISION - 1
0406          || !_trigreduce(x, digits)
0407          || !_tan(x, digits)? _seterror(x, EvalUnstable) : 1;
0408 }
0409 
0410 char
0411 float_raisei(
0412   floatnum power,
0413   cfloatnum base,
0414   int exponent,
0415   int digits)
0416 {
0417   if (digits <= 0 || digits > maxdigits)
0418     return _seterror(power, InvalidPrecision);
0419   if (float_isnan(base))
0420     return _seterror(power, NoOperand);
0421   if (float_iszero(base))
0422   {
0423     if (exponent == 0)
0424       return _seterror(power, OutOfDomain);
0425     if (exponent < 0)
0426       return _seterror(power, ZeroDivide);
0427     return _setzero(power);
0428   }
0429   digits += 14;
0430   if (digits > maxdigits)
0431     digits = maxdigits;
0432   float_copy(power, base, digits);
0433   if (!_raisei(power, exponent, digits)
0434       || !float_isvalidexp(float_getexponent(power)))
0435   {
0436     if (float_getexponent(base) < 0)
0437       return _seterror(power, Underflow);
0438     return _seterror(power, Overflow);
0439   }
0440   return 1;
0441 }
0442 
0443 char
0444 float_raise(
0445   floatnum power,
0446   cfloatnum base,
0447   cfloatnum exponent,
0448   int digits)
0449 {
0450   signed char sgn;
0451 
0452   if (float_isnan(exponent) || float_isnan(base))
0453     return _seterror(power, NoOperand);
0454   if (digits <= 0 || digits > MATHPRECISION)
0455     return _seterror(power, InvalidPrecision);
0456   if (float_iszero(base))
0457   {
0458     switch(float_getsign(exponent))
0459     {
0460     case 0:
0461       return _seterror(power, OutOfDomain);
0462     case -1:
0463       return _seterror(power, ZeroDivide);
0464     }
0465     return _setzero(power);
0466   }
0467   sgn = float_getsign(base);
0468   if (sgn < 0)
0469   {
0470     if (!float_isinteger(exponent))
0471       return _seterror(power, OutOfDomain);
0472     if ((float_getdigit(exponent, float_getexponent(exponent)) & 1) == 0)
0473       sgn = 1;
0474   }
0475   float_copy(power, base, digits+1);
0476   float_abs(power);
0477   if (!_raise(power, exponent, digits))
0478   {
0479     float_seterror(Overflow);
0480     if (float_getexponent(base) * float_getsign(exponent) < 0)
0481       float_seterror(Underflow);
0482     return _setnan(power);
0483   }
0484   float_setsign(power, sgn);
0485   return 1;
0486 }
0487 
0488 char
0489 float_power10(
0490   floatnum x,
0491   int digits)
0492 {
0493   signed char sign;
0494 
0495   if (!chckmathparam(x, digits))
0496     return 0;
0497   sign = float_getsign(x);
0498   if (_power10(x, digits))
0499     return 1;
0500   return sign > 0? _seterror(x, Overflow) : _seterror(x, Underflow);
0501 }
0502 
0503 char
0504 float_gamma(
0505   floatnum x,
0506   int digits)
0507 {
0508   signed char sign;
0509   char result;
0510 
0511   if (!chckmathparam(x, digits))
0512     return 0;
0513   sign = float_getsign(x);
0514   if (float_isinteger(x))
0515   {
0516     if (sign <= 0)
0517       return _seterror(x, ZeroDivide);
0518     result = _gammaint(x, digits);
0519   }
0520   else if (float_getlength(x) - float_getexponent(x) == 2
0521            && float_getdigit(x, float_getlength(x) - 1) == 5)
0522     result = _gamma0_5(x, digits);
0523   else
0524     result = _gamma(x, digits);
0525   if (!result)
0526   {
0527     if (sign < 0)
0528       float_seterror(Underflow);
0529     else
0530       float_seterror(Overflow);
0531     float_setnan(x);
0532   }
0533   return result;
0534 }
0535 
0536 char
0537 float_lngamma(
0538   floatnum x,
0539   int digits)
0540 {
0541   if (!x)
0542     return _seterror(x, OutOfDomain);
0543   return chckmathparam(x, digits) && _lngamma(x, digits)?
0544           1 : _setnan(x);
0545 }
0546 
0547 char
0548 float_factorial(
0549   floatnum x,
0550   int digits)
0551 {
0552   if (!float_isnan(x))
0553     float_add(x, x, &c1, digits);
0554   return float_gamma(x, digits);
0555 }
0556 
0557 char
0558 float_pochhammer(
0559   floatnum x,
0560   cfloatnum delta,
0561   int digits)
0562 {
0563   if (!chckmathparam(x, digits))
0564     return 0;
0565   return float_isnan(delta)?
0566          _seterror(x, NoOperand)
0567          : _pochhammer(x, delta, digits);
0568 }
0569 
0570 char
0571 float_erf(floatnum x, int digits)
0572 {
0573   return chckmathparam(x, digits)? _erf(x, digits) : 0;
0574 }
0575 
0576 char
0577 float_erfc(floatnum x, int digits)
0578 {
0579   return chckmathparam(x, digits)? _erfc(x, digits) : 0;
0580 }
0581 
0582 char
0583 float_not(
0584   floatnum x)
0585 {
0586   t_longint lx;
0587 
0588   if(!_cvtlogic(&lx, x))
0589     return _setnan(x);
0590   _not(&lx);
0591   _logic2floatnum(x, &lx);
0592   return 1;
0593 }
0594 
0595 char
0596 float_and(
0597   floatnum dest,
0598   cfloatnum x,
0599   cfloatnum y)
0600 {
0601   t_longint lx, ly;
0602 
0603   if(!_cvtlogic(&lx, x) || !_cvtlogic(&ly, y))
0604     return _setnan(dest);
0605   _and(&lx, &ly);
0606   _logic2floatnum(dest, &lx);
0607   return 1;
0608 }
0609 
0610 char
0611 float_or(
0612   floatnum dest,
0613   cfloatnum x,
0614   cfloatnum y)
0615 {
0616   t_longint lx, ly;
0617 
0618   if(!_cvtlogic(&lx, x) || !_cvtlogic(&ly, y))
0619     return _setnan(dest);
0620   _or(&lx, &ly);
0621   _logic2floatnum(dest, &lx);
0622   return 1;
0623 }
0624 
0625 char
0626 float_xor(
0627   floatnum dest,
0628   cfloatnum x,
0629   cfloatnum y)
0630 {
0631   t_longint lx, ly;
0632 
0633   if(!_cvtlogic(&lx, x) || !_cvtlogic(&ly, y))
0634     return _setnan(dest);
0635   _xor(&lx, &ly);
0636   _logic2floatnum(dest, &lx);
0637   return 1;
0638 }
0639 
0640 char
0641 _doshift(
0642   floatnum dest,
0643   cfloatnum x,
0644   cfloatnum shift,
0645   char right)
0646 {
0647   int ishift;
0648   t_longint lx;
0649 
0650   if (float_isnan(shift))
0651     return _seterror(dest, NoOperand);
0652   if (!float_isinteger(shift))
0653     return _seterror(dest, OutOfDomain);
0654   if(!_cvtlogic(&lx, x))
0655     return 0;
0656   if (float_iszero(shift))
0657   {
0658     float_copy(dest, x, EXACT);
0659     return 1;
0660   }
0661   ishift = float_asinteger(shift);
0662   if (ishift == 0)
0663     ishift = (3*LOGICRANGE) * float_getsign(shift);
0664   if (!right)
0665     ishift = -ishift;
0666   if (ishift > 0)
0667     _shr(&lx, ishift);
0668   else
0669     _shl(&lx, -ishift);
0670   _logic2floatnum(dest, &lx);
0671   return 1;
0672 }
0673 
0674 char
0675 float_shr(
0676   floatnum dest,
0677   cfloatnum x,
0678   cfloatnum shift)
0679 {
0680   return _doshift(dest, x, shift, 1);
0681 }
0682 
0683 char
0684 float_shl(
0685   floatnum dest,
0686   cfloatnum x,
0687   cfloatnum shift)
0688 {
0689   return _doshift(dest, x, shift, 0);
0690 }