1*05a0b428SJohn Marino /* $OpenBSD: s_csqrtl.c,v 1.2 2011/07/20 19:28:33 martynas Exp $ */ 2*05a0b428SJohn Marino 3*05a0b428SJohn Marino /* 4*05a0b428SJohn Marino * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net> 5*05a0b428SJohn Marino * 6*05a0b428SJohn Marino * Permission to use, copy, modify, and distribute this software for any 7*05a0b428SJohn Marino * purpose with or without fee is hereby granted, provided that the above 8*05a0b428SJohn Marino * copyright notice and this permission notice appear in all copies. 9*05a0b428SJohn Marino * 10*05a0b428SJohn Marino * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11*05a0b428SJohn Marino * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*05a0b428SJohn Marino * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13*05a0b428SJohn Marino * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14*05a0b428SJohn Marino * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15*05a0b428SJohn Marino * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16*05a0b428SJohn Marino * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17*05a0b428SJohn Marino */ 18*05a0b428SJohn Marino 19*05a0b428SJohn Marino /* csqrtl() 20*05a0b428SJohn Marino * 21*05a0b428SJohn Marino * Complex square root 22*05a0b428SJohn Marino * 23*05a0b428SJohn Marino * 24*05a0b428SJohn Marino * 25*05a0b428SJohn Marino * SYNOPSIS: 26*05a0b428SJohn Marino * 27*05a0b428SJohn Marino * long double complex csqrtl(); 28*05a0b428SJohn Marino * long double complex z, w; 29*05a0b428SJohn Marino * 30*05a0b428SJohn Marino * w = csqrtl( z ); 31*05a0b428SJohn Marino * 32*05a0b428SJohn Marino * 33*05a0b428SJohn Marino * 34*05a0b428SJohn Marino * DESCRIPTION: 35*05a0b428SJohn Marino * 36*05a0b428SJohn Marino * 37*05a0b428SJohn Marino * If z = x + iy, r = |z|, then 38*05a0b428SJohn Marino * 39*05a0b428SJohn Marino * 1/2 40*05a0b428SJohn Marino * Re w = [ (r + x)/2 ] , 41*05a0b428SJohn Marino * 42*05a0b428SJohn Marino * 1/2 43*05a0b428SJohn Marino * Im w = [ (r - x)/2 ] . 44*05a0b428SJohn Marino * 45*05a0b428SJohn Marino * Cancellation error in r-x or r+x is avoided by using the 46*05a0b428SJohn Marino * identity 2 Re w Im w = y. 47*05a0b428SJohn Marino * 48*05a0b428SJohn Marino * Note that -w is also a square root of z. The root chosen 49*05a0b428SJohn Marino * is always in the right half plane and Im w has the same sign as y. 50*05a0b428SJohn Marino * 51*05a0b428SJohn Marino * 52*05a0b428SJohn Marino * 53*05a0b428SJohn Marino * ACCURACY: 54*05a0b428SJohn Marino * 55*05a0b428SJohn Marino * Relative error: 56*05a0b428SJohn Marino * arithmetic domain # trials peak rms 57*05a0b428SJohn Marino * IEEE -10,+10 500000 1.1e-19 3.0e-20 58*05a0b428SJohn Marino * 59*05a0b428SJohn Marino */ 60*05a0b428SJohn Marino 61*05a0b428SJohn Marino #include <complex.h> 62*05a0b428SJohn Marino #include <math.h> 63*05a0b428SJohn Marino 64*05a0b428SJohn Marino long double complex 65*05a0b428SJohn Marino csqrtl(long double complex z) 66*05a0b428SJohn Marino { 67*05a0b428SJohn Marino long double complex w; 68*05a0b428SJohn Marino long double x, y, r, t, scale; 69*05a0b428SJohn Marino 70*05a0b428SJohn Marino x = creall(z); 71*05a0b428SJohn Marino y = cimagl(z); 72*05a0b428SJohn Marino 73*05a0b428SJohn Marino if (y == 0.0L) { 74*05a0b428SJohn Marino if (x < 0.0L) { 75*05a0b428SJohn Marino w = 0.0L + sqrtl(-x) * I; 76*05a0b428SJohn Marino return (w); 77*05a0b428SJohn Marino } 78*05a0b428SJohn Marino else { 79*05a0b428SJohn Marino w = sqrtl(x) + 0.0L * I; 80*05a0b428SJohn Marino return (w); 81*05a0b428SJohn Marino } 82*05a0b428SJohn Marino } 83*05a0b428SJohn Marino 84*05a0b428SJohn Marino if (x == 0.0L) { 85*05a0b428SJohn Marino r = fabsl(y); 86*05a0b428SJohn Marino r = sqrtl(0.5L * r); 87*05a0b428SJohn Marino if (y > 0.0L) 88*05a0b428SJohn Marino w = r + r * I; 89*05a0b428SJohn Marino else 90*05a0b428SJohn Marino w = r - r * I; 91*05a0b428SJohn Marino return (w); 92*05a0b428SJohn Marino } 93*05a0b428SJohn Marino 94*05a0b428SJohn Marino /* Rescale to avoid internal overflow or underflow. */ 95*05a0b428SJohn Marino if ((fabsl(x) > 4.0L) || (fabsl(y) > 4.0L)) { 96*05a0b428SJohn Marino x *= 0.25L; 97*05a0b428SJohn Marino y *= 0.25L; 98*05a0b428SJohn Marino scale = 2.0L; 99*05a0b428SJohn Marino } 100*05a0b428SJohn Marino else { 101*05a0b428SJohn Marino #if 1 102*05a0b428SJohn Marino x *= 7.3786976294838206464e19; /* 2^66 */ 103*05a0b428SJohn Marino y *= 7.3786976294838206464e19; 104*05a0b428SJohn Marino scale = 1.16415321826934814453125e-10; /* 2^-33 */ 105*05a0b428SJohn Marino #else 106*05a0b428SJohn Marino x *= 4.0L; 107*05a0b428SJohn Marino y *= 4.0L; 108*05a0b428SJohn Marino scale = 0.5L; 109*05a0b428SJohn Marino #endif 110*05a0b428SJohn Marino } 111*05a0b428SJohn Marino w = x + y * I; 112*05a0b428SJohn Marino r = cabsl(w); 113*05a0b428SJohn Marino if (x > 0) { 114*05a0b428SJohn Marino t = sqrtl(0.5L * r + 0.5L * x); 115*05a0b428SJohn Marino r = scale * fabsl((0.5L * y) / t); 116*05a0b428SJohn Marino t *= scale; 117*05a0b428SJohn Marino } 118*05a0b428SJohn Marino else { 119*05a0b428SJohn Marino r = sqrtl(0.5L * r - 0.5L * x); 120*05a0b428SJohn Marino t = scale * fabsl((0.5L * y) / r); 121*05a0b428SJohn Marino r *= scale; 122*05a0b428SJohn Marino } 123*05a0b428SJohn Marino if (y < 0) 124*05a0b428SJohn Marino w = t - r * I; 125*05a0b428SJohn Marino else 126*05a0b428SJohn Marino w = t + r * I; 127*05a0b428SJohn Marino return (w); 128*05a0b428SJohn Marino } 129