JavaScript 中的 32 位整数是啥?

Posted

技术标签:

【中文标题】JavaScript 中的 32 位整数是啥?【英文标题】:What is 32-bit integer in JavaScript?JavaScript 中的 32 位整数是什么? 【发布时间】:2018-05-15 22:54:57 【问题描述】:

我在做一些编码挑战,遇到了一些我不太熟悉的东西。我更想知道它是什么以及它为什么存在。

提示很简单:

给定一个 32 位有符号整数,反转整数的数字。

Example:
Input: -123
Output: -321

Example:    
Input: 120
Output: 21

Assume we are dealing with an environment which could only hold integers within the 32-bit signed integer range. For the purpose of this problem, assume that your function returns 0 when the reversed integer overflows.

我想出了这个。

var reverse = function(x) 
    var isNegative = false;
    if(x < 0)
        isNegative = true;
        x *= -1;
    ;
    var reverseX = parseInt(String(x).split('').reverse((a,b) => a - b).join(''));
    if(reverseX > Math.pow(2,32))
      return 0;
    
    if(isNegative)
        return -1 * reverseX
     else 
        return reverseX;
    
;

但是,我对一些失败的测试感到困惑:

Input:
1563847412
Output:
2147483651
Expected: 0

据我了解,32 位整数是 2^32。它在 JS 中的意义是什么?如果我开始复习会发生什么? (2^32 + 1)

如果我可以问两个,我的第二个问题是,如果 reverseX 的值超过 2^32,我是否“预期”,但它仍然未通过测试。

if (reverseX > Math.pow(2, 32)) 
  return 0;

当我超过 32 位整数时,如何正确返回 0

【问题讨论】:

整数溢出:xkcd.com/571 改变 Math.pow(2, 32) 应该是 Math.pow(2, 31) -1 【参考方案1】:

有符号整数的上界不是 232 - 1,而是 231 - 1,因为第一位是符号位。

如果你进行比较,你会看到你的测试给出了正确的结果。

请注意,javascript 使用IEEE-754 floating point 表示数字,即使它们是整数。但是浮点的精度足以对 32 位整数进行精确计算。正如您所意识到的,您需要进行必要的测试来检测 32 位溢出。

关于您的代码的一些注意事项:它将参数传递给Array#reverse 方法,该方法不带参数。以下是我的写法——见代码中的 cmets:

// Name argument n instead of x, as that latter is commonly used for decimal numbers 
function reverse(n) 
    // Array#reverse method takes no argument.
    // You can use `Math.abs()` instead of changing the sign if negative.
    // Conversion of string to number can be done with unary plus operator.
    var reverseN = +String(Math.abs(n)).split('').reverse().join('');
    // Use a number constant instead of calculating the power
    if (reverseN > 0x7FFFFFFF) 
        return 0;
    
    // As we did not change the sign, you can do without the boolean isNegative.
    // Don't multiply with -1, just use the unary minus operator.
    // The ternary operator might interest you as well (you could even use it
    //    to combine the above return into one return statement)
    return n < 0 ? -reverseN : reverseN;


console.log(reverse(-123));
console.log(reverse(1563847412));

更高效

与简单的算术运算相比,转换为字符串、拆分和连接是相对昂贵的操作。因此,解决这样的问题会更节省时间(和内存):

function reverse(n) 
    var reverseN = 0;
    var sign = n < 0;
    n = Math.abs(n);
    while (n) 
        reverseN = reverseN*10 + (n % 10);
        n = Math.floor(n/10);
    
    return reverseN > 0x7FFFFFFF ? 0 : sign ? -reverseN : reverseN;


console.log(reverse(-123));
console.log(reverse(1563847412));

【讨论】:

对您的回答表示敬意:运行时间:84 毫秒,比 83.91% 的反向整数 JavaScript 在线提交要快。内存使用:35.9 MB,不到 56.21% 的反向整数 JavaScript 在线提交。 谢谢你,@Viet!答案并不是真正关注效率,而是解决 OP 遇到的问题。既然您提到了空间和时间效率,我在答案中添加了一个更有效的变体。 谢谢!你怎么知道2^31 -10x7FFFFFFF @vbarinov,二进制表示中的 2^31 是 1 后跟 31 个零(就像十进制中的 10^6 是 1 后跟 6 个零)。每组 4 个二进制数字(从右开始)是一个十六进制数字,所以 2^31 是 0x80000000。然后减一... OP 从来没有提到过 leetcode,也没有提到这个要求。无论如何,所有要求都应该在问题中。 OP 不能假设我们知道他们正在处理 leetcode 挑战,并且我们应该阅读场外内容以完全理解这个问题。我们应该只考虑问题中存在的规范以及 OP 的特定问题。【参考方案2】:

