mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
592f6ebc20
- Write some more unit tests - memcpy() on ARM is now faster - Address the Musl complex math FIXME comments - Some libm funcs like pow() now support setting errno - Import the latest and greatest math functions from ARM - Use more accurate atan2f() and log1pf() implementations - atoi() and atol() will no longer saturate or clobber errno
175 lines
6.3 KiB
C
175 lines
6.3 KiB
C
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
|
|
│ vi: set noet ft=c ts=8 sw=8 fenc=utf-8 :vi │
|
|
╚──────────────────────────────────────────────────────────────────────────────╝
|
|
│ │
|
|
│ FreeBSD lib/msun/src/e_hypotf.c │
|
|
│ Copyright (c) 1992-2023 The FreeBSD Project. │
|
|
│ │
|
|
│ Redistribution and use in source and binary forms, with or without │
|
|
│ modification, are permitted provided that the following conditions │
|
|
│ are met: │
|
|
│ 1. Redistributions of source code must retain the above copyright │
|
|
│ notice, this list of conditions and the following disclaimer. │
|
|
│ 2. Redistributions in binary form must reproduce the above copyright │
|
|
│ notice, this list of conditions and the following disclaimer in the │
|
|
│ documentation and/or other materials provided with the distribution. │
|
|
│ │
|
|
│ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND │
|
|
│ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE │
|
|
│ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE │
|
|
│ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE │
|
|
│ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL │
|
|
│ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS │
|
|
│ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) │
|
|
│ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT │
|
|
│ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY │
|
|
│ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF │
|
|
│ SUCH DAMAGE. │
|
|
│ │
|
|
│ Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. │
|
|
│ │
|
|
│ Developed at SunPro, a Sun Microsystems, Inc. business. │
|
|
│ Permission to use, copy, modify, and distribute this │
|
|
│ software is freely granted, provided that this notice │
|
|
│ is preserved. │
|
|
│ │
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
#include "libc/tinymath/freebsd.internal.h"
|
|
__static_yoink("freebsd_libm_notice");
|
|
__static_yoink("fdlibm_notice");
|
|
|
|
static const float one = 1.0, tiny=1.0e-30;
|
|
|
|
float
|
|
sqrtf2(float x)
|
|
{
|
|
float z;
|
|
int32_t sign = (int)0x80000000;
|
|
int32_t ix,s,q,m,t,i;
|
|
uint32_t r;
|
|
|
|
GET_FLOAT_WORD(ix,x);
|
|
|
|
/* take care of Inf and NaN */
|
|
if((ix&0x7f800000)==0x7f800000) {
|
|
return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf
|
|
sqrt(-inf)=sNaN */
|
|
}
|
|
/* take care of zero */
|
|
if(ix<=0) {
|
|
if((ix&(~sign))==0) return x;/* sqrt(+-0) = +-0 */
|
|
else if(ix<0)
|
|
return (x-x)/(x-x); /* sqrt(-ve) = sNaN */
|
|
}
|
|
/* normalize x */
|
|
m = (ix>>23);
|
|
if(m==0) { /* subnormal x */
|
|
for(i=0;(ix&0x00800000)==0;i++) ix<<=1;
|
|
m -= i-1;
|
|
}
|
|
m -= 127; /* unbias exponent */
|
|
ix = (ix&0x007fffff)|0x00800000;
|
|
if(m&1) /* odd m, double x to make it even */
|
|
ix += ix;
|
|
m >>= 1; /* m = [m/2] */
|
|
|
|
/* generate sqrt(x) bit by bit */
|
|
ix += ix;
|
|
q = s = 0; /* q = sqrt(x) */
|
|
r = 0x01000000; /* r = moving bit from right to left */
|
|
|
|
while(r!=0) {
|
|
t = s+r;
|
|
if(t<=ix) {
|
|
s = t+r;
|
|
ix -= t;
|
|
q += r;
|
|
}
|
|
ix += ix;
|
|
r>>=1;
|
|
}
|
|
|
|
/* use floating add to find out rounding direction */
|
|
if(ix!=0) {
|
|
z = one-tiny; /* trigger inexact flag */
|
|
if (z>=one) {
|
|
z = one+tiny;
|
|
if (z>one)
|
|
q += 2;
|
|
else
|
|
q += (q&1);
|
|
}
|
|
}
|
|
ix = (q>>1)+0x3f000000;
|
|
ix += ((uint32_t)m <<23);
|
|
SET_FLOAT_WORD(z,ix);
|
|
return z;
|
|
}
|
|
|
|
/**
|
|
* Returns euclidean distance.
|
|
*
|
|
* Error is less than 1 ULP.
|
|
*/
|
|
float
|
|
hypotf2(float x, float y)
|
|
{
|
|
float a,b,t1,t2,y1,y2,w;
|
|
int32_t j,k,ha,hb;
|
|
|
|
GET_FLOAT_WORD(ha,x);
|
|
ha &= 0x7fffffff;
|
|
GET_FLOAT_WORD(hb,y);
|
|
hb &= 0x7fffffff;
|
|
if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;}
|
|
a = fabsf(a);
|
|
b = fabsf(b);
|
|
if((ha-hb)>0xf000000) {return a+b;} /* x/y > 2**30 */
|
|
k=0;
|
|
if(ha > 0x58800000) { /* a>2**50 */
|
|
if(ha >= 0x7f800000) { /* Inf or NaN */
|
|
/* Use original arg order iff result is NaN; quieten sNaNs. */
|
|
w = fabsl(x+0.0L)-fabsf(y+0);
|
|
if(ha == 0x7f800000) w = a;
|
|
if(hb == 0x7f800000) w = b;
|
|
return w;
|
|
}
|
|
/* scale a and b by 2**-68 */
|
|
ha -= 0x22000000; hb -= 0x22000000; k += 68;
|
|
SET_FLOAT_WORD(a,ha);
|
|
SET_FLOAT_WORD(b,hb);
|
|
}
|
|
if(hb < 0x26800000) { /* b < 2**-50 */
|
|
if(hb <= 0x007fffff) { /* subnormal b or 0 */
|
|
if(hb==0) return a;
|
|
SET_FLOAT_WORD(t1,0x7e800000); /* t1=2^126 */
|
|
b *= t1;
|
|
a *= t1;
|
|
k -= 126;
|
|
} else { /* scale a and b by 2^68 */
|
|
ha += 0x22000000; /* a *= 2^68 */
|
|
hb += 0x22000000; /* b *= 2^68 */
|
|
k -= 68;
|
|
SET_FLOAT_WORD(a,ha);
|
|
SET_FLOAT_WORD(b,hb);
|
|
}
|
|
}
|
|
/* medium size a and b */
|
|
w = a-b;
|
|
if (w>b) {
|
|
SET_FLOAT_WORD(t1,ha&0xfffff000);
|
|
t2 = a-t1;
|
|
w = sqrtf2(t1*t1-(b*(-b)-t2*(a+t1)));
|
|
} else {
|
|
a = a+a;
|
|
SET_FLOAT_WORD(y1,hb&0xfffff000);
|
|
y2 = b - y1;
|
|
SET_FLOAT_WORD(t1,(ha+0x00800000)&0xfffff000);
|
|
t2 = a - t1;
|
|
w = sqrtf2(t1*y1-(w*(-w)-(t1*y2+t2*b)));
|
|
}
|
|
if(k!=0) {
|
|
SET_FLOAT_WORD(t1,(127+k)<<23);
|
|
return t1*w;
|
|
} else return w;
|
|
}
|