Delicious Bookmark this on Delicious Share on Facebook SlashdotSlashdot It! Digg! Digg



PHP : Function Reference : BCMath Arbitrary Precision Mathematics Functions

BCMath Arbitrary Precision Mathematics Functions

Introduction

For arbitrary precision mathematics PHP offers the Binary Calculator which supports numbers of any size and precision, represented as strings.

Requirements

Since PHP 4.0.4, libbcmath is bundled with PHP. You don't need any external libraries for this extension.

Installation

These functions are only available if PHP was configured with --enable-bcmath. In PHP 3, these functions are only available if PHP was not configured with --disable-bcmath.

The windows version of PHP has built in support for this extension. You do not need to load any additional extension in order to use these functions.

Runtime Configuration

The behaviour of these functions is affected by settings in php.ini.

Table 22. BC math configuration options

Name Default Changeable Changelog
bcmath.scale "0" PHP_INI_ALL  


For further details and definitions of the PHP_INI_* constants, see the Appendix I, php.ini directives.

Here's a short explanation of the configuration directives.

bcmath.scale integer

Number of decimal digits for all bcmath functions. See also bcscale().

Resource Types

This extension has no resource types defined.

Predefined Constants

This extension has no constants defined.

Table of Contents

bcadd — Add two arbitrary precision numbers
bccomp — Compare two arbitrary precision numbers
bcdiv — Divide two arbitrary precision numbers
bcmod — Get modulus of an arbitrary precision number
bcmul — Multiply two arbitrary precision number
bcpow — Raise an arbitrary precision number to another
bcpowmod — Raise an arbitrary precision number to another, reduced by a specified modulus
bcscale — Set default scale parameter for all bc math functions
bcsqrt — Get the square root of an arbitrary precision number
bcsub — Subtract one arbitrary precision number from another

Code Examples / Notes » ref.bc

marcus

