Files
2025-08-27 09:51:58 +01:00

141 lines
3.4 KiB
C

/*Copyright (C) 2008-2009 Timothy B. Terriberry (tterribe@xiph.org)
You can redistribute this library and/or modify it under the terms of the
GNU Lesser General Public License as published by the Free Software
Foundation; either version 2.1 of the License, or (at your option) any later
version.*/
#include <stdlib.h>
#include "util.h"
/*Computes floor(sqrt(_val)) exactly.*/
unsigned qr_isqrt(unsigned _val){
unsigned g;
unsigned b;
int bshift;
/*Uses the second method from
http://www.azillionmonkeys.com/qed/sqroot.html
The main idea is to search for the largest binary digit b such that
(g+b)*(g+b) <= _val, and add it to the solution g.*/
g=0;
b=0x8000;
for(bshift=16;bshift-->0;){
unsigned t;
t=((g<<1)+b)<<bshift;
if(t<=_val){
g+=b;
_val-=t;
}
b>>=1;
}
return g;
}
/*Computes sqrt(_x*_x+_y*_y) using CORDIC.
This implementation is valid for all 32-bit inputs and returns a result
accurate to about 27 bits of precision.
It has been tested for all postiive 16-bit inputs, where it returns correctly
rounded results in 99.998% of cases and the maximum error is
0.500137134862598032 (for _x=48140, _y=63018).
Very nearly all results less than (1<<16) are correctly rounded.
All Pythagorean triples with a hypotenuse of less than ((1<<27)-1) evaluate
correctly, and the total bias over all Pythagorean triples is -0.04579, with
a relative RMS error of 7.2864E-10 and a relative peak error of 7.4387E-9.*/
unsigned qr_ihypot(int _x,int _y){
unsigned x;
unsigned y;
int mask;
int shift;
int u;
int v;
int i;
x=_x=abs(_x);
y=_y=abs(_y);
mask=-(x>y)&(_x^_y);
x^=mask;
y^=mask;
_y^=mask;
shift=31-qr_ilog(y);
shift=QR_MAXI(shift,0);
x=(unsigned)((x<<shift)*0x9B74EDAAULL>>32);
_y=(int)((_y<<shift)*0x9B74EDA9LL>>32);
u=x;
mask=-(_y<0);
x+=(_y+mask)^mask;
_y-=(u+mask)^mask;
u=(x+1)>>1;
v=(_y+1)>>1;
mask=-(_y<0);
x+=(v+mask)^mask;
_y-=(u+mask)^mask;
for(i=1;i<16;i++){
int r;
u=(x+1)>>2;
r=(1<<2*i)>>1;
v=(_y+r)>>2*i;
mask=-(_y<0);
x+=(v+mask)^mask;
_y=(_y-((u+mask)^mask))<<1;
}
return (x+((1U<<shift)>>1))>>shift;
}
#if defined(__GNUC__) && defined(HAVE_FEATURES_H)
# include <features.h>
# if __GNUC_PREREQ(3,4)
# include <limits.h>
# if INT_MAX>=2147483647
# define QR_CLZ0 sizeof(unsigned)*CHAR_BIT
# define QR_CLZ(_x) (__builtin_clz(_x))
# elif LONG_MAX>=2147483647L
# define QR_CLZ0 sizeof(unsigned long)*CHAR_BIT
# define QR_CLZ(_x) (__builtin_clzl(_x))
# endif
# endif
#endif
int qr_ilog(unsigned _v){
#if defined(QR_CLZ)
/*Note that __builtin_clz is not defined when _x==0, according to the gcc
documentation (and that of the x86 BSR instruction that implements it), so
we have to special-case it.*/
return QR_CLZ0-QR_CLZ(_v)&-!!_v;
#else
int ret;
int m;
m=!!(_v&0xFFFF0000)<<4;
_v>>=m;
ret=m;
m=!!(_v&0xFF00)<<3;
_v>>=m;
ret|=m;
m=!!(_v&0xF0)<<2;
_v>>=m;
ret|=m;
m=!!(_v&0xC)<<1;
_v>>=m;
ret|=m;
ret|=!!(_v&0x2);
return ret + !!_v;
#endif
}
#if defined(QR_TEST_SQRT)
#include <math.h>
#include <stdio.h>
/*Exhaustively test the integer square root function.*/
int main(void){
unsigned u;
u=0;
do{
unsigned r;
unsigned s;
r=qr_isqrt(u);
s=(int)sqrt(u);
if(r!=s)printf("%u: %u!=%u\n",u,r,s);
u++;
}
while(u);
return 0;
}
#endif