【问题标题】:Add or Subtract From 64bit Integer in Javascript在 Javascript 中添加或减去 64 位整数
【发布时间】:2012-12-30 02:59:17
【问题描述】:

有没有一种简单的方法(希望是小函数,而不是库)在 JavaScript 中对 64 位整数进行加减运算?

64 位整数示例:291270990346989568

背景:我正在使用具有 64 位推文 ID 的 Twitter API。我想从这些 ID 中添加或减去一个,以操纵我从 Twitter 获得的结果。

【问题讨论】:

  • 你的意思是yournumber--;yournumber++;
  • 您必须将其拆分为两个 32 位整数;在(当前)JavaScript 291270990346989568 === 291270990346989600 中,您没有那么高的精度
  • @PaulS。我在想一些事情。拆分,加减,然后重新加入...数字存储为字符串,因此我也不需要 JS 将最终结果识别为 INT。但我真的不知道该怎么做。

标签: javascript 64-bit


【解决方案1】:

整数格式字符串(以 10 为底)的不定长度可以通过将字符串拆分为 9 个字符的段来完成,计算 + 或 @987654324 @ ,然后移动到前面的 9 个字符。这是因为最大的 9 个字符数 999999999 是 32 位安全的(就像我在减法中使用的 1999999999 一样)。

以下代码有 3 个函数,并且假设单词 integer 表示一个 整数格式的字符串

  • addAsString,接受两个非负整数xy,返回x + y
  • subtractAsString,接受两个非负整数xy|x| >= |y|,返回x - y
  • addORsub,接受 any 两个整数 xy,返回 x + y

我试图通过代码中的 cmets 来解释发生了什么

// 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
}

使用示例 (fiddle)

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

i = addORsub('291270990346989568', '-1'); // subtract
i === '291270990346989567';

【讨论】:

  • 我会用 parseInt(x,10) 切换你的演员表 (+)
  • @JohnJohnGa 是的。我也可以一次以 9 位为一组进行此操作.. 让我编辑
  • 那我怎么称呼它?只需拆分 INT 并将其传入?也许您可以在jsfiddle.net 中设置一个工作示例
  • @Justin 在示例使用中进行了编辑,如果 s 很短,则将其填充(在极少数情况下,例如 1000000000+1 会变成 11,现已修复)
  • @Justin 为它添加了更多代码。我知道它看起来很乱,可能会被清理掉,但这些函数现在支持任何长度的整数的加法和减法,addORsub 接受正数或负数(尝试我的小提琴与任何整数,过度杀伤)。跨度>
【解决方案2】:

以下代码执行您所描述的操作。

拆分,加减,然后重新加入...

此代码具有递增和递减函数,以及带有一些边缘情况的测试函数。在拆分数字字符串并对它们进行数学运算时,您需要考虑“前导零”会发生什么,因此有一个填充函数。

感谢贾斯汀提供JSFiddle with this solution

/*
 * 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");
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-28
    • 2014-02-10
    相关资源
    最近更新 更多