Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to calculate largest float smaller than input integer in C#?

I need a C# function that takes in an integer and returns a float, which is the largest float smaller than that integer. In normal (not floating point) math, this is an example: For input of 5 the expected output is 4.999999

I tried doing

float Calculate(int input) {
    return ((float)input) - float.Epsilon;
}

But it only works for input of 0, and not for any other integers. For 0 it returns -1,401298E-45 and for others it just returns the same value as input.

I understand that this is due to how floating point math works, but what would be the consistent way of handling this? Would it be manually setting mantissa bits?

like image 801
Laserna Tunika Avatar asked Oct 25 '25 14:10

Laserna Tunika


1 Answers

You can use MathF.BitDecrement. This is available from .NET Core 3+, and is also available as Math.BitDecrement.

var output = MathF.BitDecrement((float)input);

On newer .NET versions this is also available on IFloatingPointIeee754.


The relevant source code for float is fairly simple: just add a 1 to the bare integer value, given that the fraction part is the lowest bits.

public static float BitDecrement(float x)
{
    uint bits = BitConverter.SingleToUInt32Bits(x);

    if (!float.IsFinite(x))
    {
        // NaN returns NaN
        // -Infinity returns -Infinity
        // +Infinity returns MaxValue
        return (bits == float.PositiveInfinityBits) ? float.MaxValue : x;
    }

    if (bits == float.PositiveZeroBits)
    {
        // +0.0 returns -float.Epsilon
        return -float.Epsilon;
    }

    // Negative values need to be incremented
    // Positive values need to be decremented

    if (float.IsNegative(x))
    {
        bits += 1;
    }
    else
    {
        bits -= 1;
    }
    return BitConverter.UInt32BitsToSingle(bits);
}

In Mono you don't have SingleToUInt32Bits so you can do

uint bits = unchecked((int)BitConverter.SingleToInt32Bits(x));
return BitConverter.Int32BitsToSingle(unchecked((int)bits));
like image 102
Charlieface Avatar answered Oct 27 '25 02:10

Charlieface