#include "ultra64.h" #include "math.h" #include "macros.h" #pragma weak sinf = __sinf // Coefficients of a degree 9 polynomial approximation of sine. It is not the Maclaurin polynamial, but some as-yet // undetermined more uniform approximation. static const du P[] = { { 1.0 }, { -0.16666659550427756 }, { 0.008333066246082155 }, { -0.0001980960290193795 }, { 0.000002605780637968037 }, }; static const du rpi = { 1 / M_PI }; // "reciprocal of pi" // pihi + pilo is the closest double to pi, this representation allows more precise calculations since pi itself is not // an exact float static const du pihi = { 3.1415926218032837 }; static const du pilo = { 3.178650954705639E-8 }; static const fu zero = { 0x00000000 }; /** * Returns the sine of a float as a float, using the Maclaurin series and shifting. */ f32 __sinf(f32 x) { f64 dx; // x promoted to double f64 xSq; // square of dx f64 polyApprox; // Most of the polynomial approximation to sin(x) f64 dn; // n promoted to double s32 n; // number of multiples of pi away from the first half-period f64 result; s32 ix = *(s32*)&x; // Type-pun x into an s32, i.e. its IEEE-754 hex representation s32 xpt = (ix >> 22); // Obtain the exponent of x (actually 2 * exponent + 127) xpt &= 0x1FF; // Remove the sign bit // |x| < 1 if (xpt < 255) { dx = x; // |x| > 2^{-12}: for x smaller in magnitude than this, sin(x) - x is too small for a float to register the // error if (xpt >= 230) { xSq = dx * dx; polyApprox = ((P[4].d * xSq + P[3].d) * xSq + P[2].d) * xSq + P[1].d; result = dx + (dx * xSq) * polyApprox; return (f32)result; } return x; } // |x| < 2^{28} (beyond this range, floats are too sparse to make the trig functions usable) if (xpt < 310) { dx = x; dn = dx * rpi.d; n = ROUND(dn); dn = n; // Bring x to the first half-period where the Maclaurin polynomial can be used dx -= dn * pihi.d; dx -= dn * pilo.d; xSq = dx * dx; polyApprox = ((P[4].d * xSq + P[3].d) * xSq + P[2].d) * xSq + P[1].d; result = dx + (dx * xSq) * polyApprox; // Actual Maclaurin polynomial for sin(x) // add a minus sign if x is an odd number of multiples of pi away from the first half-period if (n % 2 == 0) { return (f32)result; } return -(f32)result; } // if x is NaN if (x != x) { return __libm_qnan_f; } return zero.f; }