Javascript - 将十六进制转换为 IEEE-754 64 位双精度

Javascript - Convert hex to IEEE-754 64-bit double precision

我正在尝试将以下十六进制字符串:"40934B999999999A" 转换为 1234.9 (float-64)。

我在网上找了几个解决方案,但大部分都是代码,答案和我需要的不一样,比如把hex改成float类型

因为我使用的是遗留解决方案,所以我处于无法使用 es6 或更高语法(例如 DataView 或 Int16Array)的环境中。

我怎样才能得到一个 javascript 函数来给出我需要的答案?

谢谢

您的编码是双精度数字的标准 IEEE754 布局。详细布局如下:

  DECODED = 1234.9 :: Double
                  6    5          4         3         2         1         0
                  3 21098765432 1098765432109876543210987654321098765432109876543210
                  S ----E11---- ------------------------S52-------------------------
   Binary layout: 0 10000001001 0011010010111001100110011001100110011001100110011010
      Hex layout: 4093 4B99 9999 999A
       Precision: Double
            Sign: Positive
        Exponent: 10 (Stored: 1033, Bias: 1023)
  Classification: FP_NORMAL
          Binary: 0b1.001101001011100110011001100110011001100110011001101p+10
           Octal: 0o2.32271463146314632p+9
         Decimal: 1234.9
             Hex: 0x4.D2E6666666668p+8

如果您使用 node.js,那么您可以使用 https://nodejs.org/docs/latest/api/buffer.html#bufreaddoublebeoffset 读取和 https://nodejs.org/docs/latest/api/buffer.html#bufwritedoublebevalue-offset 写入这些值。

如果您必须自己编写代码,那么 https://en.wikipedia.org/wiki/Double-precision_floating-point_format 包含您需要的所有详细信息。

下面的 ES1 兼容函数准确地将十六进制字符串转换为 64 位浮点数。
它可以 return 只能表示 JavaScript 中的数字,因此 NaN 将丢失其有效负载。

function hex_to_number(str) {
  // Pad the string with zeroes to 16 characters.
  // You can omit this if you control your inputs.
  str = (str + "0000000000000000").slice(0,16);

  // Split into bits: sign (1), exponent (11), significand (52).
  var sign_and_exponent_bits = parseInt(str.slice(0,3), 16);
  var sign = sign_and_exponent_bits >= 0x800 ? -1 : +1;
  var exponent_bits = sign_and_exponent_bits & ((1<<11) - 1);
  var significand_bits = parseInt(str.slice(3,16), 16);

  // Classify the floating-point value.
  if (exponent_bits == 0x7FF)  // infinity | not a number
    return significand_bits == 0 ? sign * Number.POSITIVE_INFINITY : Number.NaN;
  else if (exponent_bits == 0)  // zero | subnormal number
    return sign * Math.pow(2, 1-1023-52) * significand_bits;
  else  // normal number
    return sign * Math.pow(2, exponent_bits-1023-52) * (Math.pow(2, 52) + significand_bits);
}

例如“40934B999999999A”:

  • 符号 = +1
  • exponent_bits = 0x409: 这是一个标准化数字
  • significand_bits = 0x34B999999999A
  • 结果是 2⁻⁴² ⋅ 0x134B999999999A,这是最接近 1234.9 的 float64(正好是 1234.90000000000009094947017729282379150390625)。

编辑:如果你不相信Math.pow(2, n)的实现,你可以用下面的函数计算它:

function ldexp(x, n) {  // compute 2^n * x, assume n is an integer
  if (!isFinite(x) || x == 0) return x;
  if (n < -2098) return x * 0;
  if (n > 2097) return x * Number.POSITIVE_INFINITY;

  // Make negative exponents positive.
  var p = 2;
  if (n < 0) { n = -n; p = 0.5; }

  // Compute 2^n by binary exponentiation.
  for (var i=1; ; i<<=1) {
    if (n & i) x *= p;
    if (i == 512) break;
    p *= p;
  }
  // Do the remaining bits manually because 2^1024 overflows.
  if (n & 1024) { x *= p; x *= p; }
  if (n & 2048) { x *= p; x *= p; x *= p; x *= p; }
  return x;
}