From: Mapi B. <ma...@us...> - 2009-07-05 20:53:20
|
Update of /cvsroot/easycalc/PPCport/compat In directory 23jxhf1.ch3.sourceforge.com:/tmp/cvs-serv17350 Added Files: MathLib.cpp MathLib.h Preferences.cpp Preferences.h Log Message: MathLib compatibility --- NEW FILE: Preferences.cpp --- #include "StdAfx.h" #include "Preferences.h" #include <winnls.h> #define DEC_DOT 0 #define DEC_COM 1 #define TH_SPC 0 #define TH_COM 1 #define TH_DOT 2 #define TH_APO 3 unsigned int PrefGetPreference(SystemPreferencesChoice choice) { unsigned int returnVal; switch (choice) { case prefNumberFormat: { int dec, th; TCHAR cdec[10], cth[10]; int rcdec = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, cdec, 9 ); int rcth = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, cth, 9 ); if (rcdec <= 0) dec = DEC_DOT; // By default .. else { cdec[rcdec] = 0; if (_tcsstr(cdec, _T(",")) != NULL) { dec = DEC_COM; } else { dec = DEC_DOT; // By default } } if (rcth <= 0) th = TH_SPC; // By default .. else { cth[rcth] = 0; if (_tcsstr(cth, _T("'")) != NULL) { th = TH_APO; } else if (_tcsstr(cth, _T(".")) != NULL) { th = TH_DOT; } else if (_tcsstr(cth, _T(",")) != NULL) { th = TH_COM; } else { th = TH_SPC; // By default } } if ((th == TH_APO) && (dec == DEC_COM)) returnVal = nfApostropheComma; else if ((th == TH_APO) && (dec == DEC_DOT)) returnVal = nfApostrophePeriod; else if ((th == TH_SPC) && (dec == DEC_COM)) returnVal = nfSpaceComma; else if ((th == TH_DOT) && (dec == DEC_COM)) returnVal = nfPeriodComma; else returnVal = nfCommaPeriod; } break; default: returnVal = 0; } return (returnVal); } --- NEW FILE: Preferences.h --- #pragma once #ifndef PREFERENCES_H #define PREFERENCES_H 1 typedef enum { nfCommaPeriod, nfPeriodComma, nfSpaceComma, nfApostrophePeriod, nfApostropheComma } NumberFormatType; typedef enum { prefNumberFormat } SystemPreferencesChoice; unsigned int PrefGetPreference(SystemPreferencesChoice choice); #endif --- NEW FILE: MathLib.h --- /* MathLib: Pilot shared library of IEEE-754 double math functions * * Library function prototypes for the calling application. This is * the file that the calling application should include in order to * get access to the routines in the library; it serves the same * function as the file "math.h" normally used on systems with * standard math libraries. Each function in the library has two * prototypes listed; the first is for the programmer-friendly * wrapper function in MathLib.c, the second is for the raw SYS_TRAP() * invocation that actually calls the library routine. * * Copyright (C) 1997 Rick Huebner * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this program; see file COPYING.LIB. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA * * Version 1.01, 23 August 1997, Rick Huebner */ #ifndef __MATHLIB_H__ #define __MATHLIB_H__ // This is the major version number of the library. If new functions // are added to this library, this version number must be incremented // to protect programs which are compiled with this header from trying // to invoke the new functions in an old version of MathLib.prc, // which would be fatal. Do NOT delete any functions from this list, // or any older programs which try to use them will die. Any changes // other than adding new functions should be reflected in the minor // part of the version number, e.g. 1.1 if a bug fix, 2.0 if new // functions added. #define MathLibVersion 1 // Possible Err values from MathLib functions typedef enum MathLibErrorCode { mlErrNone = 0, mlErrOldVersion, // library is older than version passed to open() mlErrNotOpen, // close() without having called open() first mlErrNoMemory // can't allocate global data block } MathLibErrorCode; // Library reference returned by SysLibFind() or SysLibLoad() extern UInt16 MathLibRef; /***************************** * Library control functions * *****************************/ Err MathLibOpen(UInt16 refnum, UInt16 version) // Initialize library for use SYS_TRAP(sysLibTrapOpen); Err MathLibClose(UInt16 refnum, UInt16 *usecountP)// Free library resources when finished SYS_TRAP(sysLibTrapClose); Err MathLibSleep(UInt16 refnum) // Called by OS when Pilot sleeps SYS_TRAP(sysLibTrapSleep); Err MathLibWake(UInt16 refnum) // Called by OS when Pilot wakes SYS_TRAP(sysLibTrapWake); /*************************** * Trigonometric functions * ***************************/ //double acos(double x); // Arc cosine of x //double asin(double x); // Arc sine of x //double atan(double x); // Arc tangent of x //double atan2(double y, double x); // Arc tangent of y/x //double cos(double x); // Cosine of x //double sin(double x); // Sine of x //double tan(double x); // Tangent of x void sincos(double x, double *sinx, double *cosx); // Sine and cosine of x /************************ * Hyperbolic functions * ************************/ //double cosh(double x); // Hyperbolic cosine of x //double sinh(double x); // Hyperbolic sine of x //double tanh(double x); // Hyperbolic tangent of x double acosh(double x); // Hyperbolic arc cosine of x double asinh(double x); // Hyperbolic arc sine of x double atanh(double x); // Hyperbolic arc tangent of x /***************************************** * Exponential and logarithmic functions * *****************************************/ //double exp(double x); // Exponential function of x [pow(e,x)] //double frexp(double x, Int16 *exponent); // Break x into normalized fraction and an integral power of 2 //double ldexp(double x, Int16 exponent); // x * pow(2,exponent) //double log(double x); // Natural logarithm of x //double log10(double x); // Base 10 logarithm of x //double modf(double x, double *intpart); // Break x into integral and fractional parts double expm1(double x); // exp(x) - 1 double log1p(double x); // log(1+x) //double logb(double x); // Base 2 signed integral exponent of x #define logb(x) _logb(x) double log2(double x); // Base 2 logarithm of x /******************* * Power functions * *******************/ //double pow(double x, double y); // x to the y power [x**y] //double sqrt(double x); // Square root of x [x**0.5] //double hypot(double x, double y); // sqrt(x*x + y*y) [hypotenuse of right triangle] #define hypot(x,y) _hypot(x,y) double cbrt(double x); // Cube root of x [x**(1/3)] /************************************************************ * Nearest integer, absolute value, and remainder functions * ************************************************************/ //double ceil(double x); // Smallest integral value not less than x //double fabs(double x); // Absolute value of x //double floor(double x); // Largest integral value not greater than x //double fmod(double x, double y); // Modulo remainder of x/y /*************************** * Miscellaneous functions * ***************************/ //Int16 isinf(double x); // Return 0 if x is finite or NaN, +1 if +Infinity, or -1 if -Infinity int isinf(double x); //Int16 finite(double x); // Return nonzero if x is finite and not NaN #define finite(x) _finite(x) //double scalbn(double x, Int16 exponent); // x * pow(2,exponent) #define scalbn(x,exponent) _scalb(x,(long)exponent) double drem(double x, double y); // Remainder of x/y double significand(double x); // Fractional part of x after dividing out ilogb(x) //double copysign(double x, double y); // Return x with its sign changed to match y's #define copysign(x,y) _copysign(x,y) //Int16 isnan(double x); // Return nonzero if x is NaN (Not a Number) #define isnan(x) _isnan(x) //Int16 ilogb(double x); // Binary exponent of non-zero x int ilogb(double x); double rint(double x); // Integral value nearest x in direction of prevailing rounding mode //double nextafter(double x, double y); // Next machine double value after x in the direction towards y #define nextafter(x,y) _nextafter(x,y) //double remainder(double x, double y); // Remainder of integer division x/y with infinite precision #define remainder(x,y) drem(x,y) // Not used by EasyCalc, and not worth a fudge ... //double scalb(double x, double exponent);// x * pow(2,exponent) double round(double x); // Round x to nearest integral value away from zero double trunc(double x); // Round x to nearest integral value not larger than x //UInt32 signbit(double x); // Return signbit of x's machine representation #define signbit(x) ((_fpclass(x) & (_FPCLASS_NINF | _FPCLASS_NN | _FPCLASS_ND | _FPCLASS_NZ) != 0) #endif // __MATHLIB_H__ --- NEW FILE: MathLib.cpp --- /* MathLib: Pilot shared library of IEEE-754 double math functions * * Convenience functions for the calling application. These functions * provide a programmer-friendly wrapper around the raw system trap * invocations which actually call the library routines. The idea * is to allow the programmer to say: * y = sqrt(x); * instead of requiring: * MathLibSqrt(MathLibRef, x, &y); * like the system trap interface requires. The system trap form is * not only harder to read, but can't directly replace the traditional * function call in ported code, and can't be nested inside an expression. * Just add this source file to your project or makefile, and include * "MathLib.h" in any source file that needs to call these. * * The downside to these routines is that they'll take up some space * in your program, though CodeWarrior at least is smart enough to * only link in the ones which you actually use, so it doesn't really * cost you that much. In fact, if you call these enough they'll pay * for themselves, since "x=sqrt(x)" generates much less code than * calling MathLibSqrt() directly. * * Copyright (C) 1997 Rick Huebner * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this program; see file COPYING.LIB. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * Version 1.01, 23 August 1997, Rick Huebner */ #include "stdafx.h" #include "PalmOS.h" #include "MathLib.h" #include "defuns.h" // Library reference returned by SysLibFind() or SysLibLoad() UInt16 MathLibRef; //double acos(double x) { // double result; // MathLibACos(MathLibRef, x, &result); // return result; //} //double asin(double x) { // double result; // MathLibASin(MathLibRef, x, &result); // return result; //} //double atan(double x) { // double result; // MathLibATan(MathLibRef, x, &result); // return result; //} //double atan2(double y, double x) { // double result; // MathLibATan2(MathLibRef, y, x, &result); // return result; //} //double cos(double x) { // double result; // MathLibCos(MathLibRef, x, &result); // return result; //} //double sin(double x) { // double result; // MathLibSin(MathLibRef, x, &result); // return result; //} //double tan(double x) { // double result; // MathLibTan(MathLibRef, x, &result); // return result; //} //void sincos(double x, double *sinx, double *cosx) { // MathLibSinCos(MathLibRef, x, sinx, cosx); //} void sincos(double x, double *sinx, double *cosx) { // Note: could also be calculated with: //1. Reduce the angle x to the range (0, pi/2) //2. Let z = tan(x/2), // then sin(x) = 2*z/(1+z*z), cos(x) = (1-z*z)/(1+z*z) . // But with a floating point unit around ... not sure that // the perf/accuracy tradeoff is so beneficial. // The ARM processor does not have a sincos function like on Intel/AMD. *sinx = sin(x); *cosx = cos(x); } //double cosh(double x) { // double result; // MathLibCosH(MathLibRef, x, &result); // return result; //} //double sinh(double x) { // double result; // MathLibSinH(MathLibRef, x, &result); // return result; //} //double tanh(double x) { // double result; // MathLibTanH(MathLibRef, x, &result); // return result; //} //double acosh(double x) { // double result; // MathLibACosH(MathLibRef, x, &result); // return result; //} double acosh(double x) { //acosh(x) = ln(x + sqrt(x-1) * sqrt(x+1)) // = ln(x + sqrt(x*x-1)) //for x > 1 //Note: acosh(1) = 0 double result = 0.0; if (x < 1.0) result = NaN; else if (isinf(x)) result = x; else if (x > 1.0) result = log(x + sqrt(x*x - 1.0)); return (result); } //double asinh(double x) { // double result; // MathLibASinH(MathLibRef, x, &result); // return result; //} double asinh(double x) { //asinh(x) = ln(x + sqrt(x*x+1)) //for x > 0 //asinh(0) = 0 //If x<0, take the opposite or the result calculated with -x. double result = 0.0; if (isinf(x) || _isnan(x)) result = x; else if (x > 0.0) result = log(x + sqrt(x*x + 1.0)); else if (x < 0.0) result = -log(-x + sqrt(x*x + 1.0)); return (result); } //double atanh(double x) { // double result; // MathLibATanH(MathLibRef, x, &result); // return result; //} double atanh(double x) { //atan(x) = 1/2 * ln((1+x)/(1-x)) //for -1 < x < 1 //atanh(-1) = -infinity //atanh(1) = +infinity double result = 0.0; if (_isnan(x) || (x < -1.0) || (x > 1.0)) result = NaN; else if ((x == 1.0) || (x == -1.0)) result = x / 0.0; else if (x != 0.0) // result = 0.5 * log((1.0 + x) * (1.0 - x)); result = _scalb(log((1.0 + x) * (1.0 - x)), -1); return (result); } //double exp(double x) { // double result; // MathLibExp(MathLibRef, x, &result); // return result; //} //double frexp(double x, Int16 *exponent) { // double fraction; // MathLibFrExp(MathLibRef, x, &fraction, exponent); // return fraction; //} //double ldexp(double x, Int16 exponent) { // double result; // MathLibLdExp(MathLibRef, x, exponent, &result); // return result; //} //double log(double x) { // double result; // MathLibLog(MathLibRef, x, &result); // return result; //} //double log10(double x) { // double result; // MathLibLog10(MathLibRef, x, &result); // return result; //} //double modf(double x, double *intpart) { // double fraction; // MathLibModF(MathLibRef, x, intpart, &fraction); // return fraction; //} //double expm1(double x) { // double result; // MathLibExpM1(MathLibRef, x, &result); // return result; //} /*************************************************************** * The following is imported from the Free42 source code 1.4.50 at * http://free42.sourceforge.net/ , from pocketpc/mathfudge.c, * itself borrowing the log1p() and expm1() parts from the GNU C * Library, version 2.2.5, originally donated by Sun Microsystems. * Indeed, the Microsoft Visual series are missing those functions. ***************************************************************/ static double //one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */ //ln2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */ ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */ ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */ //two54 = 1.80143985094819840000e+16, /* 43500000 00000000 */ vast= 1.00000000000000000000e+300; #define int32_t int #define u_int32_t unsigned int /* __FLOAT_WORD_ORDER == LITTLE_ENDIAN */ typedef union { double d; struct { int lx, hx; } w; } double_words; /* Get the more significant 32 bit int from a double. */ typedef union { double value; struct { u_int32_t lsw; u_int32_t msw; } parts; } ieee_double_shape_type; #define GET_HIGH_WORD(i,d) \ do { \ ieee_double_shape_type gh_u; \ gh_u.value = (d); \ (i) = gh_u.parts.msw; \ } while (0) /* Get the less significant 32 bit int from a double. */ #define GET_LOW_WORD(i,d) \ do { \ ieee_double_shape_type gl_u; \ gl_u.value = (d); \ (i) = gl_u.parts.lsw; \ } while (0) /* Set the more significant 32 bits of a double from an int. */ #define SET_HIGH_WORD(d,v) \ do { \ ieee_double_shape_type sh_u; \ sh_u.value = (d); \ sh_u.parts.msw = (v); \ (d) = sh_u.value; \ } while (0) /*---------------------------------------------------------------------------*/ /* @(#)s_expm1.c 5.1 93/09/24 */ /* * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * * Developed at SunPro, a Sun Microsystems, Inc. business. * Permission to use, copy, modify, and distribute this * software is freely granted, provided that this notice * is preserved. * ==================================================== */ /* Modified by Naohiko Shimizu/Tokai University, Japan 1997/08/25, for performance improvement on pipelined processors. */ /* expm1(x) * Returns exp(x)-1, the exponential of x minus 1. * * Method * 1. Argument reduction: * Given x, find r and integer k such that * * x = k*ln2 + r, |r| <= 0.5*ln2 ~ 0.34658 * * Here a correction term c will be computed to compensate * the error in r when rounded to a floating-point number. * * 2. Approximating expm1(r) by a special rational function on * the interval [0,0.34658]: * Since * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ... * we define R1(r*r) by * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r) * That is, * R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r) * = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r)) * = 1 - r^2/60 + r^4/2520 - r^6/100800 + ... * We use a special Reme algorithm on [0,0.347] to generate * a polynomial of degree 5 in r*r to approximate R1. The * maximum error of this polynomial approximation is bounded * by 2**-61. In other words, * R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5 * where Q1 = -1.6666666666666567384E-2, * Q2 = 3.9682539681370365873E-4, * Q3 = -9.9206344733435987357E-6, * Q4 = 2.5051361420808517002E-7, * Q5 = -6.2843505682382617102E-9; * (where z=r*r, and the values of Q1 to Q5 are listed below) * with error bounded by * | 5 | -61 * | 1.0+Q1*z+...+Q5*z - R1(z) | <= 2 * | | * * expm1(r) = exp(r)-1 is then computed by the following * specific way which minimize the accumulation rounding error: * 2 3 * r r [ 3 - (R1 + R1*r/2) ] * expm1(r) = r + --- + --- * [--------------------] * 2 2 [ 6 - r*(3 - R1*r/2) ] * * To compensate the error in the argument reduction, we use * expm1(r+c) = expm1(r) + c + expm1(r)*c * ~ expm1(r) + c + r*c * Thus c+r*c will be added in as the correction terms for * expm1(r+c). Now rearrange the term to avoid optimization * screw up: * ( 2 2 ) * ({ ( r [ R1 - (3 - R1*r/2) ] ) } r ) * expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- ) * ({ ( 2 [ 6 - r*(3 - R1*r/2) ] ) } 2 ) * ( ) * * = r - E * 3. Scale back to obtain expm1(x): * From step 1, we have * expm1(x) = either 2^k*[expm1(r)+1] - 1 * = or 2^k*[expm1(r) + (1-2^-k)] * 4. Implementation notes: * (A). To save one multiplication, we scale the coefficient Qi * to Qi*2^i, and replace z by (x^2)/2. * (B). To achieve maximum accuracy, we compute expm1(x) by * (i) if x < -56*ln2, return -1.0, (raise inexact if x!=inf) * (ii) if k=0, return r-E * (iii) if k=-1, return 0.5*(r-E)-0.5 * (iv) if k=1 if r < -0.25, return 2*((r+0.5)- E) * else return 1.0+2.0*(r-E); * (v) if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1) * (vi) if k <= 20, return 2^k((1-2^-k)-(E-r)), else * (vii) return 2^k(1-((E+2^-k)-r)) * * Special cases: * expm1(INF) is INF, expm1(NaN) is NaN; * expm1(-INF) is -1, and * for finite argument, only expm1(0)=0 is exact. * * Accuracy: * according to an error analysis, the error is always less than * 1 ulp (unit in the last place). * * Misc. info. * For IEEE double * if x > 7.09782712893383973096e+02 then expm1(x) overflow * * Constants: * The hexadecimal values are the intended ones for the following * constants. The decimal values may be used, provided that the * compiler will convert from decimal to binary accurately enough * to produce the hexadecimal values shown. */ #define one Q[0] static double /*vast = 1.0e+300,*/ tiny = 1.0e-300, o_threshold = 7.09782712893383973096e+02,/* 0x40862E42, 0xFEFA39EF */ /*ln2_hi = 6.93147180369123816490e-01,*/ /* 0x3fe62e42, 0xfee00000 */ /*ln2_lo = 1.90821492927058770002e-10,*/ /* 0x3dea39ef, 0x35793c76 */ invln2 = 1.44269504088896338700e+00,/* 0x3ff71547, 0x652b82fe */ /* scaled coefficients related to expm1 */ Q[] = {1.0, -3.33333333333331316428e-02, /* BFA11111 111110F4 */ 1.58730158725481460165e-03, /* 3F5A01A0 19FE5585 */ -7.93650757867487942473e-05, /* BF14CE19 9EAADBB7 */ 4.00821782732936239552e-06, /* 3ED0CFCA 86E65239 */ -2.01099218183624371326e-07}; /* BE8AFDB7 6E09C32D */ double expm1(double x) { double y,hi,lo,c,t,e,hxs,hfx,r1,h2,h4,R1,R2,R3; int32_t k,xsb; u_int32_t hx; GET_HIGH_WORD(hx,x); xsb = hx&0x80000000; /* sign bit of x */ if(xsb==0) y=x; else y= -x; /* y = |x| */ hx &= 0x7fffffff; /* high word of |x| */ /* filter out vast and non-finite argument */ if(hx >= 0x4043687A) { /* if |x|>=56*ln2 */ if(hx >= 0x40862E42) { /* if |x|>=709.78... */ if(hx>=0x7ff00000) { u_int32_t low; GET_LOW_WORD(low,x); if(((hx&0xfffff)|low)!=0) return x+x; /* NaN */ else return (xsb==0)? x:-1.0;/* exp(+-inf)={inf,-1} */ } if(x > o_threshold) return vast*vast; /* overflow */ } if(xsb!=0) { /* x < -56*ln2, return -1.0 with inexact */ if(x+tiny<0.0) /* raise inexact */ return tiny-one; /* return -1 */ } } /* argument reduction */ if(hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */ if(hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */ if(xsb==0) {hi = x - ln2_hi; lo = ln2_lo; k = 1;} else {hi = x + ln2_hi; lo = -ln2_lo; k = -1;} } else { k = (int32_t) (invln2*x+((xsb==0)?0.5:-0.5)); t = k; hi = x - t*ln2_hi; /* t*ln2_hi is exact here */ lo = t*ln2_lo; } x = hi - lo; c = (hi-x)-lo; } else if(hx < 0x3c900000) { /* when |x|<2**-54, return x */ t = vast+x; /* return x with inexact flags when x!=0 */ return x - (t-(vast+x)); } else k = 0; /* x is now in primary range */ hfx = 0.5*x; hxs = x*hfx; #ifdef DO_NOT_USE_THIS r1 = one+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5)))); #else R1 = one+hxs*Q[1]; h2 = hxs*hxs; R2 = Q[2]+hxs*Q[3]; h4 = h2*h2; R3 = Q[4]+hxs*Q[5]; r1 = R1 + h2*R2 + h4*R3; #endif t = 3.0-r1*hfx; e = hxs*((r1-t)/(6.0 - x*t)); if(k==0) return x - (x*e-hxs); /* c is 0 */ else { e = (x*(e-c)-c); e -= hxs; if(k== -1) return 0.5*(x-e)-0.5; if(k==1) { if(x < -0.25) return -2.0*(e-(x+0.5)); else return one+2.0*(x-e); } if (k <= -2 || k>56) { /* suffice to return exp(x)-1 */ u_int32_t high; y = one-(e-x); GET_HIGH_WORD(high,y); SET_HIGH_WORD(y,high+(k<<20)); /* add k to y's exponent */ return y-one; } t = one; if(k<20) { u_int32_t high; SET_HIGH_WORD(t,0x3ff00000 - (0x200000>>k)); /* t=1-2^-k */ y = t-(e-x); GET_HIGH_WORD(high,y); SET_HIGH_WORD(y,high+(k<<20)); /* add k to y's exponent */ } else { u_int32_t high; SET_HIGH_WORD(t,((0x3ff-k)<<20)); /* 2^-k */ y = x-(e+t); y += one; GET_HIGH_WORD(high,y); SET_HIGH_WORD(y,high+(k<<20)); /* add k to y's exponent */ } } return y; } //double log1p(double x) { // double result; // MathLibLog1P(MathLibRef, x, &result); // return result; //} /*---------------------------------------------------------------------------*/ /* @(#)s_log1p.c 5.1 93/09/24 */ /* * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * * Developed at SunPro, a Sun Microsystems, Inc. business. * Permission to use, copy, modify, and distribute this * software is freely granted, provided that this notice * is preserved. * ==================================================== */ /* Modified by Naohiko Shimizu/Tokai University, Japan 1997/08/25, for performance improvement on pipelined processors. */ /* double log1p(double x) * * Method : * 1. Argument Reduction: find k and f such that * 1+x = 2^k * (1+f), * where sqrt(2)/2 < 1+f < sqrt(2) . * * Note. If k=0, then f=x is exact. However, if k!=0, then f * may not be representable exactly. In that case, a correction * term is need. Let u=1+x rounded. Let c = (1+x)-u, then * log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u), * and add back the correction term c/u. * (Note: when x > 2**53, one can simply return log(x)) * * 2. Approximation of log1p(f). * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) * = 2s + 2/3 s**3 + 2/5 s**5 + ....., * = 2s + s*R * We use a special Reme algorithm on [0,0.1716] to generate * a polynomial of degree 14 to approximate R The maximum error * of this polynomial approximation is bounded by 2**-58.45. In * other words, * 2 4 6 8 10 12 14 * R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s +Lp6*s +Lp7*s * (the values of Lp1 to Lp7 are listed in the program) * and * | 2 14 | -58.45 * | Lp1*s +...+Lp7*s - R(z) | <= 2 * | | * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. * In order to guarantee error in log below 1ulp, we compute log * by * log1p(f) = f - (hfsq - s*(hfsq+R)). * * 3. Finally, log1p(x) = k*ln2 + log1p(f). * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) * Here ln2 is split into two floating point number: * ln2_hi + ln2_lo, * where n*ln2_hi is always exact for |n| < 2000. * * Special cases: * log1p(x) is NaN with signal if x < -1 (including -INF) ; * log1p(+INF) is +INF; log1p(-1) is -INF with signal; * log1p(NaN) is that NaN with no signal. * * Accuracy: * according to an error analysis, the error is always less than * 1 ulp (unit in the last place). * * Constants: * The hexadecimal values are the intended ones for the following * constants. The decimal values may be used, provided that the * compiler will convert from decimal to binary accurately enough * to produce the hexadecimal values shown. * * Note: Assuming log() return accurate answer, the following * algorithm can be used to compute log1p(x) to within a few ULP: * * u = 1+x; * if(u==1.0) return x ; else * return log(u)*(x/(u-1.0)); * * See HP-15C Advanced Functions Handbook, p.193. */ static double //ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */ //ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */ two54 = 1.80143985094819840000e+16, /* 43500000 00000000 */ Lp[] = {0.0, 6.666666666666735130e-01, /* 3FE55555 55555593 */ 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ 2.857142874366239149e-01, /* 3FD24924 94229359 */ 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ 1.479819860511658591e-01}; /* 3FC2F112 DF3E5244 */ static double zero = 0.0; double log1p(double x) { double hfsq,f,c,s,z,R,u,z2,z4,z6,R1,R2,R3,R4; int32_t k,hx,hu,ax; GET_HIGH_WORD(hx,x); ax = hx&0x7fffffff; k = 1; if (hx < 0x3FDA827A) { /* x < 0.41422 */ if(ax>=0x3ff00000) { /* x <= -1.0 */ if(x==-1.0) return -two54/(x-x);/* log1p(-1)=+inf */ else return (x-x)/(x-x); /* log1p(x<-1)=NaN */ } if(ax<0x3e200000) { /* |x| < 2**-29 */ if(two54+x>zero /* raise inexact */ &&ax<0x3c900000) /* |x| < 2**-54 */ return x; else return x - x*x*0.5; } if(hx>0||hx<=((int32_t)0xbfd2bec3)) { k=0;f=x;hu=1;} /* -0.2929<x<0.41422 */ } if (hx >= 0x7ff00000) return x+x; if(k!=0) { if(hx<0x43400000) { u = 1.0+x; GET_HIGH_WORD(hu,u); k = (hu>>20)-1023; c = (k>0)? 1.0-(u-x):x-(u-1.0);/* correction term */ c /= u; } else { u = x; GET_HIGH_WORD(hu,u); k = (hu>>20)-1023; c = 0; } hu &= 0x000fffff; if(hu<0x6a09e) { SET_HIGH_WORD(u,hu|0x3ff00000); /* normalize u */ } else { k += 1; SET_HIGH_WORD(u,hu|0x3fe00000); /* normalize u/2 */ hu = (0x00100000-hu)>>2; } f = u-1.0; } hfsq=0.5*f*f; if(hu==0) { /* |f| < 2**-20 */ if(f==zero) { if(k==0) return zero; else {c += k*ln2_lo; return k*ln2_hi+c;} } R = hfsq*(1.0-0.66666666666666666*f); if(k==0) return f-R; else return k*ln2_hi-((R-(k*ln2_lo+c))-f); } s = f/(2.0+f); z = s*s; #ifdef DO_NOT_USE_THIS R = z*(Lp1+z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7)))))); #else R1 = z*Lp[1]; z2=z*z; R2 = Lp[2]+z*Lp[3]; z4=z2*z2; R3 = Lp[4]+z*Lp[5]; z6=z4*z2; R4 = Lp[6]+z*Lp[7]; R = R1 + z2*R2 + z4*R3 + z6*R4; #endif if(k==0) return f-(hfsq-s*(hfsq+R)); else return k*ln2_hi-((hfsq-(s*(hfsq+R)+(k*ln2_lo+c)))-f); } //double logb(double x) { // double result; // MathLibLogB(MathLibRef, x, &result); // return result; //} //double log2(double x) { // double result; // MathLibLog2(MathLibRef, x, &result); // return result; //} double log2(double x) { //log2(x) = ln(x)/ln(2) //for x > 0 //Note: log2(1) = 0, log2(0) = -infinity, log2(+infinity) = +infinity double result = 0.0; if (x < 0.0) result = NaN; else if (x == 0.0) result = -1.0 / x; else if (isinf(x)) result = x; else result = log(x) / log(2.0); return (result); } //double pow(double x, double y) { // double result; // MathLibPow(MathLibRef, x, y, &result); // return result; //} //double sqrt(double x) { // double result; // MathLibSqrt(MathLibRef, x, &result); // return result; //} //double hypot(double x, double y) { // double result; // MathLibHypot(MathLibRef, x, y, &result); // return result; //} //double cbrt(double x) { // double result; // MathLibCbrt(MathLibRef, x, &result); // return result; //} double cbrt(double x) { //cbrt(x) = x**(1/3) = exp(ln(x)/3) double result; if (_isnan(x) || (x == 0.0) || (x == 1.0) || (x == -1.0) || isinf(x)) result = x; else result = pow(x, 1.0/3.0); // else if (x > 0.0) // result = exp(log(x)/3.0); // else result = - exp(log(-x)/3.0); return (result); } //double ceil(double x) { // double result; // MathLibCeil(MathLibRef, x, &result); // return result; //} //double fabs(double x) { // double result; // MathLibFAbs(MathLibRef, x, &result); // return result; //} //double floor(double x) { // double result; // MathLibFloor(MathLibRef, x, &result); // return result; //} //double fmod(double x, double y) { // double result; // MathLibFMod(MathLibRef, x, y, &result); // return result; //} //Int16 isinf(double x) { // Int16 result; // MathLibIsInf(MathLibRef, x, &result); // return result; //} int isinf(double x) { int rc = _fpclass(x); if ((rc & _FPCLASS_NINF) != 0) return (-1); else if ((rc & _FPCLASS_PINF) != 0) return (1); else return (0); } //Int16 finite(double x) { // Int16 result; // MathLibFinite(MathLibRef, x, &result); // return result; //} //double scalbn(double x, Int16 exponent) { // double result; // MathLibScalBN(MathLibRef, x, exponent, &result); // return result; //} //double drem(double x, double y) { // double result; // MathLibDRem(MathLibRef, x, y, &result); // return result; //} double drem(double x, double y) { // The function drem is like fmod and compute the remainder r = x - ny when y is nonzero // except that it rounds the internal quotient n to the nearest integer // instead of towards zero to an integer. // For example, drem (6.5, 2.3) returns -0.4, which is 6.5 minus 6.9. // The absolute value of the result is less than or equal to half the absolute value // of the denominator. The difference between fmod (numerator, denominator) // and drem (numerator, denominator) is always either denominator, minus denominator, // or zero. // If the absolute value |n-x/y| = 0.5, n is chosen to be even. // For example, drem (5.5, 2.2) returns 1.1, which is 5.5 minus 2 * 2.2 = 4.4, // and drem (7.7, 2.2) returns -1.1, which is 7.7 minus 4 * 2.2 = 8.8. // If denominator is zero, drem returns NaN, just like fmod. // If x or y is a NaN, a NaN is returned. // If x is an infinity, a NaN is returned. // If y is an infinity, x is returned. double result; if ((y == 0.0) || _isnan(x) || _isnan(y) || isinf(x)) result = NaN; else if (isinf(y)) result = x; else { // result = fmod(x, y); // double r1 = result - y; // Takes care of the positive case, with n+1 // double r2 = result + y; // Takes care of the negative case, with n-1 // double fr = fabs(result); // double fr1 = fabs(r1); // double fr2 = fabs(r2); // if (fr1 < fr) { // Keep the one with lowest absolute value // result = r1; // fr = fr1; // } else if (fr2 < fr) { // result = r2; // fr = fr2; // } else if (fr1 == fr) { // Equidistant // } else if (fr2 == fr) { // Equidistant // } double q = x / y; int n = (int) rint(q); result = x - (double) n * y; } return (result); } //double significand(double x) { // double result; // MathLibSignificand(MathLibRef, x, &result); // return result; //} double significand(double x) { //The Math.significand() function returns the mantissa of x scaled to the range [1,2]. //It is equivalent to scalb(x, (double) -ilogb(x)). //This function exists mainly for use in certain standardized tests for IEEE 754 conformance. //The function significand(x) isn't defined when x is one of: //* 0, //* positive or negative infinity, //* NAN. double result; if ((x == 0.0) || _isnan(x) || isinf(x)) result = NaN; else result = _scalb(x, (long) ilogb(x)); return result; } //double copysign(double x, double y) { // double result; // MathLibCopySign(MathLibRef, x, y, &result); // return result; //} //Int16 isnan(double x) { // Int16 result; // MathLibIsNaN(MathLibRef, x, &result); // return result; //} //Int16 ilogb(double x) { // Int16 result; // MathLibILogB(MathLibRef, x, &result); // return result; //} int ilogb(double x) { //The ilogb() function returns the exponent part of x. //Formally, the return value is the integral part of logr|x| as a signed integral value, //for non-zero x, where r is the radix of the machine's floating point arithmetic. //The call ilogb(x) is equivalent to (int)logb(x). //If x is 0, then ilogb() returns INT_MIN. //If x is NaN or ±Inf, then ilogb() returns INT_MAX. int result; if (_isnan(x) || isinf(x)) result = INT_MAX; else if (x == 0.0) result = INT_MIN; else result = (int) _logb(x); return result; } //double rint(double x) { // double result; // MathLibRInt16(MathLibRef, x, &result); // return result; //} double rint(double x) { //Round x to an integer value according to the current rounding mode. //The default rounding mode is to round to the nearest integer. //Some machines support other modes, but round-to-nearest is always used unless //you explicitly select another. //This implementation will use round-to-nearest. //Note: for halfway numbers, rint() is to pick the even closest integer. double result; if (_isnan(x) || isinf(x) || (x == 0.0)) result = x; else { double fract, n; int nn, nn1; fract = modf(x, &n); nn = (int) n; nn1 = nn >> 1; nn1 <<= 1; if (x > 0.0) { if (fract > 0.5) n += 1.0; else if (fract == 0.5) { if (nn != nn1) n += 1.0; } } else { if (fract < -0.5) n -= 1.0; else if (fract == -0.5) { if (nn != nn1) n -= 1.0; } } result = n; } return (result); } //double nextafter(double x, double y) { // double result; // MathLibNextAfter(MathLibRef, x, y, &result); // return result; //} //double remainder(double x, double y) { // double result; // MathLibRemainder(MathLibRef, x, y, &result); // return result; //} //double scalb(double x, double exponent) { // double result; // MathLibScalB(MathLibRef, x, exponent, &result); // return result; //} //double round(double x) { // double result; // MathLibRound(MathLibRef, x, &result); // return result;floor //} double round(double x) { double result; if (_isnan(x) || isinf(x)) result = NaN; else if (x == trunc(x)) result = x; else if (x < 0.0) result = trunc(x-0.5); else result = trunc(x+0.5); return (result); } //double trunc(double x) { // double result; // MathLibTrunc(MathLibRef, x, &result); // return result; //} double trunc(double x) { double result; if (_isnan(x) || isinf(x)) result = NaN; modf(x, &result); return (result); } //UInt32 signbit(double x) { // UInt32 result; // MathLibSignBit(MathLibRef, x, &result); // return result; //} |