但是,我对一些失败的测试感到困惑:

Input:
1563847412
Output:
2147483651
Expected: 0

我认为最大的 32 位整数是 (2^31),即 2,147,483,647。这样一来,也可以存储负值 (-2^31) 是 32 位限制(这就是“签名”的意思)。因此,任何高于此的数字,为了您的程序,您都可以返回 0。如果提示要求您输入“未签名”,则范围为 02^32,正如您最初假设的那样。

就您的失败测试而言,21474836512,147,483,647 大 4,因此您应该返回 0。相反,您应该说 reverseX &gt; Math.pow(2,31) - 1

它在 JS 中的意义是什么?如果我开始复习会发生什么? (2^32 + 1)

从技术上讲,在 JS 中你不受这个数字的限制,JS 使用 significand double-precision floating point 数字。所以最大值其实是(2^53) - 1

【讨论】:

奇怪的是 2^31 应该是奇数。【参考方案3】:

这是我对该问题的解决方案。我不推荐 split().join() 方法,因为它大大增加了时间和空间的复杂性。

// 0(n)
var reverse = function(x) 
  var reverse = 0
  var isNegative = x < 0 ? -1 : 1
  x = x * isNegative

  // capture single digits
  if (x / 10 < 1) 
    return x
  

  // reverse
  while (x >= 1) 
    var diff = parseInt(x % 10)
    reverse = (reverse * 10) + diff
    x = x / 10
  

  // capture greater than 32bit
  if (reverse > Math.pow(2,31)-1) 
    return 0;
  

  // capture negative
  return reverse * isNegative
;

【讨论】:

【参考方案4】:

这很好用

var reverse = function(x) 
        let num = Math.abs(x);
        let result = 0;
        let rem;
        while(num>0)
            rem = num % 10;
            result = result * 10 + rem;
            num = Math.floor(num/10);
        
        if(0x7FFFFFFF < result) return 0
        if(x < 0) return result * -1;
        return result;
    ;

【讨论】:

【参考方案5】:

var reverse = function(x) 
  let ans = parseInt(x.toString().split('').reverse().join('').toString());

  if (x < 0)  ans *= -1; 

  if (ans < (Math.pow(2, 31) * -1) || ans > Math.pow(2, 31) - 1) return 0;
  return ans;
;

console.log("Reverse of 123: " + reverse(123));
console.log("Reverse of -123: " + reverse(-123));

【讨论】:

在与 OP 的问题相关的地方添加两行描述,将为以后访问此答案的每个人提供更广泛的背景。 我会把最后两行合并成一个像这样return (Math.abs(Math.pow(2, 31) - 1) &lt; ans) ? 0 : ans【参考方案6】:
const reverse = x => 
    let possible = x.toString().split('').reverse();
    let temp, sign, overflow;
    if(Number.isNaN(parseInt(possible[possible.length -1]))) 
      sign = possible.pop();
       
    temp = parseInt(possible.join(''));
    overflow = temp > 2**31-1;
    if(sign) 
        if(!overflow) 
            return temp*-1;
        
     else 
        if(!overflow)
           return temp;   
            
    
    return 0;
;

【讨论】:

【参考方案7】:
var reverse = function(x) 
    let isNegative = x < 0 ? -1 : 1    
    x = x * isNegative
    const split = `$x`.split(``)
    if(split && split.length)
        let reversedInteger = ``
        for(let i=1;i<= split.length;i++) 
             reversedInteger = reversedInteger + split[(split.length)-i]
        
         if (reversedInteger > Math.pow(2,31)-1) 
             return 0;
         
        return parseInt(reversedInteger*isNegative)
    
;

运行时间:72 毫秒,比 82.67% 的反向整数 JavaScript 在线提交要快。 内存使用:36 MB,不到 28.12% 的反向整数 JavaScript 在线提交。

【讨论】:

【参考方案8】:
function reverse(x) 
    let strArr = x.toString().split('');
    let initialString = '';
    for (let i = strArr.length - 1; i >= 0; i--) 
        initialString += strArr[i];
    
    if (parseInt(initialString) > Math.pow(2, 31) - 1 || parseInt(initialString) < Math.pow(-2, 31)) 
        return 0;
     else if (x < 0) 
        return -parseInt(initialString);
     else 
        return parseInt(initialString);
    

【讨论】:

【参考方案9】:
var reverse = function(x) 
     let reversed = parseInt(Array.from(`$Math.sign(x) * x`).reverse().join(''));
     return Math.sign(x)*(reversed > 0x7FFFFFFF?0:reversed);
    
;

运行时间:96 毫秒,比 73.30% 的 JavaScript 在线提交要快 对于反向整数。内存使用:40.4 MB,不到 38.77% 反向整数的 JavaScript 在线提交。

