It is possible to use a lookup table to speed up the computation. This technique should work for all normal floating point numbers. Subnormal numbers and NaN won't work without some dedicated logic, 0 and infinity can be handled by extreme values in the table.
Although I expect this technique to be actually faster than original implementation, measurements are needed.
The code uses C++20 std::bit_cast to extract the exponent from the float value. If not available, other older techniques like frexpf exist.
#include <bit>
#include <cstdint>
#include <cstdio>
#include <limits>
constexpr float magnitudeLUT[] = {
0.f, 1e-38f, 1e-38f, 1e-38f, 1e-38f, 1e-37f, 1e-37f, 1e-37f, 1e-36f, 1e-36f, 1e-36f, 1e-35f,
1e-35f, 1e-35f, 1e-35f, 1e-34f, 1e-34f, 1e-34f, 1e-33f, 1e-33f, 1e-33f, 1e-32f, 1e-32f, 1e-32f,
1e-32f, 1e-31f, 1e-31f, 1e-31f, 1e-30f, 1e-30f, 1e-30f, 1e-29f, 1e-29f, 1e-29f, 1e-28f, 1e-28f,
1e-28f, 1e-28f, 1e-27f, 1e-27f, 1e-27f, 1e-26f, 1e-26f, 1e-26f, 1e-25f, 1e-25f, 1e-25f, 1e-25f,
1e-24f, 1e-24f, 1e-24f, 1e-23f, 1e-23f, 1e-23f, 1e-22f, 1e-22f, 1e-22f, 1e-22f, 1e-21f, 1e-21f,
1e-21f, 1e-20f, 1e-20f, 1e-20f, 1e-19f, 1e-19f, 1e-19f, 1e-19f, 1e-18f, 1e-18f, 1e-18f, 1e-17f,
1e-17f, 1e-17f, 1e-16f, 1e-16f, 1e-16f, 1e-16f, 1e-15f, 1e-15f, 1e-15f, 1e-14f, 1e-14f, 1e-14f,
1e-13f, 1e-13f, 1e-13f, 1e-13f, 1e-12f, 1e-12f, 1e-12f, 1e-11f, 1e-11f, 1e-11f, 1e-10f, 1e-10f,
1e-10f, 1e-10f, 1e-09f, 1e-09f, 1e-09f, 1e-08f, 1e-08f, 1e-08f, 1e-07f, 1e-07f, 1e-07f, 1e-07f,
1e-06f, 1e-06f, 1e-06f, 1e-05f, 1e-05f, 1e-05f, 1e-04f, 1e-04f, 1e-04f, 1e-04f, 1e-03f, 1e-03f,
1e-03f, 1e-02f, 1e-02f, 1e-02f, 1e-01f, 1e-01f, 1e-01f, 1e+00f, 1e+00f, 1e+00f, 1e+00f, 1e+01f,
1e+01f, 1e+01f, 1e+02f, 1e+02f, 1e+02f, 1e+03f, 1e+03f, 1e+03f, 1e+03f, 1e+04f, 1e+04f, 1e+04f,
1e+05f, 1e+05f, 1e+05f, 1e+06f, 1e+06f, 1e+06f, 1e+06f, 1e+07f, 1e+07f, 1e+07f, 1e+08f, 1e+08f,
1e+08f, 1e+09f, 1e+09f, 1e+09f, 1e+09f, 1e+10f, 1e+10f, 1e+10f, 1e+11f, 1e+11f, 1e+11f, 1e+12f,
1e+12f, 1e+12f, 1e+12f, 1e+13f, 1e+13f, 1e+13f, 1e+14f, 1e+14f, 1e+14f, 1e+15f, 1e+15f, 1e+15f,
1e+15f, 1e+16f, 1e+16f, 1e+16f, 1e+17f, 1e+17f, 1e+17f, 1e+18f, 1e+18f, 1e+18f, 1e+18f, 1e+19f,
1e+19f, 1e+19f, 1e+20f, 1e+20f, 1e+20f, 1e+21f, 1e+21f, 1e+21f, 1e+21f, 1e+22f, 1e+22f, 1e+22f,
1e+23f, 1e+23f, 1e+23f, 1e+24f, 1e+24f, 1e+24f, 1e+24f, 1e+25f, 1e+25f, 1e+25f, 1e+26f, 1e+26f,
1e+26f, 1e+27f, 1e+27f, 1e+27f, 1e+27f, 1e+28f, 1e+28f, 1e+28f, 1e+29f, 1e+29f, 1e+29f, 1e+30f,
1e+30f, 1e+30f, 1e+31f, 1e+31f, 1e+31f, 1e+31f, 1e+32f, 1e+32f, 1e+32f, 1e+33f, 1e+33f, 1e+33f,
1e+34f, 1e+34f, 1e+34f, 1e+34f, 1e+35f, 1e+35f, 1e+35f, 1e+36f, 1e+36f, 1e+36f, 1e+37f, 1e+37f,
1e+37f, 1e+37f, 1e+38f, 1e+38f, std::numeric_limits<float>::infinity() };
float decimalMagnitude(float val)
{
uint32_t intVal = std::bit_cast<uint32_t>(val);
uint8_t exponent = intVal >> 23;
if (val >= magnitudeLUT[exponent + 1])
return magnitudeLUT[exponent + 1];
else
return magnitudeLUT[exponent];
}
int main()
{
for (float v = 1e-38f; v < 1e38f; v *= 1.78)
printf("%e => %e\n", v, decimalMagnitude(v));
}