3

JavaScriptで64ビット整数を加算または減算する簡単な方法(ライブラリではなく小さな関数を期待)はありますか?

例 64 ビット整数: 291270990346989568

背景: 私は 64 ビットのツイート ID を持つ Twitter API を使用しています。これらの ID に 1 を加算または減算して、Twitter から返される結果を操作したいと考えています。

4

2 に答える 2

2

次のコードは、あなたが説明したことを行います。

分割、加算、または減算、および再結合...

このコードには、インクリメント関数とデクリメント関数の両方と、いくつかのエッジ ケースを含むテスト関数があります。数値文字列を分割して計算する場合、「先頭のゼロ」がどうなるかを考慮する必要があるため、そのためのパディング関数があります。

JSFiddle にこのソリューションを提供してくれてありがとう、ジャスティン。

/*
 * Prepend zeros to expand a given string to given length
 *
 * @var {String} numStr Number
 * @var {Number} len    Length to pad out to
 *
 * @returns {String}
 */
function pad0 (numStr,len) {
  while (numStr.length < len) {
    numStr = "0" + numStr;
  }
  return numStr
}

/*
 * Decrement the given (64 bit) integer.
 *
 * @var {String} int64  Postive non-zero integer, as a string
 *
 * @returns {String}
 */
function decrInt64 (int64) {
  var result = "";
  var midpt = Math.floor(int64.length/2);
  var upper = int64.substring(0,midpt);
  var lower = int64.substring(midpt);
  var upperVal = new Number(upper);
  var lowerVal = new Number(lower);

  if (lowerVal == 0) {
    if (upperVal == 0) {
      // We don't support negative numbers
      result = "*ERROR*"
    }
    else {
      // borrow 1
      result = pad0((--upperVal).toString(),upper.length) +
               (new Number("1"+lower) - 1).toString();
    }
  }
  else {
    var newLower = (lowerVal - 1).toString();
    result = upper + pad0(newLower,lower.length);
  }
  alert(result);
}

/*
 * Increment the given (64 bit) integer.
 *
 * @var {String} int64  Postive, as a string
 *
 * @returns {String}
 */
function incrInt64 (int64) {
  var result = "";
  var midpt = Math.floor(int64.length/2);
  var upper = int64.substring(0,midpt);
  var lower = int64.substring(midpt);
  var upperVal = new Number(upper);
  var lowerVal = new Number(lower);

  var newLower = (++lowerVal).toString();
  // Did we overflow?
  if (lower.length < newLower.length) {
    // Yes, carry the 1
    result = (++upperVal).toString() + newLower.substring(1);
  }
  else {
    result = upper + pad0(newLower,lower.length);
  }
  alert(result);
}

// Test function
window.displaymessage= function ()
{
  decrInt64("291270990046989568");
  incrInt64("291270990046989568");
  decrInt64("000000000000000000");
  incrInt64("000000000000000000");
  decrInt64("000000001000000000");
  incrInt64("000000001000000000");
  decrInt64("099999999999999999");
  incrInt64("099999999999999999");
  decrInt64("999999999999999999");
  incrInt64("999999999999999999");
}
于 2013-01-15T23:41:48.767 に答える
1

長さが不定の整数形式の文字列(基数10)の追加は、文字列を9文字のセグメントに分割し、それを計算してから、前の9文字に移動することで実行できます。これは、最大の9文字の数値が32ビットセーフであるためです(減算で使用したように)。+-9999999991999999999

次のコードには3つの関数があり、整数という単語整数形式の文字列を意味すると想定されています。

  • addAsString、は2つの非負の整数xを取り、、yx + y
  • subtractAsString、は2つの非負の整数xを取りy、、、|x| >= |y|x - y
  • addORsub、任意の2つの整数xを取り、、をy返しますx + y

コード内のコメントで何が起こっているのかを説明しようとしました

// Indefinate length addition
function addAsString(x, y) { // x, y strings
    var s = '';
    if (y.length > x.length) { // always have x longer
        s = x;
        x = y;
        y = s;
    }
    s = (parseInt(x.slice(-9),10) + parseInt(y.slice(-9),10)).toString(); // add last 9 digits
    x = x.slice(0,-9); // cut off last 9 digits
    y = y.slice(0,-9);
    if (s.length > 9) { // if >= 10, add in the 1
        if (x === '') return s; // special case (e.g. 9+9=18)
        x = addAsString(x, '1');
        s = s.slice(1);
    } else if (x.length) { // if more recursions to go
        while (s.length < 9) { // make sure to pad with 0s
            s = '0' + s;
        }
    }
    if (y === '') return x + s; // if no more chars then done, return
    return addAsString(x, y) + s; // else recurse, next digit
}

// Indefinate length subtraction (x - y, |x| >= |y|)
function subtractAsString(x, y) {
    var s;
    s = (parseInt('1'+x.slice(-9),10) - parseInt(y.slice(-9),10)).toString(); // subtract last 9 digits
    x = x.slice(0,-9); // cut off last 9 digits
    y = y.slice(0,-9);
    if (s.length === 10 || x === '') { // didn't need to go mod 1000000000
        s = s.slice(1);
    } else { // went mod 1000000000, inc y
        if (y.length) { // only add if makes sense
            y = addAsString(y, '1');
        } else { // else set
            y = '1';
        }
        if (x.length) {
            while (s.length < 9) { // pad s
                s = '0' + s;
            }
        }
    }
    if (y === '') { // finished
        s = (x + s).replace(/^0+/,''); // dont return all 0s
        return s;
    }
    return subtractAsString(x, y) + s;
}

// Indefinate length addition or subtraction (via above)
function addORsub(x, y) {
    var s = '';
    x = x.replace(/^(-)?0+/,'$1').replace(/^-?$/,'0'); // -000001 = -1
    y = y.replace(/^(-)?0+/,'$1').replace(/^-?$/,'0'); // -000000 =  0
    if (x[0] === '-') { // x negative
        if (y[0] === '-') { // if y negative too
            return '-' + addAsString(x.slice(1), y.slice(1)); // return -(|x|+|y|)
        }
        return addORsub(y, x); // else swap
    }
    if (y[0] === '-') { // x positive, y negative
        s = y.slice(1);
        if (s.length < x.length || (s.length === x.length && s < x)) return subtractAsString(x, s) || '0'; // if |x|>|y|, return x-y
        if (s === x) return '0'; // equal then 0
        s = subtractAsString(s, x); // else |x|<|y|
        s = (s && '-' + s) || '0';
        return s; // return -(|y|-x)
    }
    return addAsString(x, y); // x, y positive, return x+y
}

使用例(フィドル

var i = addORsub('291270990346989568', '1'); // add
i === '291270990346989569';

i = addORsub('291270990346989568', '-1'); // subtract
i === '291270990346989567';
于 2013-01-15T22:10:00.103 に答える