PHP  
downloads | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
search for in the  
<aspell_suggestbcadd>
view the version of this page
Last updated: Thu, 21 Aug 2003

IV. 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

In PHP 4, 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 1. BC math configuration options

NameDefaultChangeable
bcmath.scale0PHP_INI_ALL
For further details and definition of the PHP_INI_* constants see ini_set().

Here's a short explanation of the configuration directives.

bcmath.scale integer

Number of decimal digits for all bcmath functions.

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


add a note add a note User Contributed Notes
BCMath Arbitrary Precision Mathematics Functions
postmaster at notreached-diemarketers dot net
20-Jun-2003 11:58
One way to use the base conversion functions provided above is
to implement bitwise math. I give you the functions bcand, bcor,
bcxor, bcleftshift, and bcrightshift (NOTE: the functions are
compatible with Pulstar's base-conversion functions, not
Oliver's):

// MAX_BASE is the maximum base that can be represented in
// one byte on the host machine. On most modern systems, this
// value can be 256, but if there are still any systems with 7-bit
// bytes out there, you should use 128 for maximum
// portability.

define('MAX_BASE', 128);

//// INTERFACE ROUTINES:

// Bitwise AND

function bcand($x, $y)
{
        return _bcbitwise_internal($x, $y, '_bcand');
}

// Bitwise OR

function bcor($x, $y)
{
        return _bcbitwise_internal($x, $y, '_bcor');
}

// Bitwise XOR

function bcxor($x, $y)
{
        return _bcbitwise_internal($x, $y, '_bcxor');
}

// Left shift (<<)

function bcleftshift($num, $shift)
{
        bcscale(0);
        return bcmul($num, bcpow(2, $shift));
}

// Right shift (>>)

function bcrightshift($num, $shift)
{
        bcscale(0);
        return bcdiv($num, bcpow(2, $shift));
}
//// INTERNAL ROUTINES

// These routines operate on only one byte. They are used to
// implement _bcbitwise_internal.

function _bcand($x, $y)
{
        return $x & $y;
}

function _bcor($x, $y)
{
        return $x | $y;
}

function _bcxor($x, $y)
{
        return $x ^ $y;
}

// _bcbitwise_internal - The majority of the code that implements
//                       the bitwise functions bcand, bcor, and bcxor.
//
// arguments           - $x and $y are the operands (in decimal format),
//                       and $op is the name of one of the three
//                       internal functions, _bcand, _bcor, or _bcxor.
//
//
// see also            - The interfaces to this function: bcand, bcor,
//                       and bcxor

function _bcbitwise_internal($x, $y, $op)
{
        $bx = bc2bin($x);
        $by = bc2bin($y);

        // Pad $bx and $by so that both are the same length.

        equalbinpad($bx, $by);

        $ix=0;
        $ret = '';

        for($ix = 0; $ix < strlen($bx); $ix++)
        {
                $xd = substr($bx, $ix, 1);
                $yd = substr($by, $ix, 1);
                $ret .= call_user_func($op, $xd, $yd);
        }

        return bin2bc($ret);
}

// equalbinpad - Pad the operands on the most-significant end
//               so they have the same number of bytes.
//
// arguments   - $x and $y, binary-format numbers (converted
//               from decimal format with bc2bin()), passed
//               by reference.
//
// notes       - Both operands are modified by this function.

function equalbinpad(&$x, &$y)
{
        $xlen = strlen($x);
          $ylen = strlen($y);

        $length = max($xlen, $ylen);
          fixedbinpad($x, $length);
        fixedbinpad($y, $length);
}

// fixedbinpad - Pad a binary number up to a certain length
//
// arguments   - $num: The operand to be padded.
//
//             - $length: The desired minimum length for
//                        $num
//
// notes       - $num is modified by this function.

function fixedbinpad(&$num, $length)
{
        $pad = '';
        for($ii = 0; $ii < $length-strlen($num); $ii++)
        {
                $pad .= bc2bin('0');
        }

        $num = $pad . $num;
}

// bc2bin       - Convert a decimal number to the internal
//                binary format used by this library.
//
// return value - The binary representation of $num.

function bc2bin($num)
{
        return dec2base($num, MAX_BASE);
}

// bin2bc       - Reverse of bc2bin

function bin2bc($num)
{
        return base2dec($num, MAX_BASE);
}
pulstar at mail dot com
16-Apr-2003 07:12
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.
oliver at summertime dot net
02-Mar-2003 02:12
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 at mail dot com
20-Sep-2002 09:23
A found a little fix to do in my base2dec() function:
The line "if($base<37) $value=strtolower($value);" should be removed if you want to specify another digits for your base conversions. Change it this way:

if(!$digits) {
$digits=digits($base);
if($base<37) {
$value=strtolower($value);
}
}

Another example using these functions is to generate a key for a session, to name temporary files or something else:

srand((double) microtime()*1000000);
$id=uniqid(rand(10,999));
$mykey=dec2base(base2dec($id,16),64);

$mykey is a base64 value, which is a good key for passing thru an URL and also is shorter than a MD5 string (it will be allways 11 chars long). If you need something more secure, just scramble the 64 digits in the digits() function.

Well, I hope you enjoy it.

Regards,
Edemilson Lima
pulstar at mail dot com
20-Sep-2002 10:27
Here some examples of the previous post:

a) Converting bases:

