有效地在JavaScript中添加十六进制字符串

时间:2014-04-25 11:34:39

标签: javascript math hex modular-arithmetic

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

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

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

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

另一方面,有一些限制会使事情变得更难:

  • 如上例所示,数字不是由四位数组成,而是由20位数组成。因此,您不能简单地将它们转换为十进制,添加它们并将它们转换回来。换句话说:对于JavaScript的number类型,这些数字太大了(这就是为什么this answer不起作用的原因。)
  • 不允许溢出。如果您添加'ffff''0001',则结果应为'0000',而不是'10000'。换句话说:所有计算都必须使用模除法。

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

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

PS:我需要在Node.js中这样做,所以如果有一个现成的模块可以做到这一点,我完全可以这样做: - )

2 个答案:

答案 0 :(得分: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,此代码似乎比上述代码快三倍,至少在某些浏览器上是这样。

答案 1 :(得分: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