虽然不是最佳的空间和时间复杂度。

【讨论】:

【参考方案10】:

已经晚了,但还是想给出答案。

   var reverse = function(x) 
   let rev =  parseInt(x.toString().split('').reverse().join(''));

    if(rev > Math.pow(2, 31))
     return 0;
    
     else        
      return rev*Math.sign(x);
        
   

运行时间:88 毫秒,比 95.55% 的反向整数 JavaScript 在线提交要快。 内存使用:40 MB,不到 88.15% 的反向整数 JavaScript 在线提交。

【讨论】:

【参考方案11】:
var reverse = function(x) 
    var reverseX = parseInt(x.toString().split('').reverse().join(''));
    if (reverseX < (Math.pow(2, 31) * -1) || reverseX > Math.pow(2, 31) - 1) return 0;
    return reverseX* Math.sign(x);
    
;

先将x转成字符串,用''分割,得到数组。

稍后使用数组的reverse()函数来反转数组的元素

使用 join('') 函数再次加入之后 现在,检查如果反转 reverseX 导致值超出有符号的 32 位整数范围 [-231, 231 - 1],则返回 0。

if (reverseX Math.pow(2, 31) - 1) 返回 0;

【讨论】:

请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常更有帮助、质量更好,并且更有可能吸引投票。【参考方案12】:

我已经尝试过这个解决方案。它有 运行时间:84 毫秒,比用于 Reverse Integer 的 98.31% 的 JavaScript 在线提交要快。在 Leetcode 上。

var reverse = function(x) 
let minus = false;
    x < 0 ? minus=true : minus=false;
    let reverse = parseInt(x.toString().split("").reverse().join(''));
    if (reverse > Math.pow(2,31) - 1) 
        return 0;
    
    if(minus)
      return parseInt(`-$reverse`)
    
    return reverse
;

【讨论】:

【参考方案13】:

这是我的解决方案

 var reverse = function(x) 


    rev_string = x.toString()
    strArray = rev_string.split("")
    revArray = strArray.reverse()
    new_str =  revArray.join("")

    if (parseInt(new_str) < (Math.pow(2, 31) * -1) || parseInt(new_str) > Math.pow(2,31) - 1) 
         new_str = 0;
    
    if (Math.sign(x) === -1) 
    
       new_str = parseInt(new_str) * Math.sign(x);
    


  return new_str;
  ;

【讨论】:

【参考方案14】:

这就是我的做法。

var reverse = function(x) 
    let negative = x < 0;
    x = parseInt(String(Math.abs(x)).split("").reverse().join(""));
    return x > 0x7FFFFFFF ? 0 : negative ? -x : x;
;

【讨论】:

【参考方案15】:

不幸的是,到目前为止发布的所有解决方案(可能this one 除外)都不正确!包括目前accepted solution。这就是原因。

32 位整数的范围从 -2147483648 (-2^31) 到 2147483647 (2^31 − 1)

因此,如果我们传入 reverse 函数

-8463847412 - 我们应该得到-2147483648(仍在范围内),但在此处发布的大多数解决方案中,我们得到0,这是错误的! 8463847412 - 我们应该得到0。此处发布的一些解决方案未能解决此问题,而是显示2147483648,它高于最大 32 位整数限制。

这是我的解决方案,也许不是最优雅的,但肯定是最准确的

// feel free to use exact values here to optimize performance
const minIntegerNumber = Math.pow(-2, 31) // -2147483648
const maxIntegerNumber = Math.pow(2, 31) - 1 // 2147483647

function reverse(x: number): number 
  const reversedCharacters = x.toString().split('').reverse().join('')
  if (x < 0) 
    const result = Number(`-$reversedCharacters.slice(0, reversedCharacters.length - 1)`)
    return result < minIntegerNumber ? 0 : result
   else 
    const result = Number(reversedCharacters)
    return result > maxIntegerNumber ? 0 : result
  

【讨论】:

【参考方案16】:

我是带着这个来的。不如其他一些答案好,但它有效。

    function reverse(x) 
        if(x>0)
            x=x.toString();
            var v=1;    
        
        else
            x= -1*x;
            x= x.toString();
            var v=-1;
        
        var newArr = [];
        for(var i=x.length-1;i>=0;i--)
            var index = x.length-1-i;
            newArr[index]=x[i];
        
        var result = parseInt(newArr.join('')*v);
        if(result <=2147483647 && result >= -2147483647)
            return result
        
        else
            return 0
        
    ;

【讨论】:

以上是关于JavaScript 中的 32 位整数是啥?的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript学习笔记四:基本概念

c语言NULL是啥意思?

C语言中的unsigned int是啥

JavaScript位运算符

JavaScriptJavaScript位操作符

javascript运算符——位运算符