Javascript:将(十六进制)有符号整数转换为Javascript值

Javascript:将(十六进制)有符号整数转换为Javascript值,javascript,sign,Javascript,Sign,我有一个以十六进制数形式给出的有符号值,例如0xffeb,并希望将其转换为-21作为“普通”Javascript整数 到目前为止,我已经编写了一些代码: function toBinary(a) { //: String var r = ''; var binCounter = 0; while (a > 0) { r = a%2 + r; a = Math.floor(a/2); } return r; } fun

我有一个以十六进制数形式给出的有符号值,例如
0xffeb
,并希望将其转换为
-21
作为“普通”Javascript整数

到目前为止,我已经编写了一些代码:

function toBinary(a) { //: String
    var r = '';
    var binCounter = 0;
    while (a > 0) {
        r = a%2 + r;
        a = Math.floor(a/2);
    }
    return r;
}

function twoscompl(a) { //: int
    var l = toBinaryFill(a).length;
    var msb = a >>> (l-1);

    if (msb == 0) {
        return a;
    }

    a = a-1;
    var str = toBinary(a);
    var nstr = '';
    for (var i = 0; i < str.length; i++) {
        nstr += str.charAt(i) == '1' ? '0' : '1';
    }
    return (-1)*parseInt(nstr);
}
你有没有办法更有效、更好地实施这个计划

您好, mythbu

使用
parseInt()
转换(只接受十六进制字符串):

然后使用掩码确定是否设置了MSB:

a & 0x8000
如果它返回一个非零值,你就知道它是负值

总而言之:

a = "0xffeb";
a = parseInt(a, 16);
if ((a & 0x8000) > 0) {
   a = a - 0x10000;
}
请注意,这仅适用于16位整数(
short
在C中)。如果你有一个32位整数,你需要一个不同的掩码和减法。

我想出了这个

function hexToInt(hex) {
    if (hex.length % 2 != 0) {
        hex = "0" + hex;
    }
    var num = parseInt(hex, 16);
    var maxVal = Math.pow(2, hex.length / 2 * 8);
    if (num > maxVal / 2 - 1) {
        num = num - maxVal
    }
    return num;
}
使用方法:

var res = hexToInt("FF"); // -1
res = hexToInt("A"); // same as "0A", 10
res = hexToInt("FFF"); // same as "0FFF", 4095
res = hexToInt("FFFF"); // -1
所以基本上十六进制的转换范围取决于十六进制的长度,这就是我想要的。希望能有帮助

function hexToSignedInt(hex) {
    if (hex.length % 2 != 0) {
        hex = "0" + hex;
    }
    var num = parseInt(hex, 16);
    var maxVal = Math.pow(2, hex.length / 2 * 8);
    if (num > maxVal / 2 - 1) {
        num = num - maxVal
    }
    return num;
}

function hexToUnsignedInt(hex){
    return parseInt(hex,16);
}
第一个用于有符号整数和 第二个是基于@I've的无符号整数

function HexToSignedInt(num, numSize) {
    var val = {
        mask: 0x8 * Math.pow(16, numSize-1), //  0x8000 if numSize = 4
        sub: -0x1 * Math.pow(16, numSize)    //-0x10000 if numSize = 4
    }
    if(parseInt(num, 16) & val.mask > 0) { //negative
        return (val.sub + parseInt(num, 16))
    }else {                                 //positive
        return (parseInt(num,16))
    }
 }
现在您可以指定精确的长度(以半字节为单位)


由于我必须将绝对数值转换为介于-2^24到2^24-1之间的int32值, 我提出了这个解决方案,您只需通过
parseInt(hex,16)
将输入更改为一个数字,在您的情况下,nBytes是2

function toSignedInt(value, nBytes) { // 0 <= value < 2^nbytes*4, nBytes >= 1, 
  var hexMask = '0x80' + '00'.repeat(nBytes - 1);
  var intMask = parseInt(hexMask, 16);
  if (value >= intMask) {
    value = value - intMask * 2;
  }
  return value;
}

var vals = [       // expected output
  '0x00',          // 0
  '0xFF',          // 255
  '0xFFFFFF',      // 2^24 - 1 = 16777215
  '0x7FFFFFFF',    // 2^31 -1 = 2147483647
  '0x80000000',    // -2^31 = -2147483648
  '0x80000001',    // -2^31 + 1 = -2147483647
  '0xFFFFFFFF',    // -1
];
for (var hex of vals) {
  var num = parseInt(hex, 16);
  var result = toSignedInt(num, 4);
  console.log(hex, num, result);
}

var sampleInput = '0xffeb';
var sampleResult = toSignedInt(parseInt(sampleInput, 16), 2);
console.log(sampleInput, sampleResult); // "0xffeb", -21
函数toSignedInt(值,n字节){//0=1, var hexMask='0x80'+'00'。重复(n字节-1); var intMask=parseInt(hexMask,16); 如果(值>=intMask){ value=value-intMask*2; } 返回值; } var VAL=[//预期输出 “0x00”,//0 '0xFF',//255 '0xFFFFFF',//2^24-1=16777215 '0x7FFFFFFF',//2^31-1=2147483647 '0x8000000',/-2^31=-2147483648 '0x80000001',/-2^31+1=-2147483647 '0xFFFFFF',/-1 ]; 用于(var十六进制VAL){ var num=parseInt(十六进制,16); var结果=toSignedInt(数值,4); 日志(十六进制,数字,结果); } var sampleInput='0xffeb'; var samplesult=toSignedInt(parseInt(sampleInput,16),2); console.log(sampleInput,sampleResult);//“0xffeb”,-21
不确定它有多重要,但由于您正在使用hex和
parseInt
,您可能想要使用
parseInt(a,16)
@Ian,我在Firebug控制台中测试了它,并且
parseInt(“0xffeb”)
正确解析。当省略
0x
时,它需要基数。为了安全起见,应该始终添加它。我更新了我的答案。确实,它可以在没有它的情况下工作,但是
parseInt
也可以在没有它的情况下在正常的int字符串上工作……除非您意外地给出了错误的输入(比如期望基数为10的解析,但出于任何原因提供了“012”),并且得到
10
。这似乎也是浏览器一致性的问题。我刚刚发现,始终提供基数更好,即使您使用的是“正常”基数10。只是想指出这一切:)惊人的干净和微小的代码!世界可以如此简单…:-)工作是一种享受。。。谢谢我真的很喜欢这个解决方案。我不得不在否定检查中加上一个额外的括号,以使我所有的测试都通过。例如,HexToSignedInt(“7d”,2)如果((parseInt(num,16)&val.mask)>0){//否定这个解决方案总体上是很好的,但是对于那些会导致最小负值的值来说是失败的:(0x80,2)如果给出的是-128,而不是128,那么输入2的范围是从0x00到0xFF,应该从-128到127,其中0x00-7F是0-127,0x80-0xFF是从-128到-1
function HexToSignedInt(num, numSize) {
    var val = {
        mask: 0x8 * Math.pow(16, numSize-1), //  0x8000 if numSize = 4
        sub: -0x1 * Math.pow(16, numSize)    //-0x10000 if numSize = 4
    }
    if(parseInt(num, 16) & val.mask > 0) { //negative
        return (val.sub + parseInt(num, 16))
    }else {                                 //positive
        return (parseInt(num,16))
    }
 }
var numberToConvert = "CB8";
HexToSignedInt(numberToConvert, 3);
//expected output: -840
function toSignedInt(value, nBytes) { // 0 <= value < 2^nbytes*4, nBytes >= 1, 
  var hexMask = '0x80' + '00'.repeat(nBytes - 1);
  var intMask = parseInt(hexMask, 16);
  if (value >= intMask) {
    value = value - intMask * 2;
  }
  return value;
}

var vals = [       // expected output
  '0x00',          // 0
  '0xFF',          // 255
  '0xFFFFFF',      // 2^24 - 1 = 16777215
  '0x7FFFFFFF',    // 2^31 -1 = 2147483647
  '0x80000000',    // -2^31 = -2147483648
  '0x80000001',    // -2^31 + 1 = -2147483647
  '0xFFFFFFFF',    // -1
];
for (var hex of vals) {
  var num = parseInt(hex, 16);
  var result = toSignedInt(num, 4);
  console.log(hex, num, result);
}

var sampleInput = '0xffeb';
var sampleResult = toSignedInt(parseInt(sampleInput, 16), 2);
console.log(sampleInput, sampleResult); // "0xffeb", -21