我有一个64位无符号整数,我需要在PostgreSQL中表示。我把它分解为两个32位无符号整数high
和low
。为了让Postgres接受它,我需要将high
和low
转换为表示带符号的64位整数的字符串。
如何将两个32位无符号整数转换为以十进制表示的有符号64位整数的字符串?
答案 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)
我已经在 Javascript 中以一种快速'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^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]
范围内。