You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
219 lines
5.6 KiB
219 lines
5.6 KiB
/***
|
|
*sincosh.c - hyperbolic sine and cosine
|
|
*
|
|
* Copyright (c) 1991-2001, Microsoft Corporation. All rights reserved.
|
|
*
|
|
*Purpose:
|
|
*
|
|
*Revision History:
|
|
* 8-15-91 GDP written
|
|
* 12-20-91 GDP support IEEE exceptions
|
|
* 02-03-92 GDP use _exphlp for computing e^x
|
|
* 06-23-92 GDP sinh(denormal) now raises underflow exception (NCEG)
|
|
* 07-16-93 SRW ALPHA Merge
|
|
* 11-18-93 GJF Merged in NT SDK version.
|
|
* 02-06-95 JWM Mac merge
|
|
* 05-17-99 PML Remove all Macintosh support.
|
|
* 07-15-01 PML Remove all ALPHA, MIPS, and PPC code
|
|
*
|
|
*******************************************************************************/
|
|
|
|
#include <math.h>
|
|
#include <trans.h>
|
|
|
|
extern double _exphlp(double, int *);
|
|
|
|
static double const EPS = 5.16987882845642297e-26; /* 2^(-53) / 2 */
|
|
/* exp(YBAR) should be close to but less than XMAX
|
|
* and 1/exp(YBAR) should not underflow
|
|
*/
|
|
static double const YBAR = 7.00e2;
|
|
|
|
/* WMAX=ln(OVFX)+0.69 (Cody & Waite),ommited LNV, used OVFX instead of BIGX */
|
|
|
|
static double const WMAX = 1.77514678223345998953e+003;
|
|
|
|
/* constants for the rational approximation */
|
|
static double const p0 = -0.35181283430177117881e+6;
|
|
static double const p1 = -0.11563521196851768270e+5;
|
|
static double const p2 = -0.16375798202630751372e+3;
|
|
static double const p3 = -0.78966127417357099479e+0;
|
|
static double const q0 = -0.21108770058106271242e+7;
|
|
static double const q1 = 0.36162723109421836460e+5;
|
|
static double const q2 = -0.27773523119650701667e+3;
|
|
/* q3 = 1 is not used (avoid myltiplication by 1) */
|
|
|
|
#define P(f) (((p3 * (f) + p2) * (f) + p1) * (f) + p0)
|
|
#define Q(f) ((((f) + q2) * (f) + q1) * (f) + q0)
|
|
|
|
#if !defined(_M_AMD64)
|
|
#pragma function(sinh, cosh)
|
|
#endif
|
|
|
|
/***
|
|
*double sinh(double x) - hyperbolic sine
|
|
*
|
|
*Purpose:
|
|
* Compute the hyperbolic sine of a number.
|
|
* The algorithm (reduction / rational approximation) is
|
|
* taken from Cody & Waite.
|
|
*
|
|
*Entry:
|
|
*
|
|
*Exit:
|
|
*
|
|
*Exceptions:
|
|
* I P
|
|
* no exception if x is denormal: return x
|
|
*******************************************************************************/
|
|
|
|
double sinh(double x)
|
|
{
|
|
uintptr_t savedcw;
|
|
double result;
|
|
double y,f,z,r;
|
|
int newexp;
|
|
int sgn;
|
|
|
|
/* save user fp control word */
|
|
savedcw = _maskfp();
|
|
|
|
if (IS_D_SPECIAL(x)){
|
|
switch(_sptype(x)) {
|
|
case T_PINF:
|
|
case T_NINF:
|
|
RETURN(savedcw,x);
|
|
case T_QNAN:
|
|
return _handle_qnan1(OP_SINH, x, savedcw);
|
|
default: //T_SNAN
|
|
return _except1(FP_I,OP_SINH,x,_s2qnan(x),savedcw);
|
|
}
|
|
}
|
|
|
|
if (x == 0.0) {
|
|
RETURN(savedcw,x); // no precision ecxeption
|
|
}
|
|
|
|
y = ABS(x);
|
|
sgn = x<0 ? -1 : +1;
|
|
|
|
if (y > 1.0) {
|
|
if (y > YBAR) {
|
|
if (y > WMAX) {
|
|
// result too large, even after scaling
|
|
return _except1(FP_O | FP_P,OP_SINH,x,x*D_INF,savedcw);
|
|
}
|
|
|
|
//
|
|
// result = exp(y)/2
|
|
//
|
|
|
|
result = _exphlp(y, &newexp);
|
|
newexp --; //divide by 2
|
|
if (newexp > MAXEXP) {
|
|
result = _set_exp(result, newexp-IEEE_ADJUST);
|
|
return _except1(FP_O|FP_P,OP_SINH,x,result,savedcw);
|
|
}
|
|
else {
|
|
result = _set_exp(result, newexp);
|
|
}
|
|
|
|
}
|
|
else {
|
|
z = _exphlp(y, &newexp);
|
|
z = _set_exp(z, newexp);
|
|
result = (z - 1/z) / 2;
|
|
}
|
|
|
|
if (sgn < 0) {
|
|
result = -result;
|
|
}
|
|
}
|
|
else {
|
|
if (y < EPS) {
|
|
result = x;
|
|
if (IS_D_DENORM(result)) {
|
|
return _except1(FP_U | FP_P,OP_SINH,x,_add_exp(result, IEEE_ADJUST),savedcw);
|
|
}
|
|
}
|
|
else {
|
|
f = x * x;
|
|
r = f * (P(f) / Q(f));
|
|
result = x + x * r;
|
|
}
|
|
}
|
|
|
|
RETURN_INEXACT1(OP_SINH,x,result,savedcw);
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
*double cosh(double x) - hyperbolic cosine
|
|
*
|
|
*Purpose:
|
|
* Compute the hyperbolic cosine of a number.
|
|
* The algorithm (reduction / rational approximation) is
|
|
* taken from Cody & Waite.
|
|
*
|
|
*Entry:
|
|
*
|
|
*Exit:
|
|
*
|
|
*Exceptions:
|
|
* I P
|
|
* no exception if x is denormal: return 1
|
|
*******************************************************************************/
|
|
double cosh(double x)
|
|
{
|
|
uintptr_t savedcw;
|
|
double y,z,result;
|
|
int newexp;
|
|
|
|
/* save user fp control word */
|
|
savedcw = _maskfp();
|
|
|
|
if (IS_D_SPECIAL(x)){
|
|
switch(_sptype(x)) {
|
|
case T_PINF:
|
|
case T_NINF:
|
|
RETURN(savedcw,D_INF);
|
|
case T_QNAN:
|
|
return _handle_qnan1(OP_COSH, x, savedcw);
|
|
default: //T_SNAN
|
|
return _except1(FP_I,OP_COSH,x,_s2qnan(x),savedcw);
|
|
}
|
|
}
|
|
|
|
if (x == 0.0) {
|
|
RETURN(savedcw,1.0);
|
|
}
|
|
|
|
y = ABS(x);
|
|
if (y > YBAR) {
|
|
if (y > WMAX) {
|
|
return _except1(FP_O | FP_P,OP_COSH,x,D_INF,savedcw);
|
|
}
|
|
|
|
//
|
|
// result = exp(y)/2
|
|
//
|
|
|
|
result = _exphlp(y, &newexp);
|
|
newexp --; //divide by 2
|
|
if (newexp > MAXEXP) {
|
|
result = _set_exp(result, newexp-IEEE_ADJUST);
|
|
return _except1(FP_O|FP_P,OP_COSH,x,result,savedcw);
|
|
}
|
|
else {
|
|
result = _set_exp(result, newexp);
|
|
}
|
|
}
|
|
else {
|
|
z = _exphlp(y, &newexp);
|
|
z = _set_exp(z, newexp);
|
|
result = (z + 1/z) / 2;
|
|
}
|
|
|
|
RETURN_INEXACT1(OP_COSH,x,result,savedcw);
|
|
}
|