C# 如何通过 IEEE 754 将 float 转换为十六进制字符串并再次转回 float?

3

我需要将一个float值转换为十六进制字符串,然后再将其转换回来。在线IEEE 754转换器可以帮助我完成这个操作。以下是我尝试实现该转换的代码:

unsafe static void Main(string[] args)
{
    float f = 0.0023984962F;
    long l = *((long*)&f);
    float r = *((float*)&l);

    Console.WriteLine("{0} <-> {1:X} <-> {1:F1} <-> {2:F1}", f, l, r);
    Console.ReadLine();
}

我的问题:

  1. 使用浮点数 0.0023984962 期望结果是 0x3B1D3017, 但我的代码输出的是 0x22CB20C3B1D3017。我错在哪儿了?

  2. 如何将输出保存到变量中?


1
一个很好的提醒是为什么“不安全代码块”确实不安全。应该使用BitConverter.GetBytes()代替它。 - Hans Passant
3个回答

4
为了能够双向转换,您需要两个函数。您代码中的一个漏洞是将32位浮点数(float)强制转换为64位整数(long)。由于您的代码是unsafe,因此编译器无法捕获此错误。
然而,使用unsafe代码性能非常出色,因此这里是可行的代码:
unsafe string ToHexString(float f) {
  var i = *((int*) &f);
  return "0x" + i.ToString("X8");
}

unsafe float FromHexString(string s) {
  var i = Convert.ToInt32(s, 16);
  return *((float*) &i);
}

为了避免不安全代码的问题,您还可以使用 BitConverter,它将为您检查中间字节缓冲区的大小。
string ToHexString(float f) {
  var bytes = BitConverter.GetBytes(f);
  var i = BitConverter.ToInt32(bytes, 0);
  return "0x" + i.ToString("X8");
}

float FromHexString(string s) {
  var i = Convert.ToInt32(s, 16);
  var bytes = BitConverter.GetBytes(i);
  return BitConverter.ToSingle(bytes, 0);
}

现在您可以双向转换:
var hexString = ToHexString(0.0023984962F);
var f = FromHexString(hexString);

2

在将 float 转换时,应使用 int 而不是 long,因为 float(也称为 Single)是 32 位值(不像 double 是 64 位值):

unsafe static void Main(string[] args)
{
    float f = 0.0023984962F;
    int l = *((int*)&f); // int here: 32-bit float into 32-bit integer
    float r = *((float*)&l);

    // Let's save the result in the variable
    String result = String.Format("{0} <-> {1:X} <-> {1:F1} <-> {2:F1}", f, l, r);

    Console.WriteLine(result);
    Console.ReadLine();
}

然而,更好的方法是使用专门设计用于此角色并避免不安全例程的BitConverter

static void Main(string[] args) {
  float f = 0.0023984962F;

  uint l = BitConverter.ToUInt32(BitConverter.GetBytes(f), 0);
  float r = BitConverter.ToSingle(BitConverter.GetBytes(l), 0);

  // Let's save the result in the variable
  String result = String.Format("{0} <-> {1:X} <-> {1:F1} <-> {2:F1}", f, l, r);

  Console.WriteLine(result);
  Console.ReadLine();
}

我试图转换一个双精度浮点数,但不知道为什么它不能正常工作。首先将双精度浮点数强制转换为单精度浮点数解决了我的问题。 - Moon Waxing
1
@月亮盈凸:double64 位的值,因此在使用 double 时应该使用 long(或 ulong)。 - Dmitry Bychenko

0
回答你的第二个问题,你可以使用字符串变量来存储输出,例如:
String output = String.Format("{0} <-> {1:X} <-> {1:F1} <-> {2:F1}", f, l, r);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接