1

JavaScript には、それぞれ 16 進数を文字列として含む 2 つの変数があります。例えば:

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

今、私はそれらを追加したいです (したがって、結果は になるはずです'c0cb')。物事を少し簡単にするために、これにいくつかの制約を加えましょう:

  • 数値は常に同じ桁数で構成されます (つまり、文字列の長さは同じです)。
  • 0必要に応じて数字の前にs が付くため'001a'、 だけでなく になり'1a'ます。

一方で、物事を少し難しくする制約があります。

  • 数値は上の例のように 4 桁ではなく、20 桁です。したがって、単純に 10 進数に変換して加算し、元に戻すことはできません。つまり、数値が JavaScript のタイプに対して大きすぎます(これが、この回答が機能しないnumber理由です)。
  • オーバーフローは許されません。と を足す'ffff''0001'、結果は'0000'ではなくになり'10000'ます。つまり、すべての計算はモジュロ除算を使用して行う必要があります。

私は現在、これらすべてを解決するアルゴリズムを持っていますが、それは長く、あまり効率的ではなく、エレガントではありません。その考え方は、文字列を 1 文字ずつ調べて、それらを 10 進数に変換し、それらを追加し、それらを元に変換し、潜在的なオーバーフローを記憶することなどです。前述のように、それは完全に機能しますが、最善の解決策ではないと思います。

どうすればこれをより良い方法で解決できますか?

PS: Node.js でこれを行う必要があるため、これを行う既製のモジュールが利用可能であれば、これでまったく問題ありません :-)

4

2 に答える 2

2

最も単純なケースでは、キャリーを追跡しながら、一度に 1 桁ずつ追加できます。

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

パフォーマンスが問題になる場合は、一度に 1 桁以上を処理することをお勧めしますが、そうすると、処理が困難になるか、桁数をハードコーディングする必要があります。それでも、ゼロパディングには多少の作業が必要です。以下は、3 つのステップで 20 の 16 進数を処理するソリューションです。そのため、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によると、少なくとも一部のブラウザでは、このコードは上記のコードよりも 3 倍速いようです。

于 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 に答える