summaryrefslogtreecommitdiffstats
path: root/private/fp32/tran/mips/sqrt4000.c
blob: 67e68adc2fb188092521a4df49aa60fbd5394011 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/***
*sqrt4000.c - square root for the R4000
*
*	Copyright (c) 1991-1991, Microsoft Corporation.	All rights reserved.
*
*Purpose:
*
*Revision History:
*   3-31-92	GDP	written
*******************************************************************************/
#ifdef R4000

#include <math.h>
#include <trans.h>

static double scale = 4503599627370496.0;  // 2^52
static double lgscale = 26;		   // log2(2^52) / 2

#define SWMASK	     0x78
#define INEXACT_MASK 0x4


/***
*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)
{
    unsigned int savedcw,cw,sw;
    double result,savedx;
    int scaled = 0;

    // mask exceptions, keep user's rounding mode
    savedcw = _ctrlfp(ICW, IMCW & ~IMCW_RC);

    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);
    }

    savedx = x;

    if (IS_D_DENORM(x)) {
	x *= scale;
	scaled = 1;
    }

    sw = _clrfp();
    result = _fsqrt(x);
    cw = _get_fsr();

    _set_fsr(cw & ~SWMASK | sw & SWMASK); // restore all but inexact

    if (scaled) {
	result = _add_exp(result, -lgscale);
    }

    if ((cw & INEXACT_MASK) == INEXACT_MASK) {
	return _except1(FP_P,OP_SQRT,savedx,result,savedcw);
    }

    RETURN(savedcw,result);
}

#endif