float 是否可以通过 double 往返而不损失精度?

Can float be round tripped via double without losing precision?

如果我有一个 C# float,我可以将它转换为 double 而不会丢失任何精度吗?

如果 double 转换回 float,它的值是否完全相同?

让我们用代码来测试一下:

[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;
}

此代码测试 MinValueMaxValue 之间的每个 float 值(NaN、无穷大等除外)。比较内存中的字节表示以确保不会发生其他转换。

虽然测试大约 40 亿个可能的浮点数看起来很疯狂,但它实际上在我的机器上运行大约 11 秒。

是的,转换是安全的。从 float 转换为 double,然后再返回不会丢失任何信息。

是的。 IEEE754 浮点数(这是 C# 必须使用的)保证:

  1. float 转换为 double完全 保留相同的值

  2. double 转换回 float 可以恢复 原来的 float

double 的集合是 float 的超集。

请注意,此 适用于 NaN+Infinity-Infinity。零的符号也被保留。