bcmul

(PHP 4, PHP 5, PHP 7, PHP 8)

bcmul β€” Π£ΠΌΠ½ΠΎΠΆΠ°Π΅Ρ‚ Π΄Π²Π° числа ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ»ΡŒΠ½ΠΎΠΉ точности

ОписаниС

function bcmul(string $num1, string $num2, ?int $scale = null): string

Ѐункция ΡƒΠΌΠ½ΠΎΠΆΠ°Π΅Ρ‚ число num1 Π½Π° число num2.

Бписок ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ²

num1

Π›Π΅Π²Ρ‹ΠΉ ΠΎΠΏΠ΅Ρ€Π°Π½Π΄ (слагаСмоС) Π² Π²ΠΈΠ΄Π΅ строки.

num2

ΠŸΡ€Π°Π²Ρ‹ΠΉ ΠΎΠΏΠ΅Ρ€Π°Π½Π΄ (слагаСмоС) Π² Π²ΠΈΠ΄Π΅ строки.

scale
ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для установки количСства Ρ†ΠΈΡ„Ρ€ послС дСсятичного Π·Π½Π°ΠΊΠ° Π² Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π΅. Если установлСно Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ null, Ρ‚ΠΎ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ Π±ΡƒΠ΄Π΅Ρ‚ установлСн ΠΌΠ°ΡΡˆΡ‚Π°Π± ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ, Π·Π°Π΄Π°Π½Π½Ρ‹ΠΉ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ bcscale() ΠΈΠ»ΠΈ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ INI-Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΈΠ²Ρ‹ bcmath.scale.

Π’ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌΡ‹Π΅ значСния

Ѐункция Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ Π² Π²ΠΈΠ΄Π΅ строки.

Ошибки

Ѐункция выбрасываСт ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ValueError Π² ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΡ… случаях:

  • Π—Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π° num1 ΠΈΠ»ΠΈ num2 оказалось строкой, ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ сформировали Π½Π΅ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎ с Ρ‚ΠΎΡ‡ΠΊΠΈ зрСния допустимого Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π° числовых строк Π² ΠΌΠΎΠ΄ΡƒΠ»Π΅ BCMath.
  • Π—Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π° scale Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΡ‚ Π·Π° ΠΏΡ€Π΅Π΄Π΅Π»Ρ‹ допустимого Π΄ΠΈΠ°ΠΏΠ°Π·ΠΎΠ½Π°.

Бписок измСнСний

ВСрсия ОписаниС
8.0.0 ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ scale Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ null.
7.3.0 Π’Π΅ΠΏΠ΅Ρ€ΡŒ функция bcmul() Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ числа с Π·Π°Π΄Π°Π½Π½ΠΎΠΉ Ρ‚ΠΎΡ‡Π½ΠΎΡΡ‚ΡŒΡŽ. РаньшС Π½ΡƒΠ»ΠΈ Π² ΠΊΠΎΠ½Ρ†Π΅ Π΄Ρ€ΠΎΠ±Π½ΠΎΠΉ части числа ΠΎΡ‚Π±Ρ€Π°ΡΡ‹Π²Π°Π»ΠΈΡΡŒ.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€Ρ‹

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #1 ΠŸΡ€ΠΈΠΌΠ΅Ρ€ умноТСния чисСл ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ»ΡŒΠ½ΠΎΠΉ точности Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ bcmul()

<?php

echo bcmul('1.34747474747', '35', 3); // 47.161
echo bcmul('2', '4'); // 8

?>

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΡ

Π—Π°ΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅:

Π”ΠΎ PHP 7.3.0 функция bcmul() ΠΈΠ½ΠΎΠ³Π΄Π° Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π»Π° Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ с мСньшим количСством Ρ†ΠΈΡ„Ρ€ послС дСсятичной Ρ‚ΠΎΡ‡ΠΊΠΈ, Ρ‡Π΅ΠΌ ΡƒΠΊΠ°Π·Π°Π»ΠΈ Π² Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π΅ scale. Ѐункция усСкала Π΄Ρ€ΠΎΠ±Π½ΡƒΡŽ Ρ‡Π°ΡΡ‚ΡŒ, Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΊΠΎΠ³Π΄Π° Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ Π½Π΅ Ρ‚Ρ€Π΅Π±ΠΎΠ²Π°Π» всСй точности, ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ Ρ€Π°Π·Ρ€Π΅ΡˆΠ°Π» ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ scale. НапримСр:

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #2 ΠŸΡ€ΠΈΠΌΠ΅Ρ€ усСчСния точности Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ bcmul()

<?php

echo bcmul('5', '2', 2); // Π’Ρ‹Π²ΠΎΠ΄ΠΈΡ‚ "10", Π° Π½Π΅ "10.00"

?>

Π‘ΠΌΠΎΡ‚Ρ€ΠΈΡ‚Π΅ Ρ‚Π°ΠΊΠΆΠ΅

  • bcdiv() - Π”Π΅Π»ΠΈΡ‚ Π΄Π²Π° числа ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ»ΡŒΠ½ΠΎΠΉ точности
  • BcMath\Number::mul() - Π£ΠΌΠ½ΠΎΠΆΠ°Π΅Ρ‚ число ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ»ΡŒΠ½ΠΎΠΉ точности
οΌ‹Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΡ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ 4 notes

up
10
Nitrogen ΒΆ
16 years ago
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.
up
7
mgkirs ΒΆ
8 years ago
$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;
?>
up
3
admin at spamhere dot sinfocol dot org ΒΆ
15 years ago
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;
}
?>
up
0
gar37bic at gmail dot com ΒΆ
13 years ago
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.