LoginSignup
2
1

More than 3 years have passed since last update.

おれがコンピュータに足し算を教えてやろうと思ったらもう知ってた

Posted at
echo gmp_add(
    '2345760293460295683704558703456102394871348756109347501936410934756102913874187344541930193470934875',
    '7947618927365019364019257691823461928734634570193248703473987562093471093576293478628949398873429857'
); // 10293379220825315047723816395279564323605983326302596205410398496849574007450480823170879592344364732

はい。

まあ、これだけだとアレなので、GMPを使わずaddBigIntをもう少し簡単に書けないか検討してみることにします。

function addBigInt(string $a, string $b): string{
    $a = strrev($a);
    $b = strrev($b);

    $ret = '';
    for ($i = $c = 0;isset($a[$i]) || isset($b[$i]); $i++) {
        $tmp = ($a[$i] ?? 0) + ($b[$i] ?? 0) + $c;
        $c = $tmp > 9;
        $ret[$i] = $tmp % 10;
    }

    if ($c) {
        $ret[$i] = 1;
    }
    return strrev($ret);
}

とりあえず何も考えずに書いたらこんなかんじになりました。
単に1桁毎に順番に計算しているだけですね。

strrevが3回も入ってたりisset判定が残念な感じだったりif($c)とかわざわざ書いてたり微妙なのでどうにかしたいところです。

function addBigInt(string $a, string $b): string
{
    $i = max(strlen($a), strlen($b));
    $a = str_pad($a, $i, 0, STR_PAD_LEFT);
    $b = str_pad($b, $i, 0, STR_PAD_LEFT);
    $ret = '';

    for ($c = 0, $i--; $i >= 0; $i--) {
        $tmp = ($a[$i] ?? 0) + ($b[$i] ?? 0) + $c;
        $c = $tmp > 9;
        $ret[$i] = $tmp % 10;
    }

    if ($c) {
        return '1' . $ret;
    }
    return $ret;
}

strrevを消して逆順に計算することとし、また桁数を揃えることで毎回issetで条件判定せずに済むようにしました。
しかしstr_padのもっさり感と、if($c)がやっぱり消せないのが惜しいところです。

最終式

function addBigInt(string $a, string $b): string
{
    for($a=str_pad($a,$i=max(strlen($a),strlen($b),$c=0),0,0),$b=$r=str_pad($b,$i--,0,0);$i>=0;$c=($t=$a[$i]+$b[$i]+$c)>9,$r[$i--]=$t%10);return$c?'1'.$r:$r;
}

単に詰めただけです。
エラーを出さない条件では、このあたりが限界でした。

ちなみにエラーを許容するなら、strrevを使ったほうが短くなります。

エラー出る
function addBigInt(string $a, string $b): string
{
    for($f=strrev,$l=max(strlen($a=$f($a)),strlen($b=$r=$f($b)));$i<$l;$c=($t=$a[$i]+$b[$i]+$c)>9,$r[$i++]=$t%10);return($c?1:'').$f($r);
}

最終式の問題点

max(strlen($a))と入力値を元にした数値を使っているので、PHP_INT_MAX桁を超える文字列だと正常に動かなくなります。
その前にメモリとかが死にそうですが。

あと0未満の値は正しく計算できません。
これは元の関数からしてそうなので仕様としておきます。

感想

残った2カ所の,を消せないものか。
あれがあると結局単に複数の式を並べてるだけになるから、なんというかこう面白くないんだよね。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1