以字符串的形式完成加法和乘法运算

问题描述和思路:当运算的数字过大时,会溢出范围,导致最后的结果出错。

PHP种整型数的字长和平台有关,32 位平台下的最大值通常最大值是大约二十亿,64 位平台下的最大值通常是大约 9E18。在PHP中,当数字超出整型范围时,会自动将其转换为浮点型,浮点数的字长和平台相关,通常最大值是 1.8e308 并具有 14 位十进制数字的精度。在本题中,虽然范围是在浮点数内的,但是精度却不足了,所以需要用别的方法来实现大数的运算,在这里我们可以使用字符串来实现。

直接运算——精度不足

//用字符串的形式实现数的乘法运算,是我们所熟悉的垂直乘法运算

function multiply(string $a, string $b): string {

  $lenA = strlen($a);

  $lenB = strlen($b);

  $result = '0';

  for ($inxA = $lenA - 1; $inxA >= 0; --$inxA) {

      $re = '';

      //补0操作,相当于位往前进一位,然后乘上10

      for ($i = $inxA + 1; $i < $lenA; ++$i) {

          $re = "0" . $re;

      }

      $j = 0;

      for ($inxB = $lenB - 1; $inxB >= 0; --$inxB) {

          //每一位乘法运算的结果

          $mul = $a[$inxA] * $b[$inxB] + $j;

          //进位

          if ($mul > 9) {

              $j = floor($mul / 10);

              $mul = $mul - $j * 10;

          } else {

              $j = 0;

          }

          $re = $mul . $re;

      }

      if ($j > 0) $re = $j . $re;

      $result = add($result, $re);

  }

  //去除字符串首的0

  if($result != '0') $result = preg_replace('/^0+/','',$result);

  return $result;

}

//用字符串的形式实现数的加法运算

function add($a, $b) {

    $j = 0;

    $re = '';

    for ($inxA = strlen($a) - 1, $inxB = strlen($b) - 1; ($inxA >= 0 || $inxB >= 0); --$inxA, --$inxB) {

        $itemA = $a[$inxA];

        $itemB = $b[$inxB];

        $sum = $itemA + $itemB + $j;

        //进位,因为是加法,所以进位最多为1

        if ($sum > 9) {

            $j = 1;

            $sum = $sum - 10;

        } else {

            $j = 0;

        }

        $re = (string)$sum . $re;

    }

    if ($j > 0) $re = (string)$j . $re;

    return $re;

}

虽然功能是实现了,但是还是离大佬的水平相差甚远呀。还是看看大佬的代码学习学习吧!

function multiply(string $a, string $b): string {

  //移除左侧无效的0,然后分割成数组,再反序。

  $a = array_reverse(str_split(ltrim($a, '0')));

  $b = array_reverse(str_split(ltrim($b, '0')));

  $r = [];

  foreach ($a as $ai => $av) {

    foreach ($b as $bi => $bv) {

      //两个数的每一位相乘,再存放至数组当中,这里以两数的位之和为键

      $m = $av * $bv;

      $r[$ai + $bi] += $m;

      //进位操作

      if ($r[$ai + $bi] >= 10) {

        $r[$ai + $bi + 1] += floor($r[$ai + $bi] / 10);

        $r[$ai + $bi] = $r[$ai + $bi] % 10;

      }

    }

  }

  //最后以字符串的形式输出

  return implode('', array_reverse($r));

}

function multiply(string $a, string $b): string {

  $result = array_fill(0, '0', strlen($a) + strlen($b));

  //反转字符串

  $a = strrev($a);

  $b = strrev($b);

  for ($i = 0; $i < strlen($a); $i++) {

    for ($j = 0; $j < strlen($b); $j++) {

      //计算每位乘法运算的结果和进位

      $tmp = $a[$i] * $b[$j] + $result[$i + $j];

      $result[$i + $j] = $tmp % 10;

      $result[$i + $j + 1] += floor($tmp / 10);

    }

  }

  //去掉字符串首的无效0字符

  return preg_replace('/^0+\B/', '', strrev(join($result)));

}

上面两个大佬写的思想是一样的,都是垂直乘法的实现,优化点在于使用了数组来存放每一位的运算结果,最后再拼接成字符串输出。这里都是先反转再运算,虽然这么做与我们自己笔算时从低位开始算不同,但是能够防止数组下标越界,是种更好的办法。

另外,如果你有兴趣,或者是有问题想要与我探讨,欢迎来访问我的博客:https:mu-mu.cn/blog

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。