xref: /aosp_15_r20/external/musl/src/math/atanh.c (revision c9945492fdd68bbe62686c5b452b4dc1be3f8453)
1*c9945492SAndroid Build Coastguard Worker #include "libm.h"
2*c9945492SAndroid Build Coastguard Worker 
3*c9945492SAndroid Build Coastguard Worker /* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */
atanh(double x)4*c9945492SAndroid Build Coastguard Worker double atanh(double x)
5*c9945492SAndroid Build Coastguard Worker {
6*c9945492SAndroid Build Coastguard Worker 	union {double f; uint64_t i;} u = {.f = x};
7*c9945492SAndroid Build Coastguard Worker 	unsigned e = u.i >> 52 & 0x7ff;
8*c9945492SAndroid Build Coastguard Worker 	unsigned s = u.i >> 63;
9*c9945492SAndroid Build Coastguard Worker 	double_t y;
10*c9945492SAndroid Build Coastguard Worker 
11*c9945492SAndroid Build Coastguard Worker 	/* |x| */
12*c9945492SAndroid Build Coastguard Worker 	u.i &= (uint64_t)-1/2;
13*c9945492SAndroid Build Coastguard Worker 	y = u.f;
14*c9945492SAndroid Build Coastguard Worker 
15*c9945492SAndroid Build Coastguard Worker 	if (e < 0x3ff - 1) {
16*c9945492SAndroid Build Coastguard Worker 		if (e < 0x3ff - 32) {
17*c9945492SAndroid Build Coastguard Worker 			/* handle underflow */
18*c9945492SAndroid Build Coastguard Worker 			if (e == 0)
19*c9945492SAndroid Build Coastguard Worker 				FORCE_EVAL((float)y);
20*c9945492SAndroid Build Coastguard Worker 		} else {
21*c9945492SAndroid Build Coastguard Worker 			/* |x| < 0.5, up to 1.7ulp error */
22*c9945492SAndroid Build Coastguard Worker 			y = 0.5*log1p(2*y + 2*y*y/(1-y));
23*c9945492SAndroid Build Coastguard Worker 		}
24*c9945492SAndroid Build Coastguard Worker 	} else {
25*c9945492SAndroid Build Coastguard Worker 		/* avoid overflow */
26*c9945492SAndroid Build Coastguard Worker 		y = 0.5*log1p(2*(y/(1-y)));
27*c9945492SAndroid Build Coastguard Worker 	}
28*c9945492SAndroid Build Coastguard Worker 	return s ? -y : y;
29*c9945492SAndroid Build Coastguard Worker }
30