【问题标题】:Convert two 32 bit integers to one signed 64 bit integer string将两个 32 位整数转换为一个有符号 64 位整数字符串
【发布时间】:2013-12-22 14:28:02
【问题描述】:

我有一个 64 位无符号整数需要在 PostgreSQL 中表示。我将其分解为两个 32 位无符号整数,highlow。为了让 Postgres 接受它,我需要将 highlow 转换为表示有符号 64 位整数的字符串。

如何将两个 32 位无符号整数转换为以十进制表示有符号 64 位整数的字符串?

【问题讨论】:

  • high.toString() + low.toString()?
  • @MattBurland 否。因为它不是 1→1 映射,而且它可能超过 64 位有符号的最大值。
  • 低和高分别代表什么?我不明白为什么你不能像@MattBurland 建议的那样连接两者
  • @AndrewWalters 高位是高 32 位,低位是低 32 位。想一想。 ''+(Math.pow(2, 32)-1)+(Math.pow(2, 32)-1) = “42949672954294967295”。 42949672954294967295 大于 2^63-1,即有符号整数的最大值。

标签: javascript node.js postgresql


【解决方案1】:

我已经在 J​​avascript 中以一种快速'n'dirty-but-works'n'fast 的方式完成了这项工作:Int64HighLowToFromString,使用 53 位尾数双精度算术和 32 位位运算,专门用于十进制输入/输出。

function Int64HiLoToString(hi,lo){
  hi>>>=0;lo>>>=0;
  var sign="";
  if(hi&0x80000000){
    sign="-";
    lo=(0x100000000-lo)>>>0;
    hi=0xffffffff-hi+ +(lo===0);
  }
  var dhi=~~(hi/0x5af4),dhirem=hi%0x5af4;
  var dlo=dhirem*0x100000000+dhi*0xef85c000+lo;
  dhi += ~~(dlo/0x5af3107a4000);
  dlo%=0x5af3107a4000;
  var slo=""+dlo;
  if(dhi){
    slo="000000000000000000".slice(0,14-slo.length)+dlo;
    return sign+dhi+slo;
  }else{
    return sign+slo;
  }
}

这很可能是您需要的。

【讨论】:

    【解决方案2】:

    我改编了来自https://codegolf.stackexchange.com/questions/1620/arbitrary-base-conversion 的基本转换代码。错误是我的,聪明是他们的。

    我还必须添加一堆代码来处理负数(二进制补码)。

    此代码是 ecmascript5,需要稍作修改才能在旧浏览器中工作。

    function convert(hi, lo) {
      function invertBit(bit) {
        return bit == "0" ? "1" : "0";
      }
    
      function binaryInvert(binaryString) {
        return binaryString.split("").map(invertBit).join("");
      }
    
      function binaryIncrement(binaryString) {
        var idx = binaryString.lastIndexOf("0");
        return binaryString.substring(0, idx) + "1" + binaryInvert(binaryString.substring(idx + 1));
      }
    
      function binaryDecrement(binaryString) {
        var idx = binaryString.lastIndexOf("1");
        return binaryString.substring(0, idx) + binaryInvert(binaryString.substring(idx));
      }
    
      function binaryAbs(binaryString) {
        if (binaryString[0] === "1") {
          return invertBits(binaryDecrement(binaryString));
        }
        return binaryString;
      }
    
      function to32Bits(val) {
        var binaryString = val.toString(2);
        if (binaryString[0] === "-") {
          binaryString = Array(33 - (binaryString.length - 1)).join("1") + binaryInvert(binaryString.substr(1));
          return binaryIncrement(binaryString);
        }
        return Array(33 - binaryString.length).join("0") + binaryString;
      }
    
      var fullBinaryNumber = to32Bits(hi) + to32Bits(lo);
      var isNegative = fullBinaryNumber[0] === "1";
    
      fullBinaryNumber = binaryAbs(fullBinaryNumber);
    
      var result = "";
    
      while (fullBinaryNumber.length > 0) {
        var remainingToConvert = "", resultDigit = 0;
        for (var position = 0; position < fullBinaryNumber.length; ++position) {
          var currentValue = Number(fullBinaryNumber[position]) + resultDigit * 2;
          var remainingDigitToConvert = Math.floor(currentValue / 10);
          resultDigit = currentValue % 10;
          if (remainingToConvert.length || remainingDigitToConvert) {
            remainingToConvert += remainingDigitToConvert;
          }
        }
        fullBinaryNumber = remainingToConvert;
        result = resultDigit + result;
      }
      return (isNegative?"-":"") + result;
    }
    

    例子:

    > // largest negative number -2^63 (just the most significant bit set)
    > convert(1 << 31, 0)
    '-9223372036854775808'
    > // largest positive number
    > convert(0x7fffffff, 0xffffffff)
    '9223372036854775807'
    > // -1 is all bits set.
    > convert(0xffffffff, 0xffffffff)
    '-1'
    

    【讨论】:

      【解决方案3】:

      根据JavaScript can't handle 64-bit integers, can it?,Javascript 中的原生数字有 53 位尾数,因此 JS 无法处理 64 位整数,除非使用专门的库。

      无论数据类型和实现限制如何,我假设您要计算初始 64 位无符号数的 Two's complement,将其从 [0 ... 2^64-1] 范围转换为 [-2 ^63 ... 2^63-1] 范围。

      high 大概是最初的无符号 64 位数字除以 2^32,而low 是余数。

      到有符号 64 位的转换应该是这样的:

      if high>=2^63 then
         s64 = -(2^64-(high*2^32+low))
       else
         s64 = high*2^32+low;
      

      在 PostgreSQL 函数中,这可以使用精确精度 numeric 类型来完成,以避免中间乘法中的溢出,并将最终结果向下转换为 bigint(有符号 64 位):

      create function concat64(bigint, bigint) returns bigint
      as $$
       select (case when $1>=2147483648
        then -(18446744073709551616::numeric-($1*4294967296::numeric+$2))
        else $1*4294967296::numeric+$2 end)::bigint;
      $$ language sql;
      

      输入参数必须是bigint(64 位),因为 postgres 没有无符号类型。 假定它们在[0..4294967296] 范围内,输出应在[-9223372036854775808..9223372036854775807] 范围内。

      【讨论】:

        猜你喜欢
        • 2019-08-17
        • 2019-08-15
        • 1970-01-01
        • 2011-04-21
        • 2021-10-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-30
        相关资源
        最近更新 更多