Say I have a float X. I want to find the largest number that is less than X and can be losslessly stored in a float.
IIRC the IEEE standard says you can do this by converting the float’s bits to an int representation, subtracting one, and convert back to float.
(edit: this is true for positive numbers that are not NaN or inf. For negative numbers, you must add. See Rawling’s answer for more info.)
To change between representations, I only know of C#’s (cast) operator, which truncates. That’s not what I want.
Is there a way to do this in C#?
Here is how you can simply turn a
floatinto anint, change it, and then turn it back into afloat:BitConvertereven has this built in for the 64-bit equivalent:However, as Peter Ruderman points out, a simple decrement of the underlying
intdoesn’t reliably give you the next-smallestfloat.In particular, for negative numbers, you need to increment the integer in order to make the float more negative. For
floatzero, the next smallestintactually corresponds toNaN, so you need a special case there.Here are a couple of functions I’ve knocked together that should cope with these cases in general; it also looks like it sensibly travels between large numbers and positive/negative infinity, too! I’ve used unsafe conversions to reduce code length, but you can stick to the byte conversions above if you wish:
As Jeppe points out, you probably also want to
if (float.IsNaN(f)) return f;, so you don’t accidentally increment or decrement aNaNand give something which is a number.float.PositiveInfinityor.NegativeInfinity, since, mathematically speaking, those should probably stay constant under increment/decrement.