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カ所の,
を消せないものか。
あれがあると結局単に複数の式を並べてるだけになるから、なんというかこう面白くないんだよね。