转换 float -> double -> float
Convert float -> double -> float
是否可以将 float 转换为 double,然后返回而不丢失精度?我的意思是第一个浮点数应该像结果浮点数一样精确。
是的,我们可以测试它:
float fl = float.NegativeInfinity;
long cycles = 0;
while (true)
{
double dbl = fl;
float fl2 = (float)dbl;
int flToInt1 = new Ieee754.Int32SingleConverter { Single = fl }.Int32;
int flToInt2 = new Ieee754.Int32SingleConverter { Single = fl2 }.Int32;
if (flToInt1 != flToInt2)
{
Console.WriteLine("\nDifferent: {0} (Int32: {1}, {2})", fl, flToInt1, flToInt2);
}
if (fl == 0)
{
Console.WriteLine("\n0, Sign: {0}", flToInt1 < 0 ? "-" : "+");
}
if (fl == float.PositiveInfinity)
{
fl = float.NaN;
}
else if (float.IsNaN(fl))
{
break;
}
else
{
fl = Ieee754.NextSingle(fl);
}
cycles++;
if (cycles % 100000000 == 0)
{
Console.Write(".");
}
}
Console.WriteLine("\nDone");
Console.ReadKey();
和实用程序 类:
public static class Ieee754
{
[StructLayout(LayoutKind.Explicit)]
public struct Int32SingleConverter
{
[FieldOffset(0)]
public int Int32;
[FieldOffset(0)]
public float Single;
}
public static float NextSingle(float value)
{
int bits = new Int32SingleConverter { Single = value }.Int32;
if (bits >= 0)
{
bits++;
}
else if (bits != int.MinValue)
{
bits--;
}
else
{
bits = 0;
}
return new Int32SingleConverter { Int32 = bits }.Single;
}
}
在我的电脑上,在发布模式下,没有调试器(来自 Visual Studio 的 Ctrl+F5),大约需要 2 分钟。
大约有 40 亿个不同的 float
值。我将它们投射并将它们转换为 int
以对它们进行二进制检查。请注意 NaN
值为 "particular"。 IEEE754 标准对 NaN
有多个值,但 .NET "compresses" 它们只有一个 NaN
值。因此,您可以创建一个无法正确来回转换的 NaN
值(手动,通过位操作)。 "standard" NaN
值已正确转换,因此 PositiveInfinity
和 NegativeInfinity
、+0
和 -0
。
是的,因为每个浮点数都可以精确地表示为双精度数,所以往返将为您提供开始时的确切值。
对于您要求它们逐位相同的要求,有一个可能的技术例外:有多个位模式对应于 NaN 值(这通常称为 "NaN payload")。据我所知,没有严格要求保留它:你仍然会得到一个 NaN,只是可能略有不同。
是否可以将 float 转换为 double,然后返回而不丢失精度?我的意思是第一个浮点数应该像结果浮点数一样精确。
是的,我们可以测试它:
float fl = float.NegativeInfinity;
long cycles = 0;
while (true)
{
double dbl = fl;
float fl2 = (float)dbl;
int flToInt1 = new Ieee754.Int32SingleConverter { Single = fl }.Int32;
int flToInt2 = new Ieee754.Int32SingleConverter { Single = fl2 }.Int32;
if (flToInt1 != flToInt2)
{
Console.WriteLine("\nDifferent: {0} (Int32: {1}, {2})", fl, flToInt1, flToInt2);
}
if (fl == 0)
{
Console.WriteLine("\n0, Sign: {0}", flToInt1 < 0 ? "-" : "+");
}
if (fl == float.PositiveInfinity)
{
fl = float.NaN;
}
else if (float.IsNaN(fl))
{
break;
}
else
{
fl = Ieee754.NextSingle(fl);
}
cycles++;
if (cycles % 100000000 == 0)
{
Console.Write(".");
}
}
Console.WriteLine("\nDone");
Console.ReadKey();
和实用程序 类:
public static class Ieee754
{
[StructLayout(LayoutKind.Explicit)]
public struct Int32SingleConverter
{
[FieldOffset(0)]
public int Int32;
[FieldOffset(0)]
public float Single;
}
public static float NextSingle(float value)
{
int bits = new Int32SingleConverter { Single = value }.Int32;
if (bits >= 0)
{
bits++;
}
else if (bits != int.MinValue)
{
bits--;
}
else
{
bits = 0;
}
return new Int32SingleConverter { Int32 = bits }.Single;
}
}
在我的电脑上,在发布模式下,没有调试器(来自 Visual Studio 的 Ctrl+F5),大约需要 2 分钟。
大约有 40 亿个不同的 float
值。我将它们投射并将它们转换为 int
以对它们进行二进制检查。请注意 NaN
值为 "particular"。 IEEE754 标准对 NaN
有多个值,但 .NET "compresses" 它们只有一个 NaN
值。因此,您可以创建一个无法正确来回转换的 NaN
值(手动,通过位操作)。 "standard" NaN
值已正确转换,因此 PositiveInfinity
和 NegativeInfinity
、+0
和 -0
。
是的,因为每个浮点数都可以精确地表示为双精度数,所以往返将为您提供开始时的确切值。
对于您要求它们逐位相同的要求,有一个可能的技术例外:有多个位模式对应于 NaN 值(这通常称为 "NaN payload")。据我所知,没有严格要求保留它:你仍然会得到一个 NaN,只是可能略有不同。