1d23166b0SDavid Schultz /* From: @(#)e_hypot.c 1.3 95/01/18 */ 2d23166b0SDavid Schultz /* 3d23166b0SDavid Schultz * ==================================================== 4d23166b0SDavid Schultz * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. 5d23166b0SDavid Schultz * 6d23166b0SDavid Schultz * Developed at SunSoft, a Sun Microsystems, Inc. business. 7d23166b0SDavid Schultz * Permission to use, copy, modify, and distribute this 8d23166b0SDavid Schultz * software is freely granted, provided that this notice 9d23166b0SDavid Schultz * is preserved. 10d23166b0SDavid Schultz * ==================================================== 11d23166b0SDavid Schultz */ 12d23166b0SDavid Schultz 13d23166b0SDavid Schultz #include <sys/cdefs.h> 14d23166b0SDavid Schultz __FBSDID("$FreeBSD$"); 15d23166b0SDavid Schultz 16d23166b0SDavid Schultz /* long double version of hypot(). See e_hypot.c for most comments. */ 17d23166b0SDavid Schultz 18d23166b0SDavid Schultz #include <float.h> 19d23166b0SDavid Schultz 20d23166b0SDavid Schultz #include "fpmath.h" 21d23166b0SDavid Schultz #include "math.h" 22d23166b0SDavid Schultz #include "math_private.h" 23d23166b0SDavid Schultz 24d23166b0SDavid Schultz #define GET_LDBL_EXPSIGN(i, v) do { \ 25d23166b0SDavid Schultz union IEEEl2bits uv; \ 26d23166b0SDavid Schultz \ 27d23166b0SDavid Schultz uv.e = v; \ 28d23166b0SDavid Schultz i = uv.xbits.expsign; \ 29d23166b0SDavid Schultz } while (0) 30d23166b0SDavid Schultz 31d23166b0SDavid Schultz #define GET_LDBL_MAN(h, l, v) do { \ 32d23166b0SDavid Schultz union IEEEl2bits uv; \ 33d23166b0SDavid Schultz \ 34d23166b0SDavid Schultz uv.e = v; \ 35d23166b0SDavid Schultz h = uv.bits.manh; \ 36d23166b0SDavid Schultz l = uv.bits.manl; \ 37d23166b0SDavid Schultz } while (0) 38d23166b0SDavid Schultz 39d23166b0SDavid Schultz #define SET_LDBL_EXPSIGN(v, i) do { \ 40d23166b0SDavid Schultz union IEEEl2bits uv; \ 41d23166b0SDavid Schultz \ 42d23166b0SDavid Schultz uv.e = v; \ 43d23166b0SDavid Schultz uv.xbits.expsign = i; \ 44d23166b0SDavid Schultz v = uv.e; \ 45d23166b0SDavid Schultz } while (0) 46d23166b0SDavid Schultz 47d23166b0SDavid Schultz #undef GET_HIGH_WORD 48d23166b0SDavid Schultz #define GET_HIGH_WORD(i, v) GET_LDBL_EXPSIGN(i, v) 49d23166b0SDavid Schultz #undef SET_HIGH_WORD 50d23166b0SDavid Schultz #define SET_HIGH_WORD(v, i) SET_LDBL_EXPSIGN(v, i) 51d23166b0SDavid Schultz 52d23166b0SDavid Schultz #define DESW(exp) (exp) /* delta expsign word */ 53d23166b0SDavid Schultz #define ESW(exp) (MAX_EXP - 1 + (exp)) /* expsign word */ 54d23166b0SDavid Schultz #define MANT_DIG LDBL_MANT_DIG 55d23166b0SDavid Schultz #define MAX_EXP LDBL_MAX_EXP 56d23166b0SDavid Schultz 57d23166b0SDavid Schultz #if LDBL_MANL_SIZE > 32 58d23166b0SDavid Schultz typedef uint64_t man_t; 59d23166b0SDavid Schultz #else 60d23166b0SDavid Schultz typedef uint32_t man_t; 61d23166b0SDavid Schultz #endif 62d23166b0SDavid Schultz 63d23166b0SDavid Schultz long double 64d23166b0SDavid Schultz hypotl(long double x, long double y) 65d23166b0SDavid Schultz { 66d23166b0SDavid Schultz long double a=x,b=y,t1,t2,y1,y2,w; 67d23166b0SDavid Schultz int32_t j,k,ha,hb; 68d23166b0SDavid Schultz 69d23166b0SDavid Schultz GET_HIGH_WORD(ha,x); 70d23166b0SDavid Schultz ha &= 0x7fff; 71d23166b0SDavid Schultz GET_HIGH_WORD(hb,y); 72d23166b0SDavid Schultz hb &= 0x7fff; 73d23166b0SDavid Schultz if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;} 74d23166b0SDavid Schultz a = fabsl(a); 75d23166b0SDavid Schultz b = fabsl(b); 76d23166b0SDavid Schultz if((ha-hb)>DESW(MANT_DIG+7)) {return a+b;} /* x/y > 2**(MANT_DIG+7) */ 77d23166b0SDavid Schultz k=0; 78d23166b0SDavid Schultz if(ha > ESW(MAX_EXP/2-12)) { /* a>2**(MAX_EXP/2-12) */ 79d23166b0SDavid Schultz if(ha >= ESW(MAX_EXP)) { /* Inf or NaN */ 80d23166b0SDavid Schultz man_t manh, manl; 81d23166b0SDavid Schultz /* Use original arg order iff result is NaN; quieten sNaNs. */ 82d23166b0SDavid Schultz w = fabsl(x+0.0)-fabsl(y+0.0); 83d23166b0SDavid Schultz GET_LDBL_MAN(manh,manl,a); 84d23166b0SDavid Schultz if (manh == LDBL_NBIT && manl == 0) w = a; 85d23166b0SDavid Schultz GET_LDBL_MAN(manh,manl,b); 86d23166b0SDavid Schultz if (hb >= ESW(MAX_EXP) && manh == LDBL_NBIT && manl == 0) w = b; 87d23166b0SDavid Schultz return w; 88d23166b0SDavid Schultz } 89d23166b0SDavid Schultz /* scale a and b by 2**-(MAX_EXP/2+88) */ 90d23166b0SDavid Schultz ha -= DESW(MAX_EXP/2+88); hb -= DESW(MAX_EXP/2+88); 91d23166b0SDavid Schultz k += MAX_EXP/2+88; 92d23166b0SDavid Schultz SET_HIGH_WORD(a,ha); 93d23166b0SDavid Schultz SET_HIGH_WORD(b,hb); 94d23166b0SDavid Schultz } 95d23166b0SDavid Schultz if(hb < ESW(-(MAX_EXP/2-12))) { /* b < 2**-(MAX_EXP/2-12) */ 96d23166b0SDavid Schultz if(hb <= 0) { /* subnormal b or 0 */ 97d23166b0SDavid Schultz man_t manh, manl; 98d23166b0SDavid Schultz GET_LDBL_MAN(manh,manl,b); 99d23166b0SDavid Schultz if((manh|manl)==0) return a; 100d23166b0SDavid Schultz t1=0; 101d23166b0SDavid Schultz SET_HIGH_WORD(t1,ESW(MAX_EXP-2)); /* t1=2^(MAX_EXP-2) */ 102d23166b0SDavid Schultz b *= t1; 103d23166b0SDavid Schultz a *= t1; 104d23166b0SDavid Schultz k -= MAX_EXP-2; 105d23166b0SDavid Schultz } else { /* scale a and b by 2^(MAX_EXP/2+88) */ 106d23166b0SDavid Schultz ha += DESW(MAX_EXP/2+88); 107d23166b0SDavid Schultz hb += DESW(MAX_EXP/2+88); 108d23166b0SDavid Schultz k -= MAX_EXP/2+88; 109d23166b0SDavid Schultz SET_HIGH_WORD(a,ha); 110d23166b0SDavid Schultz SET_HIGH_WORD(b,hb); 111d23166b0SDavid Schultz } 112d23166b0SDavid Schultz } 113d23166b0SDavid Schultz /* medium size a and b */ 114d23166b0SDavid Schultz w = a-b; 115d23166b0SDavid Schultz if (w>b) { 116d23166b0SDavid Schultz t1 = a; 117d23166b0SDavid Schultz union IEEEl2bits uv; 1188087c515SDavid Schultz uv.e = t1; uv.bits.manl = 0; t1 = uv.e; 119d23166b0SDavid Schultz t2 = a-t1; 120d23166b0SDavid Schultz w = sqrtl(t1*t1-(b*(-b)-t2*(a+t1))); 121d23166b0SDavid Schultz } else { 122d23166b0SDavid Schultz a = a+a; 123d23166b0SDavid Schultz y1 = b; 124d23166b0SDavid Schultz union IEEEl2bits uv; 125d23166b0SDavid Schultz uv.e = y1; uv.bits.manl = 0; y1 = uv.e; 126d23166b0SDavid Schultz y2 = b - y1; 127d23166b0SDavid Schultz t1 = a; 128d23166b0SDavid Schultz uv.e = t1; uv.bits.manl = 0; t1 = uv.e; 129d23166b0SDavid Schultz t2 = a - t1; 130d23166b0SDavid Schultz w = sqrtl(t1*y1-(w*(-w)-(t1*y2+t2*b))); 131d23166b0SDavid Schultz } 132d23166b0SDavid Schultz if(k!=0) { 133d23166b0SDavid Schultz u_int32_t high; 134d23166b0SDavid Schultz t1 = 1.0; 135d23166b0SDavid Schultz GET_HIGH_WORD(high,t1); 136d23166b0SDavid Schultz SET_HIGH_WORD(t1,high+DESW(k)); 137d23166b0SDavid Schultz return t1*w; 138d23166b0SDavid Schultz } else return w; 139d23166b0SDavid Schultz } 140