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 }