Audio/FaceSynth.PowF.cs
using System;
namespace SquishyTerry.Audio;
public sealed partial class FaceSynth
{
// musl (fdlibm) single precision powf, the implementation the original binary was built with.
// Porting it keeps the patch's [pow] / mtof results bit identical to the original.
static readonly float[] PowBp = { 1.0f, 1.5f };
static readonly float[] PowDpH = { 0.0f, 5.84960938e-01f };
static readonly float[] PowDpL = { 0.0f, 1.56322085e-06f };
static float Bits( int i ) => BitConverter.Int32BitsToSingle( i );
static int Word( float f ) => BitConverter.SingleToInt32Bits( f );
/// <summary>musl powf.</summary>
static float PowF( float x, float y )
{
const float two24 = 16777216.0f, huge = 1.0e30f, tiny = 1.0e-30f;
const float L1 = 6.0000002384e-01f, L2 = 4.2857143283e-01f, L3 = 3.3333334327e-01f, L4 = 2.7272811532e-01f,
L5 = 2.3066075146e-01f, L6 = 2.0697501302e-01f;
const float P1 = 1.6666667163e-01f, P2 = -2.7777778450e-03f, P3 = 6.6137559770e-05f, P4 = -1.6533901999e-06f,
P5 = 4.1381369442e-08f;
const float lg2 = 6.9314718246e-01f, lg2_h = 6.93145752e-01f, lg2_l = 1.42860654e-06f, ovt = 4.2995665694e-08f;
const float cp = 9.6179670095e-01f, cp_h = 9.6191406250e-01f, cp_l = -1.1736857402e-04f;
const float ivln2 = 1.4426950216e+00f, ivln2_h = 1.4426879883e+00f, ivln2_l = 7.0526075433e-06f;
float z, ax, z_h, z_l, p_h, p_l, y1, t1, t2, r, s, sn, t, u, v, w;
int i, j, k, yisint, n, hx, hy, ix, iy, isw;
hx = Word( x );
hy = Word( y );
ix = hx & 0x7fffffff;
iy = hy & 0x7fffffff;
if ( hx == 0x3f800000 || iy == 0 ) return 1.0f;
if ( ix > 0x7f800000 || iy > 0x7f800000 ) return x + y;
yisint = 0;
if ( hx < 0 )
{
if ( iy >= 0x4b800000 ) yisint = 2;
else if ( iy >= 0x3f800000 )
{
k = (iy >> 23) - 0x7f;
j = iy >> (23 - k);
if ( (j << (23 - k)) == iy ) yisint = 2 - (j & 1);
}
}
if ( iy == 0x7f800000 )
{
if ( ix == 0x3f800000 ) return 1.0f;
if ( ix > 0x3f800000 ) return hy >= 0 ? y : 0.0f;
return hy >= 0 ? 0.0f : -y;
}
if ( iy == 0x3f800000 ) return hy >= 0 ? x : 1.0f / x;
if ( hy == 0x40000000 ) return x * x;
if ( hy == 0x3f000000 && hx >= 0 ) return MathF.Sqrt( x );
ax = MathF.Abs( x );
if ( ix == 0x7f800000 || ix == 0 || ix == 0x3f800000 )
{
z = ax;
if ( hy < 0 ) z = 1.0f / z;
if ( hx < 0 )
{
if ( ((ix - 0x3f800000) | yisint) == 0 ) z = (z - z) / (z - z);
else if ( yisint == 1 ) z = -z;
}
return z;
}
sn = 1.0f;
if ( hx < 0 )
{
if ( yisint == 0 ) return (x - x) / (x - x);
if ( yisint == 1 ) sn = -1.0f;
}
if ( iy > 0x4d000000 )
{
if ( ix < 0x3f7ffff8 ) return hy < 0 ? sn * huge * huge : sn * tiny * tiny;
if ( ix > 0x3f800007 ) return hy > 0 ? sn * huge * huge : sn * tiny * tiny;
t = ax - 1;
w = (t * t) * (0.5f - t * (0.333333333333f - t * 0.25f));
u = ivln2_h * t;
v = t * ivln2_l - w * ivln2;
t1 = u + v;
t1 = Bits( Word( t1 ) & unchecked((int)0xfffff000) );
t2 = v - (t1 - u);
}
else
{
float s2, s_h, s_l, t_h, t_l;
n = 0;
if ( ix < 0x00800000 )
{
ax *= two24;
n -= 24;
ix = Word( ax );
}
n += (ix >> 23) - 0x7f;
j = ix & 0x007fffff;
ix = j | 0x3f800000;
if ( j <= 0x1cc471 ) k = 0;
else if ( j < 0x5db3d7 ) k = 1;
else
{
k = 0;
n += 1;
ix -= 0x00800000;
}
ax = Bits( ix );
u = ax - PowBp[k];
v = 1.0f / (ax + PowBp[k]);
s = u * v;
s_h = Bits( Word( s ) & unchecked((int)0xfffff000) );
isw = ((ix >> 1) & unchecked((int)0xfffff000)) | 0x20000000;
t_h = Bits( isw + 0x00400000 + (k << 21) );
t_l = ax - (t_h - PowBp[k]);
s_l = v * ((u - s_h * t_h) - s_h * t_l);
s2 = s * s;
r = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6)))));
r += s_l * (s_h + s);
s2 = s_h * s_h;
t_h = 3.0f + s2 + r;
t_h = Bits( Word( t_h ) & unchecked((int)0xfffff000) );
t_l = r - ((t_h - 3.0f) - s2);
u = s_h * t_h;
v = s_l * t_h + t_l * s;
p_h = u + v;
p_h = Bits( Word( p_h ) & unchecked((int)0xfffff000) );
p_l = v - (p_h - u);
z_h = cp_h * p_h;
z_l = cp_l * p_h + p_l * cp + PowDpL[k];
t = n;
t1 = ((z_h + z_l) + PowDpH[k]) + t;
t1 = Bits( Word( t1 ) & unchecked((int)0xfffff000) );
t2 = z_l - (((t1 - t) - PowDpH[k]) - z_h);
}
y1 = Bits( Word( y ) & unchecked((int)0xfffff000) );
p_l = (y - y1) * t1 + y * t2;
p_h = y1 * t1;
z = p_l + p_h;
j = Word( z );
if ( j > 0x43000000 ) return sn * huge * huge;
else if ( j == 0x43000000 )
{
if ( p_l + ovt > z - p_h ) return sn * huge * huge;
}
else if ( (j & 0x7fffffff) > 0x43160000 ) return sn * tiny * tiny;
else if ( j == unchecked((int)0xc3160000) )
{
if ( p_l <= z - p_h ) return sn * tiny * tiny;
}
i = j & 0x7fffffff;
k = (i >> 23) - 0x7f;
n = 0;
if ( i > 0x3f000000 )
{
n = j + (0x00800000 >> (k + 1));
k = ((n & 0x7fffffff) >> 23) - 0x7f;
t = Bits( n & ~(0x007fffff >> k) );
n = ((n & 0x007fffff) | 0x00800000) >> (23 - k);
if ( j < 0 ) n = -n;
p_h -= t;
}
t = p_l + p_h;
t = Bits( Word( t ) & unchecked((int)0xffff8000) );
u = t * lg2_h;
v = (p_l - (t - p_h)) * lg2 + t * lg2_l;
z = u + v;
w = v - (z - u);
t = z * z;
t1 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5))));
r = (z * t1) / (t1 - 2.0f) - (w + z * w);
z = 1.0f - (r - z);
j = Word( z );
j += n << 23;
if ( (j >> 23) <= 0 ) z = ScalbnF( z, n );
else z = Bits( j );
return sn * z;
}
static float ScalbnF( float x, int n )
{
float y = x;
if ( n > 127 )
{
y *= 1.7014118e38f;
n -= 127;
if ( n > 127 )
{
y *= 1.7014118e38f;
n -= 127;
if ( n > 127 ) n = 127;
}
}
else if ( n < -126 )
{
y *= 1.1754944e-38f;
n += 126;
if ( n < -126 )
{
y *= 1.1754944e-38f;
n += 126;
if ( n < -126 ) n = -126;
}
}
return y * Bits( (0x7f + n) << 23 );
}
}