182 lines
3.4 KiB
C
182 lines
3.4 KiB
C
/***
|
|
*sqrt.c - square root
|
|
*
|
|
* Copyright (c) 1991-2001, Microsoft Corporation. All rights reserved.
|
|
*
|
|
*Purpose:
|
|
*
|
|
*Revision History:
|
|
* 8-15-91 GDP written
|
|
* 1-29-91 GDP Kahan's algorithm for final rounding
|
|
* 3-11-92 GDP new interval and initial approximation
|
|
* 10-07-97 RDL Added IA64.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
#ifndef R4000
|
|
|
|
#include <math.h>
|
|
#include <trans.h>
|
|
|
|
#if defined(_M_IA64)
|
|
#pragma function(sqrt)
|
|
#endif
|
|
|
|
//
|
|
// Coefficients for initial approximation (Hart & al)
|
|
//
|
|
|
|
static double p00 = .2592768763e+0;
|
|
static double p01 = .1052021187e+1;
|
|
static double p02 = -.3163221431e+0;
|
|
|
|
|
|
/***
|
|
*double sqrt(double x) - square root
|
|
*
|
|
*Purpose:
|
|
* Compute the square root of a number.
|
|
* This function should be provided by the underlying
|
|
* hardware (IEEE spec).
|
|
*Entry:
|
|
*
|
|
*Exit:
|
|
*
|
|
*Exceptions:
|
|
* I P
|
|
*******************************************************************************/
|
|
double sqrt(double x)
|
|
{
|
|
uintptr_t savedcw, sw;
|
|
double result,t;
|
|
uintptr_t stat,rc;
|
|
|
|
savedcw = _ctrlfp(ICW, IMCW);
|
|
|
|
if (IS_D_SPECIAL(x)){
|
|
switch (_sptype(x)) {
|
|
case T_PINF:
|
|
RETURN(savedcw, x);
|
|
case T_QNAN:
|
|
return _handle_qnan1(OP_SQRT, x, savedcw);
|
|
case T_SNAN:
|
|
return _except1(FP_I,OP_SQRT,x,QNAN_SQRT,savedcw);
|
|
}
|
|
/* -INF will be handled in the x<0 case */
|
|
}
|
|
if (x < 0.0) {
|
|
return _except1(FP_I, OP_SQRT, x, QNAN_SQRT,savedcw);
|
|
}
|
|
|
|
if (x == 0.0) {
|
|
RETURN (savedcw, x);
|
|
}
|
|
|
|
|
|
result = _fsqrt(x);
|
|
|
|
_ctrlfp(IRC_DOWN, IMCW_RC);
|
|
|
|
|
|
//
|
|
// Kahan's algorithm
|
|
//
|
|
|
|
sw = _clrfp();
|
|
t = x / result;
|
|
stat = _statfp();
|
|
if (! (stat & ISW_INEXACT)) {
|
|
// exact
|
|
if (t == result) {
|
|
_set_statfp(sw); // restore status word
|
|
RETURN(savedcw, result);
|
|
}
|
|
else {
|
|
// t = t-1
|
|
if (*D_LO(t) == 0) {
|
|
(*D_HI(t)) --;
|
|
}
|
|
(*D_LO(t)) --;
|
|
}
|
|
|
|
}
|
|
|
|
rc = savedcw & IMCW_RC;
|
|
if (rc == IRC_UP || rc == IRC_NEAR) {
|
|
// t = t+1
|
|
(*D_LO(t)) ++;
|
|
if (*D_LO(t) == 0) {
|
|
(*D_HI(t)) ++;
|
|
}
|
|
if (rc == IRC_UP) {
|
|
// y = y+1
|
|
(*D_LO(t)) ++;
|
|
if (*D_LO(t) == 0) {
|
|
(*D_HI(t)) ++;
|
|
}
|
|
}
|
|
}
|
|
|
|
result = 0.5 * (t + result);
|
|
|
|
_set_statfp(sw | ISW_INEXACT); // update status word
|
|
RETURN_INEXACT1(OP_SQRT, x, result, savedcw);
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
* _fsqrt - non IEEE conforming square root
|
|
*
|
|
*Purpose:
|
|
* compute a square root of a normal number without performing
|
|
* IEEE rounding. The argument is a finite number (no NaN or INF)
|
|
*
|
|
*Entry:
|
|
*
|
|
*Exit:
|
|
*
|
|
*Exceptions:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
double _fsqrt(double x)
|
|
{
|
|
double f,y,result;
|
|
int n;
|
|
|
|
f = _decomp(x,&n);
|
|
|
|
if (n & 0x1) {
|
|
// n is odd
|
|
n++;
|
|
f = _add_exp(f, -1);
|
|
}
|
|
|
|
//
|
|
// approximation for sqrt in the interval [.25, 1]
|
|
// (Computer Approximationsn, Hart & al.)
|
|
// gives more than 7 bits of accuracy
|
|
//
|
|
|
|
y = p00 + f * (p01 + f * p02);
|
|
|
|
y += f / y;
|
|
y = _add_exp(y, -1);
|
|
|
|
y += f / y;
|
|
y = _add_exp(y, -1);
|
|
|
|
y += f / y;
|
|
y = _add_exp(y, -1);
|
|
|
|
n >>= 1;
|
|
result = _add_exp(y,n);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
#endif
|