web-dev-qa-db-ja.com

JavaScriptの32ビット整数とは何ですか?

コーディングの挑戦をしていましたが、あまり馴染みのないものに遭遇しました。それが何であるか、なぜそこにあるのかを知りたい。

プロンプトはとても簡単です:Given a 32-bit signed integer, reverse digits of an integer.

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

2番目の質問は、reverseXの値が2 ^ 32を超えると「予想」されますが、まだテストに失敗しています。

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

32ビット整数を超えたときに0を適切に返すにはどうすればよいですか?

19
Iggy

signed整数の上限は2ではありません32 -1、ただし231 -1、最初のビットは符号ビットであるため。

その比較を行うと、テストで正しい結果が得られることがわかります。

JavaScriptでは、数値が整数であっても IEEE-754浮動小数点 表現を使用することに注意してください。しかし、浮動小数点の精度は、32ビット整数で正確な計算を実行するには十分です。気づいたら、32ビットのオーバーフローを検出するために必要なテストを行う必要があります。

コードに関するいくつかの注意事項:引数を Array#reverse メソッドに渡します。これは引数をとらないメソッドです。ここに私がそれを書く方法があります-コードのコメントを見てください:

// 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));
23
trincot

しかし、私はいくつかの失敗したテストに困惑しています:

_Input:
1563847412
Output:
2147483651
Expected: 0
_

私が信じる最大32ビット整数は_(2^31)_で、2,147,483,647です。これは、32ビットの制限である_(-2^31)_と同様に負の値を格納できるようにするためです(これが「署名」の意味です)。したがって、それより大きな数値であれば、プログラムのために0を返すことができます。プロンプトで「符号なし」を要求された場合、範囲は最初に想定したように_0_〜_2^32_になります。

失敗したテストに関しては、_2147483651_は_2,147,483,647_より4大きいため、0を返す必要があります。代わりにreverseX > Math.pow(2,31) - 1と言う必要があります

JSでのその重要性は何ですか?また、始めた場合はどうなりますか? (2 ^ 32 + 1)

技術的には、JSではこの数に制限されません。JSは 仮数倍精度浮動小数点 数を使用します。したがって、実際の最大値は_(2^53) - 1_です

5
var reverse = function(x) {
  let ans;
  if (parseInt(x) < 0) {
    ans = parseInt(x.toString().split('').reverse().join('').toString()) * -1;
  } else {
    ans = parseInt(x.toString().split('').reverse().join('').toString());
  }
  if (ans < (Math.pow(2, 31) * -1) || ans > Math.pow(2, 31) - 1) return 0;
  return ans;
};
2
Arul Benito

これはうまくいく

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;
    };
0
venkat7668
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;
};
0
Daryl

ここにその質問に対する私の解決策があります。 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
};
0
ethanneff