2 * Copyright (c) 2007 Steven G. Kargl
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice unmodified, this list of conditions, and the following
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD: head/lib/msun/src/e_sqrtl.c 176720 2008-03-02 01:47:58Z das $");
31 __RCSID("$NetBSD: e_sqrtl.c,v 1.4 2013/11/22 20:15:06 martin Exp $");
33 #include <machine/ieee.h>
37 #include "math_private.h"
39 #ifdef __HAVE_LONG_DOUBLE
45 #ifdef LDBL_IMPLICIT_NBIT
51 /* Return (x + ulp) for normal positive x. Assumes no overflow. */
52 static inline long double
55 union ieee_ext_u ux
= { .extu_ld
= x
, };
57 if (++ux
.extu_fracl
== 0) {
58 if (++ux
.extu_frach
== 0) {
60 ux
.extu_frach
|= LDBL_NBIT
;
66 /* Return (x - ulp) for normal positive x. Assumes no underflow. */
67 static inline long double
70 union ieee_ext_u ux
= { .extu_ld
= x
, };
72 if (ux
.extu_fracl
-- == 0) {
73 if (ux
.extu_frach
-- == LDBL_NBIT
) {
75 ux
.extu_frach
|= LDBL_NBIT
;
82 * This is slow, but simple and portable. You should use hardware sqrt
87 __ieee754_sqrtl(long double x
)
89 union ieee_ext_u ux
= { .extu_ld
= x
, };
94 /* If x = NaN, then sqrt(x) = NaN. */
95 /* If x = Inf, then sqrt(x) = Inf. */
96 /* If x = -Inf, then sqrt(x) = NaN. */
97 if (ux
.extu_exp
== LDBL_MAX_EXP
* 2 - 1)
100 /* If x = +-0, then sqrt(x) = +-0. */
101 if ((ux
.extu_frach
| ux
.extu_fracl
| ux
.extu_exp
) == 0)
104 /* If x < 0, then raise invalid and return NaN */
106 return ((x
- x
) / (x
- x
));
110 if (ux
.extu_exp
== 0) {
111 /* Adjust subnormal numbers. */
112 ux
.extu_ld
*= 0x1.0p514
;
118 * ux.extu_ld is a normal number, so break it into ux.extu_ld = e*2^n where
119 * ux.extu_ld = (2*e)*2^2k for odd n and ux.extu_ld = (4*e)*2^2k for even n.
121 if ((ux
.extu_exp
- EXT_EXP_BIAS
) & 1) { /* n is even. */
122 k
+= ux
.extu_exp
- EXT_EXP_BIAS
- 1; /* 2k = n - 2. */
123 ux
.extu_exp
= EXT_EXP_BIAS
+ 1; /* ux.extu_ld in [2,4). */
125 k
+= ux
.extu_exp
- EXT_EXP_BIAS
; /* 2k = n - 1. */
126 ux
.extu_exp
= EXT_EXP_BIAS
; /* ux.extu_ld in [1,2). */
130 * Newton's iteration.
131 * Split ux.extu_ld into a high and low part to achieve additional precision.
133 xn
= sqrt(ux
.extu_ld
); /* 53-bit estimate of sqrtl(x). */
134 #if LDBL_MANT_DIG > 100
135 xn
= (xn
+ (ux
.extu_ld
/ xn
)) * 0.5; /* 106-bit estimate. */
138 ux
.extu_fracl
= 0; /* Zero out lower bits. */
139 lo
= (lo
- ux
.extu_ld
) / xn
; /* Low bits divided by xn. */
140 xn
= xn
+ (ux
.extu_ld
/ xn
); /* High portion of estimate. */
141 ux
.extu_ld
= xn
+ lo
; /* Combine everything. */
142 ux
.extu_exp
+= (k
>> 1) - 1;
144 feclearexcept(FE_INEXACT
);
146 fesetround(FE_TOWARDZERO
); /* Set to round-toward-zero. */
147 xn
= x
/ ux
.extu_ld
; /* Chopped quotient (inexact?). */
149 if (!fetestexcept(FE_INEXACT
)) { /* Quotient is exact. */
150 if (xn
== ux
.extu_ld
) {
154 /* Round correctly for inputs like x = y**2 - ulp. */
155 xn
= dec(xn
); /* xn = xn - ulp. */
158 if (r
== FE_TONEAREST
) {
159 xn
= inc(xn
); /* xn = xn + ulp. */
160 } else if (r
== FE_UPWARD
) {
161 ux
.extu_ld
= inc(ux
.extu_ld
); /* ux.extu_ld = ux.extu_ld + ulp. */
162 xn
= inc(xn
); /* xn = xn + ulp. */
164 ux
.extu_ld
= ux
.extu_ld
+ xn
; /* Chopped sum. */
165 feupdateenv(&env
); /* Restore env and raise inexact */
174 * poor man's version: just use double
177 __ieee754_sqrtl(long double x
)
179 return __ieee754_sqrt((double)x
);