summaryrefslogtreecommitdiff
path: root/lib/libm/csqrt.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libm/csqrt.c')
-rw-r--r--lib/libm/csqrt.c60
1 files changed, 60 insertions, 0 deletions
diff --git a/lib/libm/csqrt.c b/lib/libm/csqrt.c
new file mode 100644
index 00000000..e98cb7c6
--- /dev/null
+++ b/lib/libm/csqrt.c
@@ -0,0 +1,60 @@
+#include "__complex.h"
+
+double complex csqrt(double complex z)
+{
+ double complex w;
+ double x, y, r, t, scale;
+
+ x = creal(z);
+ y = cimag(z);
+ if (y == 0.0) {
+ if (x == 0.0) {
+ return 0.0 + y * (double complex)I;
+ } else {
+ r = fabs(x);
+ r = sqrt(r);
+ if (x < 0.0) {
+ return 0.0 + r * (double complex)I;
+ } else {
+ return r + y * (double complex)I;
+ }
+ }
+ }
+
+ if (x == 0.0) {
+ r = fabs(y);
+ r = sqrt(0.5 * r);
+
+ if (y > 0)
+ return r + r * (double complex)I;
+ else
+ return r - r * (double complex)I;
+ }
+
+ if ((fabs(x) > 4.0) || (fabs(y) > 4.0)) {
+ x *= 0.25;
+ y *= 0.25;
+ scale = 2.0;
+ } else {
+ x *= 1.8014398509481984e16; /* 2^54 */
+ y *= 1.8014398509481984e16;
+ scale = 7.450580596923828125e-9; /* 2^-27 */
+ }
+
+ w = x + y * (double complex)I;
+ r = cabs(w);
+ if (x > 0) {
+ t = sqrt(0.5 * r + 0.5 * x);
+ r = scale * fabs((0.5 * y) / t);
+ t *= scale;
+ } else {
+ r = sqrt(0.5 * r - 0.5 * x);
+ t = scale * fabs((0.5 * y) / r);
+ r *= scale;
+ }
+
+ if (y < 0)
+ return t - r * (double complex)I;
+ else
+ return t + r * (double complex)I;
+}