1

在 JavaScript 中,我有两个变量,每个变量都包含一个十六进制数字作为字符串。例如:

var a = 'a3bc',
    b = '1d0f';

现在我想添加它们(所以,结果应该是'c0cb')。为了让事情变得更容易一些,让我们对此进行一些限制:

  • 这些数字总是由相同数量的数字组成(即字符串的长度相同)。
  • 如有必要,数字会以 s 为前缀0,因此它将是'001a',而不仅仅是'1a'

另一方面,有一些限制让事情变得有点困难:

  • 这些数字不像上面的例子那样由四位数字组成,而是由 20 位数字组成。因此,您不能简单地将它们转换为十进制,将它们相加,然后再将它们转换回来。换句话说:对于 JavaScript 的number类型来说,数字太大了(这就是这个答案不起作用的原因)。
  • 不允许溢出。如果加上'ffff'and '0001',结果应该是'0000', not '10000'。换句话说:所有计算都必须使用模除法。

我目前有一个算法可以解决所有这些问题,但它很长,效率不高,而且一切都很优雅。它的想法是逐个字符地遍历字符串,将它们转换为十进制,添加它们,将它们转换回来,记住潜在的溢出等等。如前所述,它工作得很好,但我认为这不是最好的解决方案。

我怎样才能以更好的方式解决这个问题?

PS:我需要在 Node.js 中执行此操作,因此如果有可用的现成模块可以执行此操作,我对此非常满意 :-)

4

2 回答 2

2

在最简单的情况下,您可以一次添加一个数字,跟踪进位:

var ndigits = 4, i, carry = 0, d, result = "";
for (i = ndigits - 1; i >= 0; i--) {
  d = parseInt(a[i], 16) + parseInt(b[i], 16) + carry;
  carry = d >> 4;
  result = (d & 15).toString(16) + result;
}

如果性能是一个问题,您可能更喜欢一次处理多个数字,但是事情变得很困难,或者您必须对位数进行硬编码。即使那样,零填充的东西也需要一些工作。这是一个解决方案,它分三步处理 20 个十六进制数字,因此没有一个数字长度超过 32 位:

function pad(s, n) { while (s.length < n) s = "0" + s; return s; }
d = parseInt(a.substr(13), 16) + parseInt(b.substr(13), 16);
result = pad((d & 0xfffffff).toString(16), 7);
d = parseInt(a.substr(6, 7), 16) + parseInt(b.substr(6, 7), 16) + (d >> 28);
result = pad((d & 0xfffffff).toString(16), 7) + result;
d = parseInt(a.substr(0, 6), 16) + parseInt(b.substr(0, 6), 16) + (d >> 28);
result = pad((d & 0xffffff).toString(16), 6) + result;

根据jsPerf,这段代码似乎比上面的代码快三倍,至少在某些浏览器上是这样。

于 2014-04-25T12:29:25.113 回答
0

很高兴看到您已经拥有什么,但您可以使用BigNumber等任意算术库。

Javascript

require.config({
    paths: {
        bignumber: 'https://raw.githubusercontent.com/MikeMcl/bignumber.js/master/bignumber.min'
    }
});

require(['bignumber'], function (BigNumber) {
    function sumHex() {
        var args = [].slice.call(arguments),
            length = args.length,
            sum = new BigNumber(0, 16),
            index;

        for (index = 0; index < length; index += 1) {
            sum = sum.plus(args[index], 16).mod('100000000000000000000', 16);
        }

        sum = sum.toString(16);
        while (sum.length < 20) {
            sum = '0' + sum;
        }

        return sum;
    }

    var a = '0000000000000000a3bc',
        b = '00000000000000001d0f';

    console.log(sumHex(a, b));

    a = 'ffffffffffffffffffff';
    b = '00000000000000000001';
    console.log(sumHex(a, b));
});

输出

0000000000000000c0cb
00000000000000000000

jsFiddle 上

于 2014-04-25T12:34:04.113 回答