summaryrefslogtreecommitdiff
path: root/lib/libm/csqrtf.c
blob: 79d03f4d4167d4343bd702dabf21fd9f2e18665f (plain)
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
#include <complex.h> // for I, complex, cabsf, cimagf, crealf, csqrtf
#include <math.h>    // for fabsf, sqrtf

float complex csqrtf(float complex z)
{
	float complex w;
	float x, y, r, t, scale;

	x = crealf(z);
	y = cimagf(z);
	if (y == 0.0f) {
		if (x < 0.0f) {
			return 0.0f + sqrtf(-x) * I;
		}
		if (x == 0.0f) {
			return (0.0f + y * I);
		}
		return sqrtf(x) + y * I;
	}

	if (x == 0.0f) {
		r = fabsf(y);
		r = sqrtf(0.5f * r);
		if (y > 0)
			return r + r * I;
		return r - r * I;
	}

	if ((fabsf(x) > 4.0f) || (fabsf(y) > 4.0f)) {
		x *= 0.25f;
		y *= 0.25f;
		scale = 2.0f;
	} else {
		x *= 6.7108864e7f; /* 2^26 */
		y *= 6.7108864e7f;
		scale = 1.220703125e-4f; /* 2^-13 */
	}

	w = x + y * I;
	r = cabsf(w);
	if (x > 0) {
		t = sqrtf(0.5f * r + 0.5f * x);
		r = scale * fabsf((0.5f * y) / t);
		t *= scale;
	} else {
		r = sqrtf(0.5f * r - 0.5f * x);
		t = scale * fabsf((0.5f * y) / r);
		r *= scale;
	}

	if (y < 0)
		return t - r * I;
	return t + r * I;
}