Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can float be round tripped via double without losing precision?

If I have a C# float, can I convert it to double without losing any precision?

If that double were converted back to float, would it have exactly the same value?

like image 227
Drew Noakes Avatar asked Nov 11 '16 15:11

Drew Noakes


People also ask

Can you cast a float to a double?

The doubleValue() method of Java Float class returns a double value corresponding to this Float Object by widening the primitive values or in simple words by directly converting it to double via doubleValue() method .

Why floating point numbers may lose precision?

Floating-point decimal values generally do not have an exact binary representation. This is a side effect of how the CPU represents floating point data. For this reason, you may experience some loss of precision, and some floating-point operations may produce unexpected results.

How high can a float count?

Floating-point numbers can be as large as 3.4028235E+38 and as low as -3.4028235E+38. They are stored as 32 bits (4 bytes) of information.


2 Answers

Yes. IEEE754 floating point (which is what C# must use) guarantees this:

  1. Converting a float to a double preserves exactly the same value

  2. Converting that double back to a float recovers exactly that original float.

The set of doubles is a superset of floats.

Note that this also applies to NaN, +Infinity, and -Infinity. The signedness of zero is also preserved.

like image 152
Bathsheba Avatar answered Oct 03 '22 00:10

Bathsheba


Let's test this with code:

[Fact]
public void IsFloatRoundTrippableToDouble()
{
    var bits = default(FloatUnion);
    bits.FloatData = float.MinValue;

    var testBits = default(FloatUnion);

    // ReSharper disable once LoopVariableIsNeverChangedInsideLoop
    while (bits.FloatData <= float.MaxValue)
    {
        var d = (double)bits.FloatData;
        testBits.FloatData = (float)d;

        if (bits.IntData != testBits.IntData)
            Assert.True(false);

        bits.IntData -= 1;
    }
}

[StructLayout(LayoutKind.Explicit)]
private struct FloatUnion
{
    [FieldOffset(0)] public uint IntData;
    [FieldOffset(0)] public float FloatData;
}

This code tests every float value between MinValue and MaxValue (except NaN, infinities, etc...). The in-memory byte representation is compared to ensure no other conversions take place.

Though it might seem crazy to test the ~4 billion possible floating point numbers, it actually runs in around 11 seconds on my machine.

And yes, the conversion is safe. Converting from float, to double, then back again doesn't lose any information.

like image 43
Drew Noakes Avatar answered Oct 02 '22 23:10

Drew Noakes