Converting from decimal to binary:
$x=192;
$y=dec2base($x,2);

From binary to decimal:
$x=1100101001;
$y=base2dec($x,2);

Decimal to octal:
$x=192;
$y=dec2base($x,8);

Octal to decimal:
$x=18107362;
$y=base2dec($x,8);

Decimal to hexadecimal:
$x=139245;
$y=dec2base($x,16);

Hexadecimal to decimal:
$x="e0f13d";
$y=base2dec($x,16);
// note: you must use smallcaps unless you specify another digits. Example:
// $x="E0F13D";
// $y=base2dec($x,16,"0123456789ABCDEF");

Decimal to base32:
$x=92109743;
$y=dec2base($x,32);

Decimal to base64:
$x=92109743;
$y=dec2base($x,64);

Decimal to base256:
$x=92109743;
$y=dec2base($x,256);

As you can see, you can use any value from 2 to 256 as a valid base. The size of the number ($x) doesn't matter, because BCMath is very powerful.

You can use these functions to convert a string to a value that can be passed by an URL. Example:

$string="*Here Anything+Exactly-As#You$Want@, using&any%characters(";
$decimal=base2dec($string,256);
$base64=dec2base($decimal,64);
<a href="script.php?var=<?php echo $base64 ?>">Click me</a>

You can pass the content of the $base64 var by an URL. It only will have letters, numbers, the "_" and "-". After you get it from the URL, you must do the inverse way to get the original string again:

$decimal=base2dec($var,64);
$string=dec2base($decimal,256);
echo $string;

b) "Compressing" data:

Converting an e-mail address to another base:
$digits="@0123456789abcdefghijklmnopqrstuvwxyz-.";
// these are the 39 characters used by e-mail addresses
$email="this.is@my-email.com";
$base64=decbase(basedec($email,64),39,$digits);
$base256=decbase(basedec($email,256),39,$digits);

$restored_email=decbase(basedec($base64,39,$digits),64);
$restored_email2=decbase(basedec($base256,39,$digits),256);

// $base64 is the equivalent of the email address in a base64 value, which can be passed by an URL and is shorter than the original e-mail address in ASCII.
// $base256 is the same in a base256 value, which can be stored in a database and is even shorter than $base64.
By this method you can compress informations that do not use the all 256 characters, such as names, addresses, etc. You must figure which characters these informations will use and use it as your digits.
To compress and "encrypt" you only need to scramble the digits used.

As these functions can be used for some kind of encryption too, you only need to use another sort of digits, scrambled any way you want. Just remember to use the same sequence of digits for reconversion, or you will get another thing. Here an example:

$digits="z6QgkmR1ZP irK9Ws?lbNCjnYwht.vyaJx5IM78-fODdUFHucpoS,2GEX403eALVTBq"; // 67 characters that can be used in names, for example
$data="This is my string. Can you See, what I want to do?";
$encrypted=decbase(basedec($data,256),67,$digits);
$decrypted=decbase(basedec($encrypted,67,$digits),256);

Well, I didn't tested my examples above, but the functions works for sure (I did spend a whole night working on it)...  :-)
pulstar at mail dot com
20-Sep-2002 10:27
A good use for BCMath functions:
The functions below can convert a number in any base (from 2 to 256) to its decimal value and vice-versa.

// convert a decimal value to any other base value
function dec2base($dec,$base,$digits=FALSE) {
    if($base<2 or $base>256) die("Invalid Base: ".$base);
    bcscale(0);
    $value="";
    if(!$digits) $digits=digits($base);
    while($dec>$base-1) {
        $rest=bcmod($dec,$base);
        $dec=bcdiv($dec,$base);
        $value=$digits[$rest].$value;
    }
    $value=$digits[intval($dec)].$value;
    return (string) $value;
}

// convert another base value to its decimal value
function base2dec($value,$base,$digits=FALSE) {
    if($base<2 or $base>256) die("Invalid Base: ".$base);
    bcscale(0);
    if($base<37) $value=strtolower($value);
    if(!$digits) $digits=digits($base);
    $size=strlen($value);
    $dec="0";
    for($loop=0;$loop<$size;$loop++) {
        $element=strpos($digits,$value[$loop]);
        $power=bcpow($base,$size-$loop-1);
        $dec=bcadd($dec,bcmul($element,$power));
    }
    return (string) $dec;
}

function digits($base) {
    if($base>64) {
        $digits="";
        for($loop=0;$loop<256;$loop++) {
            $digits.=chr($loop);
        }
    } else {
        $digits ="0123456789abcdefghijklmnopqrstuvwxyz";
        $digits.="ABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
    }
    $digits=substr($digits,0,$base);
    return (string) $digits;
}

The purpose of digits() function above is to supply the characters that will be used as digits for the base you want. NOTE: You can use any characters for that when you convert to another base, but when you convert again to the decimal base, you need to use the same characters or you will get another unexpected result.
benjcarson at digitaljunkies dot ca
08-Jul-2002 07:00
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);
}
benjcarson at digitaljunkies ca
08-Jul-2002 06:17
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...

<aspell_suggestbcadd>
 Last updated: Thu, 21 Aug 2003
show source | credits | sitemap | mirror sites 
Copyright © 2001-2003 The PHP Group
All rights reserved.
This mirror generously provided by: http://php.mirrors.ilisys.com.au/
Last updated: Sat 01 Nov 2003 04:13:36 EST EST