File indexing completed on 2024-05-12 05:55:11
0001 /* floatcommon.c: convenience functions, based on floatnum. */ 0002 /* 0003 Copyright (C) 2007 - 2009 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 "floatcommon.h" 0033 #include "floatconst.h" 0034 #include "floatlong.h" 0035 #include <string.h> 0036 #include <math.h> 0037 0038 #define MSB (1 << (sizeof(unsigned)*8 - 1)) 0039 #define LOGMSB ((301*(sizeof(unsigned)*8-1))/1000) 0040 0041 static char 0042 _chckparam1( 0043 cfloatnum x, 0044 int digits, 0045 int limit, 0046 int specialval) 0047 { 0048 if (float_isnan(x)) 0049 { 0050 float_seterror(NoOperand); 0051 return 0; 0052 } 0053 if ((digits <= 0 || digits > limit) && digits != specialval) 0054 { 0055 float_seterror(InvalidPrecision); 0056 return 0; 0057 } 0058 return 1; 0059 } 0060 0061 static char 0062 _chckparam( 0063 floatnum x, 0064 int digits, 0065 int limit, 0066 int specialval) 0067 { 0068 if (!_chckparam1(x, digits, limit, specialval)) 0069 return _setnan(x); 0070 return 1; 0071 } 0072 0073 char 0074 chckmathparam( 0075 floatnum x, 0076 int digits) 0077 { 0078 return _chckparam(x, digits, MATHPRECISION, 1); 0079 } 0080 0081 int 0082 logexp( 0083 cfloatnum x) 0084 { 0085 int expx, result; 0086 0087 expx = float_getexponent(x); 0088 if (expx < 0) 0089 expx = -expx; 0090 result = -1; 0091 while (expx != 0) 0092 { 0093 expx <<= 1; 0094 ++result; 0095 } 0096 return result; 0097 } 0098 0099 void 0100 float_setasciiz( 0101 floatnum x, 0102 const char* asciiz) 0103 { 0104 float_setscientific(x, asciiz, NULLTERMINATED); 0105 } 0106 0107 char 0108 float_divi( 0109 floatnum quotient, 0110 cfloatnum dividend, 0111 int divisor, 0112 int digits) 0113 { 0114 floatstruct tmp; 0115 int result, expx; 0116 0117 if (!_chckparam1(dividend, digits, maxdigits, INTQUOT)) 0118 return _setnan(quotient); 0119 if (digits != INTQUOT && (divisor == 1 || divisor == -1)) 0120 return float_muli(quotient, dividend, divisor, digits); 0121 if (divisor == 10 || divisor == -10) 0122 { 0123 expx = float_getexponent(dividend)-1; 0124 if (expx < -float_getrange() - 1) 0125 return _seterror(quotient, Underflow); 0126 } 0127 float_create(&tmp); 0128 float_setinteger(&tmp, divisor); 0129 result = float_div(quotient, dividend, &tmp, digits); 0130 float_free(&tmp); 0131 return result; 0132 } 0133 0134 char 0135 float_addi( 0136 floatnum sum, 0137 cfloatnum summand1, 0138 int summand2, 0139 int digits) 0140 { 0141 floatstruct tmp; 0142 int result; 0143 0144 if (!_chckparam1(summand1, digits, maxdigits, EXACT)) 0145 return _setnan(sum); 0146 if (summand2 == 0) 0147 return float_copy(sum, summand1, digits); 0148 float_create(&tmp); 0149 float_setinteger(&tmp, summand2); 0150 result = float_add(sum, summand1, &tmp, digits); 0151 float_free(&tmp); 0152 return result; 0153 } 0154 0155 char 0156 float_muli( 0157 floatnum product, 0158 cfloatnum factor1, 0159 int factor2, 0160 int digits) 0161 { 0162 floatstruct tmp; 0163 int result; 0164 int expx; 0165 0166 if (!_chckparam1(factor1, digits, maxdigits, EXACT)) 0167 return _setnan(product); 0168 switch(factor2) 0169 { 0170 case 0: 0171 return _setzero(product); 0172 case 1: 0173 case -1: 0174 case 10: 0175 case -10: 0176 expx = float_getexponent(factor1); 0177 if (factor2 != 1 && factor2 != -1 0178 && ++expx > float_getrange()) 0179 return _seterror(product, Overflow); 0180 result = float_copy(product, factor1, digits); 0181 if (factor2 < 0) 0182 float_neg(product); 0183 float_setexponent(product, expx); 0184 return result; 0185 case 2: 0186 case -2: 0187 result = float_add(product, factor1, factor1, digits); 0188 if (factor2 < 0) 0189 float_neg(product); 0190 return result; 0191 } 0192 float_create(&tmp); 0193 float_setinteger(&tmp, factor2); 0194 result = float_mul(product, factor1, &tmp, digits); 0195 float_free(&tmp); 0196 return result; 0197 } 0198 0199 int 0200 leadingdigits( 0201 cfloatnum x, 0202 int digits) 0203 { 0204 int i; 0205 unsigned tmp, ovfl; 0206 char buf[LOGMSB+1]; 0207 const unsigned msb = MSB; 0208 0209 if (digits <= 0 || digits > (int)LOGMSB+1 || float_isnan(x) || float_iszero(x)) 0210 return 0; 0211 memset(buf, '0', digits); 0212 float_getsignificand(buf, digits, x); 0213 tmp = 0; 0214 for(i = 0; i < digits; ++i) 0215 { 0216 ovfl = 10; 0217 if (_longmul(&tmp, &ovfl)) 0218 { 0219 ovfl = buf[i] - '0'; 0220 _longadd(&tmp, &ovfl); 0221 } 0222 if (ovfl != 0) 0223 return 0; 0224 } 0225 if (float_getsign(x) < 0) 0226 { 0227 if (tmp > msb) 0228 return 0; 0229 if (tmp == msb) 0230 return (int)tmp; 0231 return -(int)tmp; 0232 } 0233 if (tmp >= msb) 0234 return 0; 0235 return (int)tmp; 0236 } 0237 0238 int 0239 float_abscmp( 0240 floatnum x, 0241 floatnum y) 0242 { 0243 signed char sx, sy; 0244 int result; 0245 0246 sx = float_getsign(x); 0247 sy = float_getsign(y); 0248 float_abs(x); 0249 float_abs(y); 0250 result = float_cmp(x, y); 0251 float_setsign(x, sx); 0252 float_setsign(y, sy); 0253 return result; 0254 } 0255 0256 int 0257 float_relcmp( 0258 floatnum x, 0259 floatnum y, 0260 int digits) 0261 { 0262 /* do not simply use float_sub, because of overflow/underflow */ 0263 floatstruct tmp; 0264 int result; 0265 int expx, expy, expdiff; 0266 0267 result = float_cmp(x, y); 0268 if (result == 0 || float_getlength(x) == 0 0269 || float_getlength(y) == 0 0270 || float_getsign(x) != float_getsign(y)) 0271 return result; 0272 expx = float_getexponent(x); 0273 expy = float_getexponent(y); 0274 expdiff = expx - expy; 0275 if (expdiff >= 2 || expdiff < -2) 0276 return result; 0277 float_create(&tmp); 0278 if (result > 0) 0279 float_setexponent(x, 0); 0280 float_setexponent(y, expy - expx); 0281 float_sub(&tmp, x, y, 2); 0282 if ((result * float_getsign(x)) > 0) 0283 float_div(&tmp, &tmp, x, 2); 0284 else 0285 float_div(&tmp, &tmp, y, 2); 0286 if (float_getexponent(&tmp) < -digits) 0287 result = 0; 0288 float_setexponent(x, expx); 0289 float_setexponent(y, expy); 0290 float_free(&tmp); 0291 return result; 0292 } 0293 0294 char 0295 float_reciprocal( 0296 floatnum x, 0297 int digits) 0298 { 0299 return float_div(x, &c1, x, digits); 0300 } 0301 0302 char 0303 float_isinteger( 0304 cfloatnum x) 0305 { 0306 return !float_isnan(x) 0307 && float_getlength(x) <= float_getexponent(x) + 1; 0308 } 0309 0310 int 0311 float_asinteger( 0312 cfloatnum x) 0313 { 0314 return leadingdigits(x, float_getexponent(x)+1); 0315 } 0316 0317 void 0318 float_checkedround( 0319 floatnum x, 0320 int digits) 0321 { 0322 floatstruct tmp; 0323 int saveerr; 0324 0325 saveerr = float_geterror(); 0326 float_create(&tmp); 0327 if (float_round(&tmp, x, digits, TONEAREST)) 0328 float_move(x, &tmp); 0329 float_free(&tmp); 0330 float_geterror(); 0331 float_seterror(saveerr); 0332 } 0333 0334 void 0335 float_addexp( 0336 floatnum x, 0337 int smd) 0338 { 0339 float_setexponent(x, float_getexponent(x) + smd); 0340 } 0341 0342 char 0343 float_isodd( 0344 floatnum x) 0345 { 0346 return (float_getdigit(x, float_getexponent(x)) & 1) != 0; 0347 } 0348 0349 char 0350 float_roundtoint( 0351 floatnum x, 0352 roundmode mode) 0353 { 0354 signed char value = 0; 0355 signed char sign; 0356 char digit; 0357 0358 if (float_isnan(x)) 0359 return float_int(x); /* sets float_error */ 0360 if (float_getexponent(x) >= 0) 0361 return float_round(x, x, float_getexponent(x) + 1, mode); 0362 sign = float_getsign(x); 0363 switch (mode) 0364 { 0365 case TONEAREST: 0366 digit = float_getdigit(x, 0); 0367 if (digit < 5 || (digit == 5 && float_getlength(x) == 1)) 0368 value = 0; 0369 else 0370 value = sign; 0371 break; 0372 case TOINFINITY: 0373 value = sign; 0374 break; 0375 case TOPLUSINFINITY: 0376 value = sign > 0? 1 : 0; 0377 break; 0378 case TOMINUSINFINITY: 0379 value = sign > 0? 0 : -1; 0380 break; 0381 case TOZERO: 0382 value = 0; 0383 break; 0384 } 0385 switch (value) 0386 { 0387 case 0: 0388 float_setzero(x); 0389 break; 0390 case 1: 0391 float_copy(x, &c1, EXACT); 0392 break; 0393 case -1: 0394 float_copy(x, &cMinus1, EXACT); 0395 break; 0396 } 0397 return 1; 0398 } 0399 0400 static float _ipwr(float x, int exp){ 0401 int e = exp < 0? -exp : exp; 0402 double pwr = x; 0403 if ((e & 1) == 0) 0404 x = 1; 0405 while (e >>= 1){ 0406 pwr *= pwr; 0407 if ((exp & 1) != 0) 0408 x *= pwr; 0409 } 0410 return exp < 0? 1/x : x; 0411 } 0412 0413 /* returns x as a float. Only the first 6 digits 0414 contribute to the result. The exponent has to 0415 be in the valid range of a float */ 0416 0417 float float_asfloat(cfloatnum x){ 0418 return leadingdigits(x, 6)/100000.0 * _ipwr(10, float_getexponent(x)); 0419 } 0420 0421 void float_setfloat(floatnum dest, float x){ 0422 int exp = aprxlog10(x); 0423 // use two assignments to avoid overflow 0424 x *= _ipwr(10, -exp); 0425 x *= 100000000; 0426 0427 float_setinteger(dest, (int)x); 0428 float_addexp(dest, exp - 8); 0429 } 0430 0431 /* Somehow math.h cannot always be included with the full set of 0432 ISO C99 math functions enabled. So use the approximations below. 0433 These functions are used to get first guess start values for 0434 iterative algorithms, or to estimate round off errors, or to find 0435 the approximative size of a summand. They need not be 0436 accurate to more than, say, 0.1% */ 0437 0438 float aprxsqrt(float x){ 0439 int exp, i; 0440 float x2 = 2 * frexp(x, &exp) - 1; 0441 float result = (0.5 - 0.125 * x2) * x2 + 1; 0442 x2 += 1; 0443 for (i = 0; ++i <= 2;) 0444 result = 0.5 * (result + x2 / result); 0445 if ((exp & 1) == 0) 0446 result *= M_SQRT2; 0447 return result * _ipwr(2, (exp - 1) >> 1); 0448 } 0449 0450 float aprxln(float x){ 0451 /* The evaluation of approxlog(x) is based 0452 on an approximation suggested by Abramowitz, Stegun, 0453 Handbook of mathematical functions. 0454 The returned logarithm is valid to 0455 5 (decimal) digits after the decimal point. */ 0456 int exp; 0457 0458 x = 2 * frexpf(fabs(x), &exp) - 1; 0459 return ((((0.03215845 * x 0460 - 0.13606275) * x 0461 + 0.28947478) * x 0462 - 0.49190896) * x 0463 + 0.99949556) * x 0464 + (exp - 1) * M_LN2; 0465 } 0466 0467 float aprxlog2(float x){ 0468 return aprxln(x) * M_LOG2E; 0469 } 0470 0471 float aprxlog10(float x){ 0472 return aprxln(x) * M_LOG10E; 0473 } 0474 0475 float aprxlog10fn(cfloatnum x){ 0476 return float_getexponent(x) 0477 + aprxlog10(leadingdigits(x, 5)) - 4; 0478 } 0479 0480 float aprxlngamma(float x){ 0481 return (x-0.5) * aprxln(x) - x + 0.9189385332f; 0482 }