将两个32位整数转换为一个带符号的64位整数字符串

时间:2013-12-05 15:10:52

标签: javascript node.js postgresql

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

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

3 个答案:

答案 0 :(得分:1)

我调整了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'

答案 1 :(得分: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 :(得分:0)

根据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^32low是余数。

转换为带符号的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]范围内。