<?php
function makeSameLen(&$num1, &$num2){
   $len1 = strlen($num1);
   $len2 = strlen($num2);
   if($len1 < $len2){
       for($i = 0; $i < $len2 - $len1; $i++){
           $num1 = '0'.$num1;
       }
       return $len2;
   }else if($len1 > $len2){
       for($i = 0; $i < $len1 - $len2; $i++){
           $num2 = '0'.$num2;
       }
       return $len1;
   }else{
       return $len1;
   }
}

function minusString($num1, $num2) {
   $result = [];
   $len1 = strlen($num1);
   $len2 = strlen($num2);
   if($num1 == $num2){
       return '0';
   }
   $positive = true;
   if($len1 < $len2 || ($len1 == $len2 && $num1 < $num2)){
       $positive = false;
       //交换使 num1 > num2
       $tmp = $num1;
       $num1 = $num2;
       $num2 = $tmp;
       $temp = $len1;
       $len1 = $len2;
       $len2 = $temp;
   }
   $i = $len1 - 1;
   $j = $len2 - 1;
   $carray = 0;
   //从低位到高位对位做减法
   while($i >= 0 || $j >= 0){
       $a = $i >= 0 ? $num1[$i] : 0;
       $b = $j >= 0 ? $num2[$j] : 0;
       $sum = $a - $b + $carray;
       $carray = 0;
       //不够减
       if($sum < 0){
           $sum += 10;
           $carray = -1;
       }
       $result[] = $sum;
       $i--;
       $j--;
   }
   //删除前导0
   $result = array_reverse($result);
   $result = implode('', $result);
   $result = ltrim($result, 0);
   $result = $positive ? $result : '-'.$result;
   return strval($result);
}

function addString($num1, $num2){
   $result = [];
   $len1 = strlen($num1);
   $len2 = strlen($num2);
   if($len1 == 0){
       return $num2;
   }
   if($len2 == 0){
       return $num1;
   }
   $i = $len1 - 1;
   $j = $len2 - 1;
   $carry = 0;
   //倒序相加
   while($i >= 0 || $j >= 0 || $carry > 0){
       $a = $i >= 0 ? $num1[$i] : 0;
       $b = $j >= 0 ? $num2[$j] : 0;
       //按位相加并加上进位
       $sum = $a + $b + $carry;
       //进位
       $carry = intval($sum / 10);
       $result[] = $sum % 10;
       $i--;
       $j--;
   }
   $result = array_reverse($result);
   $result = implode('', $result);
   return strval($result);
}

//左移
function shiftString($num, $len){
   if($num == '0'){
       return $num;
   }
   for($i = 0; $i < $len; $i++){
       $num .= '0';
   }
   return strval($num);
}

//Karatsuba快速相乘算法
function karatsubaMultiply($num1, $num2){
   $len = MakeSameLen($num1,$num2);
   if($len == 0){
       return 0;
   }
   if($len == 1){
       return strval($num1[0] * $num2[0]);
   }
   $mid = intval($len / 2);
   $m = $len - $mid;
   $x1 = substr($num1,0, $mid);
   $x0 = substr($num1, $mid, $m);
   $y1 = substr($num2,0, $mid);
   $y0 = substr($num2,$mid, $m);
   $z0 = karatsubaMultiply($x0, $y0);
   $z1 = karatsubaMultiply(addString($x1, $x0), addString($y1, $y0));
   $z2 = karatsubaMultiply($x1, $y1);
   // (z2*10^(2*m))+((z1-z2-z0)*10^(m))+(z0)
   // z2*10^(2*m)
   $r1 = shiftString($z2,2 * $m);
   // (z1-z2-z0)*10^(m)
   $z1MinusZ2 = minusString($z1, $z2);
   $z1MinusZ2MinusZ0 = minusString($z1MinusZ2, $z0);
   $r2 = shiftString($z1MinusZ2MinusZ0, $m);
   $result = addString(addString($r1, $r2), $z0);
   return strval($result);
}

$num1 = '123';
$num2 = '5678';
$result = karatsubaMultiply($num1, $num2);
echo $num1.' * '.$num2.' = '.$result.PHP_EOL;