Oops, first posting contained wrong code... sorry.
An amendment to the entry by pulstar at mail dot com - the digits() function can be made much faster (remove the line breaks from the big string, and make sure you don't miss any characters!):
function digits2($base) {
if($base < 64) {
return substr('0123456789abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ-_', 0, $base);
} else {
return substr("\x0\x1\x2\x3\x4\x5\x6\x7\x8\x9\xa\xb\xc\xd
\xe\xf\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d
\x1e\x1f\x20!\x22#\x24%&'()*+,-./0123456789:;<=>
\x3f@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]
^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85
\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95
\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5
\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5
\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5
\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5
\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5
\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6
\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", 0, $base);
}
}
in my benchmarks, this is around 150x faster for 256 digits


benjcarson

Note that bcmath doesn't seem to handle numbers in exponential notation (i.e. "1e4"), although PHP considers such a value a number.
example:
$exp1 = "1E5";
$exp2 = "2E4";
$ans1 = bcadd($exp1, $exp2, 3);
$ans2 = $exp1 + exp2;
echo("bcadd: $exp1 + $exp2 = $ans1");
echo("php: $exp1 + $exp2 = $ans2");
// Output:
bcadd: 1E5 + 2E4 = 0.000
php: 1E5 + 2E4 = 120000
Just a gotcha if you're using passing PHP numbers into bcmath functions...


stonehew ut gm a il det com

Like any other bc function, you can't trust the last couple of digits, but everything else seems to check out.  If you want to use this for anything important, you may want to verify this against other sources of pi before use.  This function calculates 100 decimal places of pi in 329 iterations -- not exactly fast (each iteration calls the factorial function, from below, twice), so I try to avoid calling it more than once.
<?
//arbitrary precision pi approximator
//author tom boothby
//free for any use
function bcpi() {
   $r=2;
   $i=0;
   $or=0;
   while(bccomp($or,$r)) {
       $i++;
       $or=$r;
       $r = bcadd($r,bcdiv(bcmul(bcpow(bcfact($i),2),
                       bcpow(2,$i+1)),bcfact(2*$i+1)));
   }
   return $r;
}
?>


benjcarson

In addition to my last note, here are  a quick pair of functions to convert exponential notation values into bcmath-style number strings:
// exp2int converts numbers in the
// form "1.5e4" into strings
function exp2int($exp) {
 list($mantissa, $exponent) = spliti("e", $exp);
 list($int, $dec) = split("\.", $mantissa);
 bcscale ($dec);
 return bcmul($mantissa, bcpow("10", $exponent));
}
// float2exp converts floats into exponential notation
function float2exp($num) {
 if (0 == $num) { return "0E1";}
 list($int, $dec) = split("\.", $num);
 // Extract sign
 if ($int[0] == "+" || $int[0] == "-") {
   $sign = substr($int, 0,1);
   $int = substr($int, 1);
 }
 if (strlen($int) <= 1) {   // abs($num) is less than 1
   $i=0;
   for ($i=0; $dec[$i]=='0' && $i < strlen($dec); $i++);
     $exp = -$i-1;      
     $mantissa = substr($dec,$i,1).".".substr($dec,$i+1);                              
   } else { // abs($num) is greater than 1
   $i=0;
   for ($i=0; $int[$i]=='0' && $i < strlen($int); $i++);
     $exp = strlen($int)-1 - $i;
     $mantissa = substr($int,$i,1).".".substr($int,$i+1).$dec;
   }
 return ($sign . $mantissa . "E" . $exp);
}


mgcclx

I wrote this function with many BCMath functions. It should be the fastest function in PHP to find the number pi into any precision, my test is it generate 2000 digits after the dot in 8 seconds. I don't think you need anything more than that.
<?php
//bcpi function with Gauss-Legendre algorithm
//by Chao Xu (Mgccl)
function bcpi($precision){
   $limit = ceil(log($precision)/log(2))-1;
   bcscale($precision+6);
   $a = 1;
   $b = bcdiv(1,bcsqrt(2));
   $t = 1/4;
   $p = 1;
   while($n < $limit){
       $x = bcdiv(bcadd($a,$b),2);
       $y = bcsqrt(bcmul($a, $b));
       $t = bcsub($t, bcmul($p,bcpow(bcsub($a,$x),2)));
       $a = $x;
       $b = $y;
       $p = bcmul(2,$p);
       ++$n;
   }
   return bcdiv(bcpow(bcadd($a, $b),2),bcmul(4,$t),$precision);
}
?>


robert

I spent some time looking for how to generate a large random number, in the end I've settled for reading directly from /dev/urandom
I know this is a *nix only solution, but I figured that it might come in handy to someone else.
The value $size is the size in bits, it could be simplified greatly if you want the size in bytes, but bits was more helpful to what I needed.
<?php
function bcrand($size)
{
$filename = "/dev/urandom";
$handle = fopen($filename, "r");
$bin_urand = fread($handle, ceil($size/8.0));
fclose($handle);
$mask = (($size % 8 < 5) ? '0' : '') . dechex(bindec(str_repeat('1', $size % 8))) . str_repeat('FF', floor($size/8));
$binmask = pack("H*", $mask);
$binrand = $binmask & $bin_urand;
$hexnumber = unpack("H*", $binrand);
$hexnumber = $hexnumber[''];
$numlength = strlen($hexnumber);
$decnumber = 0;
for($x = 1; $x <= $numlength; $x++)
{
$place = $numlength - $x;
$operand = hexdec(substr($hexnumber,$place,1));
$exponent = bcpow(16,$x-1);
$decValue = bcmul($operand, $exponent);
$decnumber = bcadd($decValue, $decnumber);
}
return $decnumber;
}
?>


stonehew et g m a i l dut com

I hacked these taylor expansions up to make diagrams for some physics homework.  I don't think you'll be wanting to do any real science with PHP... but what the hell, why not?  I plan to implement either a spigot algorithm or something similar to generate pi in the near future.
<?
// arbitrary precision sin and cosine functions
// author tom boothby
// free for any use
function bcfact($n) {
   $r = $n--;
   while($n>1) $r=bcmul($r,$n--);
   return $r;
}
function bcsin($a) {
   $or= $a;
   $r = bcsub($a,bcdiv(bcpow($a,3),6));
   $i = 2;
   while(bccomp($or,$r)) {
       $or=$r;
       switch($i%2) {
         case 0:  $r = bcadd($r,bcdiv(bcpow($a,$i*2+1),bcfact($i*2+1))); break;
         default: $r = bcsub($r,bcdiv(bcpow($a,$i*2+1),bcfact($i*2+1))); break;
       }
       $i++;
   }
   return $r;
}
function bccos($a) {
   $or= $a;
   $r = bcsub(1,bcdiv(bcpow($a,2),2));
   $i = 2;
   while(bccomp($or,$r)) {
       $or=$r;
       switch($i%2) {
         case 0:  $r = bcadd($r,bcdiv(bcpow($a,$i*2),bcfact($i*2))); break;
         default: $r = bcsub($r,bcdiv(bcpow($a,$i*2),bcfact($i*2))); break;
       }
       $i++;
   }
   return $r;
}
?>


diabolos

Here's a function to compute the natural exponential function in arbitrary precision using the basic bcMath arithmetic operations.
EXAMPLE:
To compute the exponential function of 1.7 to 36 decimals:
$y = bcExp("1.7", 36);
The result:
4.331733759839529271053448625299468628
would be returned in variable $y
NOTE:
In practice, the last couple of digits may be inaccurate due to small rounding errors.  If you require a specific degree of precision, always compute 3-4 decimals beyond the required precision.
The program code for the natural exponential function is:
******************************************
 Function bcExp($xArg, $NumDecimals)
{
  $x = Trim($xArg);
  $PrevSum  = $x - 1;
  $CurrTerm = 1;
  $CurrSum  = bcAdd("1", $x, $NumDecimals);
  $n        = 1;
  While (bcComp($CurrSum, $PrevSum, $NumDecimals))
 {
  $PrevSum  = $CurrSum;
  $CurrTerm = bcDiv(bcMul($CurrTerm, $x, $NumDecimals), $n + 1, $NumDecimals);
  $CurrSum  = bcAdd($CurrSum, $CurrTerm, $NumDecimals);
  $n++;
 }
  Return $CurrSum;
}


udochen

Code below implements standard rounding on 5 or higer round up, else don't round.  There wasn't a round function for the BC functions, so here is a simple one that works. Same args as round, except takes strings and returns a string for more BC operations.
----------------
function roundbc($x, $p) {
    $x = trim($x);
    $data = explode(".",$x);
    if(substr($data[1],$p,1) >= "5") {
      //generate the add string.
      $i=0;
      $addString = "5";
      while($i < $p) {
      $addString = "0" . $addString;
      $i++;
      }//end while.
      $addString = "." . $addString;
      //now add the addString to the original fraction.
      $sum = bcadd($data[0] . "." . $data   [1],$addString,$p+1);
      //explode the result.
      $sumData = explode(".",$sum);
      //now, return the correct precision on the rounded number.
      return $sumData[0] . "." . substr($sumData[1],0,$p);
     } else {
      //don't round the value and return the orignal to the desired
      //precision or less.
      return $data[0] . "." . substr($data[1],0,$p);
     }//end if/else.
  }//end roundbc.


oliver

A simplier Version of the Script above:
function dec2base($dec, $digits) {
$value = "";
$base  = strlen($digits);
while($dec>$base-1) {
 $rest = $dec % $base;
 $dec  = $dec / $base;
 $value = $digits[$rest].$value;
}
$value = $digits[intval($dec)].$value;
return (string) $value;
}
function base2dec($value, $digits) {
$value = strtoupper($value);
$base  = strlen($digits);
$size  = strlen($value);
$dec   = '0';
for ($loop = 0; $loop<$size; $loop++) {
 $element = strpos($digits,$value[$loop]);
 $power   = pow($base,$size-$loop-1);
 $dec    += $element * $power;
}
return (string) $dec;
}
$digits = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
echo dec2base('1000', $digits);


pulstar

A little comment for the simplified example above: you can do base converting without BCMath functions using only math operators, but you will not able to manage very large values or work with strings to compress or scramble data. If you have BCMath installed in your system it worth use it for this.

Change Language


Follow Navioo On Twitter
.NET Functions
Apache-specific Functions
Alternative PHP Cache
Advanced PHP debugger
Array Functions
Aspell functions [deprecated]
BBCode Functions
BCMath Arbitrary Precision Mathematics Functions
PHP bytecode Compiler
Bzip2 Compression Functions
Calendar Functions
CCVS API Functions [deprecated]
Class/Object Functions
Classkit Functions
ClibPDF Functions [deprecated]
COM and .Net (Windows)
Crack Functions
Character Type Functions
CURL
Cybercash Payment Functions
Credit Mutuel CyberMUT functions
Cyrus IMAP administration Functions
Date and Time Functions
DB++ Functions
Database (dbm-style) Abstraction Layer Functions
dBase Functions
DBM Functions [deprecated]
dbx Functions
Direct IO Functions
Directory Functions
DOM Functions
DOM XML Functions
enchant Functions
Error Handling and Logging Functions
Exif Functions
Expect Functions
File Alteration Monitor Functions
Forms Data Format Functions
Fileinfo Functions
filePro Functions
Filesystem Functions
Filter Functions
Firebird/InterBase Functions
Firebird/Interbase Functions (PDO_FIREBIRD)
FriBiDi Functions
FrontBase Functions
FTP Functions
Function Handling Functions
GeoIP Functions
Gettext Functions
GMP Functions
gnupg Functions
Net_Gopher
Haru PDF Functions
hash Functions
HTTP
Hyperwave Functions
Hyperwave API Functions
i18n Functions
IBM Functions (PDO_IBM)
IBM DB2
iconv Functions
ID3 Functions
IIS Administration Functions
Image Functions
Imagick Image Library
IMAP
Informix Functions
Informix Functions (PDO_INFORMIX)
Ingres II Functions
IRC Gateway Functions
PHP / Java Integration
JSON Functions
KADM5
LDAP Functions
libxml Functions
Lotus Notes Functions
LZF Functions
Mail Functions
Mailparse Functions
Mathematical Functions
MaxDB PHP Extension
MCAL Functions
Mcrypt Encryption Functions
MCVE (Monetra) Payment Functions
Memcache Functions
Mhash Functions
Mimetype Functions
Ming functions for Flash
Miscellaneous Functions
mnoGoSearch Functions
Microsoft SQL Server Functions
Microsoft SQL Server and Sybase Functions (PDO_DBLIB)
Mohawk Software Session Handler Functions
mSQL Functions
Multibyte String Functions
muscat Functions
MySQL Functions
MySQL Functions (PDO_MYSQL)
MySQL Improved Extension
Ncurses Terminal Screen Control Functions
Network Functions
Newt Functions
NSAPI-specific Functions
Object Aggregation/Composition Functions
Object property and method call overloading
Oracle Functions
ODBC Functions (Unified)
ODBC and DB2 Functions (PDO_ODBC)
oggvorbis
OpenAL Audio Bindings
OpenSSL Functions
Oracle Functions [deprecated]
Oracle Functions (PDO_OCI)
Output Control Functions
Ovrimos SQL Functions
Paradox File Access
Parsekit Functions
Process Control Functions
Regular Expression Functions (Perl-Compatible)
PDF Functions
PDO Functions
Phar archive stream and classes
PHP Options&Information
POSIX Functions
Regular Expression Functions (POSIX Extended)
PostgreSQL Functions
PostgreSQL Functions (PDO_PGSQL)
Printer Functions
Program Execution Functions
PostScript document creation
Pspell Functions
qtdom Functions
Radius
Rar Functions
GNU Readline
GNU Recode Functions
RPM Header Reading Functions
runkit Functions
SAM - Simple Asynchronous Messaging
Satellite CORBA client extension [deprecated]
SCA Functions
SDO Functions
SDO XML Data Access Service Functions
SDO Relational Data Access Service Functions
Semaphore
SESAM Database Functions
PostgreSQL Session Save Handler
Session Handling Functions
Shared Memory Functions
SimpleXML functions
SNMP Functions
SOAP Functions
Socket Functions
Standard PHP Library (SPL) Functions
SQLite Functions
SQLite Functions (PDO_SQLITE)
Secure Shell2 Functions
Statistics Functions
Stream Functions
String Functions
Subversion Functions
Shockwave Flash Functions
Swish Functions
Sybase Functions
TCP Wrappers Functions
Tidy Functions
Tokenizer Functions
Unicode Functions
URL Functions
Variable Handling Functions
Verisign Payflow Pro Functions
vpopmail Functions
W32api Functions
WDDX Functions
win32ps Functions
win32service Functions
xattr Functions
xdiff Functions
XML Parser Functions
XML-RPC Functions
XMLReader functions
XMLWriter Functions
XSL functions
XSLT Functions
YAZ Functions
YP/NIS Functions
Zip File Functions
Zlib Compression Functions
eXTReMe Tracker