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 -1
是0x7FFFFFFF
?
@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。如果提示要求您输入“未签名”,则范围为 0
到 2^32
,正如您最初假设的那样。
就您的失败测试而言,2147483651
比 2,147,483,647
大 4,因此您应该返回 0。相反,您应该说 reverseX > 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) < 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 位整数是啥?的主要内容,如果未能解决你的问题,请参考以下文章