xref: /aosp_15_r20/external/musl/src/math/atanhf.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) */
atanhf(float x)4*c9945492SAndroid Build Coastguard Worker float atanhf(float x)
5*c9945492SAndroid Build Coastguard Worker {
6*c9945492SAndroid Build Coastguard Worker 	union {float f; uint32_t i;} u = {.f = x};
7*c9945492SAndroid Build Coastguard Worker 	unsigned s = u.i >> 31;
8*c9945492SAndroid Build Coastguard Worker 	float_t y;
9*c9945492SAndroid Build Coastguard Worker 
10*c9945492SAndroid Build Coastguard Worker 	/* |x| */
11*c9945492SAndroid Build Coastguard Worker 	u.i &= 0x7fffffff;
12*c9945492SAndroid Build Coastguard Worker 	y = u.f;
13*c9945492SAndroid Build Coastguard Worker 
14*c9945492SAndroid Build Coastguard Worker 	if (u.i < 0x3f800000 - (1<<23)) {
15*c9945492SAndroid Build Coastguard Worker 		if (u.i < 0x3f800000 - (32<<23)) {
16*c9945492SAndroid Build Coastguard Worker 			/* handle underflow */
17*c9945492SAndroid Build Coastguard Worker 			if (u.i < (1<<23))
18*c9945492SAndroid Build Coastguard Worker 				FORCE_EVAL((float)(y*y));
19*c9945492SAndroid Build Coastguard Worker 		} else {
20*c9945492SAndroid Build Coastguard Worker 			/* |x| < 0.5, up to 1.7ulp error */
21*c9945492SAndroid Build Coastguard Worker 			y = 0.5f*log1pf(2*y + 2*y*y/(1-y));
22*c9945492SAndroid Build Coastguard Worker 		}
23*c9945492SAndroid Build Coastguard Worker 	} else {
24*c9945492SAndroid Build Coastguard Worker 		/* avoid overflow */
25*c9945492SAndroid Build Coastguard Worker 		y = 0.5f*log1pf(2*(y/(1-y)));
26*c9945492SAndroid Build Coastguard Worker 	}
27*c9945492SAndroid Build Coastguard Worker 	return s ? -y : y;
28*c9945492SAndroid Build Coastguard Worker }
29