PHP Conference Japan 2024

bcmul

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

bcmul將兩個任意精度數字相乘

說明

bcmul(字串 $num1, 字串 $num2, ?整數 $scale = null): 字串

num1 乘以 num2

參數

num1

左運算元,以字串表示。

num2

右運算元,以字串表示。

scale
此參數用於設定結果中小數點後位數。如果是 null,它將預設為使用 bcscale() 設定的預設小數位數,或是退回使用 bcmath.scale INI 指令的值。

返回值

以字串形式返回結果。

錯誤/例外

在以下情況下,此函式會拋出 ValueError

  • num1num2 不是格式正確的 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() - 兩個任意精度數的除法

新增註釋

使用者貢獻的註釋 4 則註釋

Nitrogen
15 年前
我製作這個函式是為了將無限大小的整數相乘(意思是沒有小數)。
這對於沒有 BCMath 擴充功能的人來說可能很有用。

<?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
*/

?>

製作這個函式是一次有趣的體驗……即使這花了我比 BCAdd 替代方案更長的時間。
不過,對於非常大的數字,記憶體配置可能是一個問題……如果有人想測試我的函式的效能,請隨意。
祝您使用愉快,
Nitrogen.
mgkirs
7 年前
$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 將浮點數作為字串讀取*/
echo bcmul($float, $float1, 32),"\n";
//0
echo bcmul($float, sprint('%.32f',$float1), 32);
//0.000000000000000000000000000000015617072071671;
?>
admin at spamhere dot sinfocol dot org
13 年前
嗯,我在伺服器上實作 Blake Hash 時遇到了一點問題,因為它不是 x64 伺服器機器。我寫了一個小函式,利用 BC 函式庫的強大功能來執行位元位移操作。

<?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;
}

//https://php.dev.org.tw/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;
}
?>
gar37bic at gmail dot com
12 年前
使用 printf 列印 bcmath 運算結果時,請使用字串格式,例如 '%s',而不是數值格式,例如 '%d' 或 '%f'。例如,如果使用 %d 或 %f,階乘 (23) 的輸出將會不正確。

使用 %f 的結果
factorial (22) = 1124000727777607680000 (正確)
factorial (23) = 25852016738884978212864 (不正確)

使用 %s 的結果
factorial (22) = 1124000727777607680000
factorial (23) = 25852016738884976640000

使用 echo 則沒有這個問題 - PHP 會正確輸出 bcmath 字串類型。
To Top