Logic: Move (huge,tiny) test up, supersedes testing for 0.0

This commit is contained in:
Inkrementator 2025-03-18 00:13:55 +01:00
parent da127b18b8
commit 006b1ca936

View file

@ -310,7 +310,6 @@ if (isFloatingPoint!T)
// If both are tiny, avoid underflow by scaling by 2^^N. // If both are tiny, avoid underflow by scaling by 2^^N.
import core.math : fabs, sqrt; import core.math : fabs, sqrt;
import std.math.traits : floatTraits, RealFormat, isNaN; import std.math.traits : floatTraits, RealFormat, isNaN;
import std.algorithm.comparison : max;
alias F = floatTraits!T; alias F = floatTraits!T;
@ -327,12 +326,6 @@ if (isFloatingPoint!T)
} }
assert(!(u.isNaN || v.isNaN), "Comparison to NaN always fails, thus is is always handled in the branch above"); assert(!(u.isNaN || v.isNaN), "Comparison to NaN always fails, thus is is always handled in the branch above");
const maxabs = max(u,v);
if (v == 0.0)
{
return u;
}
static if (F.realFormat == RealFormat.ieeeSingle) static if (F.realFormat == RealFormat.ieeeSingle)
{ {
enum SQRTMIN = 0x1p-60f; enum SQRTMIN = 0x1p-60f;
@ -360,6 +353,13 @@ if (isFloatingPoint!T)
else else
assert(0, "hypot not implemented"); assert(0, "hypot not implemented");
if (u * T.epsilon > v)
{
// hypot (huge, tiny) = huge
// also: hypot(x, 0) = x
return u;
}
// Now u >= v, or else one is NaN. // Now u >= v, or else one is NaN.
T ratio = 1.0; T ratio = 1.0;
if (v >= SQRTMAX) if (v >= SQRTMAX)
@ -379,12 +379,6 @@ if (isFloatingPoint!T)
v *= SCALE_UNDERFLOW; v *= SCALE_UNDERFLOW;
} }
if (u * T.epsilon > v)
{
// hypot (huge, tiny) = huge
return u;
}
// both are in the normal range // both are in the normal range
return ratio * sqrt(u^^2 + v^^2); return ratio * sqrt(u^^2 + v^^2);
} }
@ -427,6 +421,7 @@ if (isFloatingPoint!T)
enum small = 5.016556e-20f; enum small = 5.016556e-20f;
assert(hypot(small, 0).isClose(small)); assert(hypot(small, 0).isClose(small));
assert(hypot(small, float.min_normal).isClose(small));
} }
@safe unittest @safe unittest