• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • bcmul()

    (PHP 4, PHP 5, PHP 7)

    2个任意精度数字乘法计算

    说明

    bcmul(string $left_operand,string $right_operand[,int $scale= int]): string

    左操作数乘以右操作数

    参数

    $left_operand

    字符串类型的左操作数.

    $right_operand

    字符串类型的右操作数.

    $scale

    此可选参数用于设置结果中小数点后的小数位数。也可通过使用bcscale()来设置全局默认的小数位数,用于所有函数。

    返回值

    返回结果为字符串类型.

    范例

    bcmul()示例

    <?php
    echo bcmul('1.34747474747', '35', 3); // 47.161
    echo bcmul('2', '4'); // 8
    ?>
    

    参见

    • bcdiv()2个任意精度的数字除法计算
    When using printf to print the results of bcmath operations, use string format, i.e. '%s', not numeric formats such as '%d' or '%f'. For example, the output of factorial (23) will be incorrect if using %d or %f:
    Result using %f:
    factorial (22) = 1124000727777607680000 (correct)
    factorial (23) = 25852016738884978212864 (incorrect)
    Result using %s:
    factorial (22) = 1124000727777607680000
    factorial (23) = 25852016738884976640000
    Using echo, this is not a problem - PHP will output the bcmath string type correctly.
    I made this to multiply an unlimited size of integers together (meaning no decimals)..
    This could be useful for those without the BCMath extension.
    <?php
    function Mul($Num1='0',$Num2='0') {
     // check if they're both plain numbers
     if(!preg_match("/^\d+$/",$Num1)||!preg_match("/^\d+$/",$Num2)) return(0);
     // remove zeroes from beginning of numbers
     for($i=0;$i<strlen($Num1);$i++) if(@$Num1{$i}!='0') {$Num1=substr($Num1,$i);break;}
     for($i=0;$i<strlen($Num2);$i++) if(@$Num2{$i}!='0') {$Num2=substr($Num2,$i);break;}
     // get both number lengths
     $Len1=strlen($Num1);
     $Len2=strlen($Num2);
     // $Rema is for storing the calculated numbers and $Rema2 is for carrying the remainders
     $Rema=$Rema2=array();
     // we start by making a $Len1 by $Len2 table (array)
     for($y=$i=0;$y<$Len1;$y++)
      for($x=0;$x<$Len2;$x++)
       // we use the classic lattice method for calculating the multiplication..
       // this will multiply each number in $Num1 with each number in $Num2 and store it accordingly
       @$Rema[$i++%$Len2].=sprintf('%02d',(int)$Num1{$y}*(int)$Num2{$x});
     // cycle through each stored number
     for($y=0;$y<$Len2;$y++)
      for($x=0;$x<$Len1*2;$x++)
       // add up the numbers in the diagonal fashion the lattice method uses
       @$Rema2[Floor(($x-1)/2)+1+$y]+=(int)$Rema[$y]{$x};
     // reverse the results around
     $Rema2=array_reverse($Rema2);
     // cycle through all the results again
     for($i=0;$i<count($Rema2);$i++) {
      // reverse this item, split, keep the first digit, spread the other digits down the array
      $Rema3=str_split(strrev($Rema2[$i]));
      for($o=0;$o<count($Rema3);$o++)
       if($o==0) @$Rema2[$i+$o]=$Rema3[$o];
       else @$Rema2[$i+$o]+=$Rema3[$o];
     }
     // implode $Rema2 so it's a string and reverse it, this is the result!
     $Rema2=strrev(implode($Rema2));
     // just to make sure, we delete the zeros from the beginning of the result and return
     while(strlen($Rema2)>1&&$Rema2{0}=='0') $Rema2=substr($Rema2,1);
     return($Rema2);
    }
    $A='5650175242508133742';
    $B='2361030539975818701734615584174625';
    printf(" Mul(%s,%s); // %s\r\n",$A,$B, Mul($A,$B));
    printf("BCMul(%s,%s); // %s\r\n",$A,$B,BCMul($A,$B)); // build-in function
    /*
     This will print something similar to this..
      Mul(5650175242508133742,2361030539975818701734615584174625);
     BCMul(5650175242508133742,2361030539975818701734615584174625);
     both of which should be followed by the answer:
     13340236303776981390475700774516825287352418182696750
    */
    ?>
    It was a fun experience making.. even though this took me longer than the BCAdd alternative I did..
    Memory allocation might be an issue for rediculously larger numbers though.. if someone wants to benchmark the performance of my function; feel free.
    Enjoy,
    Nitrogen.
    $float = 0.31234144143341;
    $float1 = 0.00000000000000000000000000000005;
    echo $float, "\n";
    //0.31234144143341
    echo $float1, "\n";
    //5.0E-32
    echo $float*$float1, "\n";
    //1.5617072071671E-32
    <?php
    /*bcmul read float as string*/
    echo bcmul($float, $float1, 32),"\n";
    //0
    echo bcmul($float, sprint('%.32f',$float1), 32);
    //0.000000000000000000000000000000015617072071671;
    ?>
    
    Well, I have a little problem implementing Blake Hash in my server because it is not a x64 server machine. I made a little function that use the powerfull of BC library to do the bitwise operation Shift.
    <?php
    echo 'Left Shift test<br />';
    bprint('1', decbin(1));
    bprint('1 << 32 (Fail)', decbin(1 << 32)); //Fail, operation not succesfull in 32-bit machine
    bprint('shiftleft(1, 32) (Success)', dec2bin(shiftleft('1', '32'))); //decbin fails, so we use personalized function, success
    echo '<br />';
    echo 'Right Shift test<br />';
    bprint('9223372036854775808', dec2bin('9223372036854775808'));
    bprint('9223372036854775808 >> 63 (Fail)', decbin(9223372036854775808 >> 63));
    bprint('rightshift(9223372036854775808, 63) (Success)', decbin(rightshift('9223372036854775808', '63')));
    function shiftleft($num, $bits) {
      return bcmul($num, bcpow('2', $bits));
    }
    function rightshift($num, $bits) {
      return bcdiv($num, bcpow('2', $bits));
    }
    function bprint($title, $content) {
      echo $title . '<br />' . str_pad($content, 64, '0', STR_PAD_LEFT) . '<br />' . PHP_EOL;
    }
    //http://www.php.net/manual/en/function.decbin.php#99533
    function dec2bin($dec) {
      // Better function for dec to bin. Support much bigger values, but doesn’t support signs
      for ($b = '', $r = $dec; $r >1;) {
        $n = floor($r / 2);
        $b = ($r - $n * 2) . $b;
        $r = $n; // $r%2 is inaccurate when using bigger values (like 11.435.168.214)!
      }
      return ($r % 2) . $b;
    }
    ?>
    

    上篇:bcmod()

    下篇:bcpow()