Implement rough versions of mod, remainder, copy_sign

This commit is contained in:
gingerBill 2016-05-01 02:10:32 +01:00
parent 2f413e88dd
commit c6d3f17e27
1 changed files with 28 additions and 89 deletions

117
gb_math.h
View File

@ -1,9 +1,9 @@
/* gb_math.h - v0.06 - public domain C math library - no warranty implied; use at your own risk */
/* A C math library geared towards game development */
/* use '#define GB_MATH_IMPLEMENTATION' before including to create the implementation in _ONE_ file */
/* gb_math.h - v0.06a - public domain C math library - no warranty implied; use at your own risk
A C math library geared towards game development
use '#define GB_MATH_IMPLEMENTATION' before including to create the implementation in _ONE_ file
/*
Version History:
0.06a - Implement rough versions of mod, remainder, copy_sign
0.06 - Windows GCC Support and C90-ish Support
0.05 - Less/no dependencies or CRT
0.04d - License Update
@ -205,6 +205,8 @@ GB_MATH_DEF float gb_angle_diff(float radians_a, float radians_b);
#define gb_max(a, b) ((a) > (b) ? (a) : (b))
#endif
GB_MATH_DEF float gb_copy_sign(float x, float y);
GB_MATH_DEF float gb_remainder(float x, float y);
GB_MATH_DEF float gb_mod(float x, float y);
GB_MATH_DEF float gb_sqrt(float a);
GB_MATH_DEF float gb_rsqrt(float a);
@ -771,95 +773,32 @@ gb_angle_diff(float radians_a, float radians_b)
return delta;
}
float
gb_copy_sign(float x, float y)
{
int ix, iy;
ix = *(int *)&x;
iy = *(int *)&y;
ix &= 0x7fffffff;
ix |= iy & 0x80000000;
return *(float *)ix;
}
float
gb_remainder(float x, float y)
{
return x - (gb_round(x/y)*y);
}
float
gb_mod(float x, float y)
{
static float const gb__zero[] = {0, -0};
int n, hx, hy, hz, ix, iy, sx, i;
hx = *(int *)&x;
hy = *(int *)&y;
sx = hx & 0x80000000;
hx ^= sx;
hy &= 0x7fffffff;
/* NOTE(bill): Purge off exception values */
if (hy == 0||(hx >= 0x7f800000)|| /* NOTE(bill): Y=0,or x not finite */
(hy > 0x7f800000)) /* NOTE(bill): Or y is NaN */
return (x*y)/(x*y);
if (hx < hy) return x; /* NOTE(bill): |x|<|y| return x */
if (hx == hy) return gb__zero[(unsigned int)sx>>31]; /* NOTE(bill): |x|=|y| return x*0 */
/* NOTE(bill): Determine ix = ilogb(x) */
if (hx < 0x00800000) { /* NOTE(bill): Subnormal x */
for (ix = -126, i = (hx<<8); i > 0; i <<= 1)
ix -=1;
} else {
ix = (hx>>23)-127;
}
/* NOTE(bill): Determine iy = ilogb(y) */
if (hy < 0x00800000) { /* NOTE(bill): Subnormal y */
for (iy = -126, i = (hy<<8); i >= 0; i <<=1 )
iy -=1;
} else {
iy = (hy>>23)-127;
}
/* NOTE(bill): Set up {hx, lx}, {hy, ly} and align y to x */
if (ix >= -126) {
hx = 0x00800000|(0x007fffff&hx);
} else { /* NOTE(bill): Subnormal x, shift x to normal */
n = -126-ix;
hx = hx<<n;
}
if (iy >= -126) {
hy = 0x00800000|(0x007fffff&hy);
} else { /* NOTE(bill): Subnormal y, shift y to normal */
n = -126-iy;
hy = hy<<n;
}
/* NOTE(bill): Fix point fmod */
n = ix - iy;
while(n--) {
hz= hx-hy;
if (hz < 0) {
hx = hx+hx;
} else {
if (hz == 0) /* NOTE(bill): Return gb_sign(x)*0 */
return gb__zero[(unsigned int)sx>>31];
hx = hz+hz;
}
}
hz = hx-hy;
if (hz >= 0)
hx = hz;
/* NOTE(bill): Convert back to floating value and restore the sign */
if (hx == 0) /* NOTE(bill): Return sign(x)*0 */
return gb__zero[(unsigned int)sx>>31];
while (hx < 0x00800000) { /* NOTE(bill): Normalize x */
hx = hx+hx;
iy -= 1;
}
if (iy >= -126) { /* NOTE(bill): Normalize output */
int t;
hx = ((hx-0x00800000) | ((iy + 127)<<23));
t = hx | sx;
x = *(float *)&t;
} else {
int t;
n = -126 - iy;
hx >>= n;
t = hx | sx;
x = *(float *)&t;
x *= 1.0f;
}
return x;
float result;
y = gb_abs(y);
result = gb_remainder(gb_abs(x), (y = gb_abs(y)));
if (gb_sign(result)) result += y;
return gb_copy_sign(result, x);
}