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: Sun, 02 May 2004

IV. Funzioni Matematiche BCMath a precisione arbitraria

Introduzione

Per la matematica a precisione arbitraria PHP offre il Binary Calculator che supporta numeri di qualsiasi dimensione e precisione, rappresentati da stringhe;

Requisiti

Dalla versione 4.0.4 del PHP, libbcmath è inclusa nella distribuzione. Non c'è bisogno di altre librerie esterne per questa estensione.

Installazione

Nel PHP 4, queste funzioni sono disponibili solo se PHP è stato configurato con --enable-bcmath. Nel PHP 3, queste funzioni sono disponibili solo se PHP NON è stato configurato con --disable-bcmath.

La versione per Windows di PHP ha già compilato il supporto per questo modulo. Non occorre caricare alcun modulo addizionale per potere utilizzare queste funzioni.

Configurazione di Runtime

Il comportamento di queste funzioni è influenzato dalle impostazioni di php.ini.

Tabella 1. Opzioni di configurazione di BC math

NomeDefaultModificabile in
bcmath.scale0PHP_INI_ALL
Per ulteriori dettagli e definizioni delle costanti PHP_INI_* vedere ini_set().

Breve descrizione dei parametri di configurazione.

bcmath.scale integer

Numero di cifre decimali per tutte le funzioni bcmath. Vedere anche bcscale().

Tipi di risorse

Questa estensione non definisce alcun tipo di risorsa.

Costanti predefinite

Questa estensione non definisce alcuna costante.

Sommario
bcadd -- Somma due numeri a precisione arbitraria
bccomp -- Confronta due numeri a precisione arbitraria
bcdiv -- Divide due numeri a precisione arbitraria
bcmod --  Ricava il modulo di un numero a precisione arbitraria
bcmul -- Moltiplica due numeri a precisione arbitraria
bcpow --  Effettua l'elevamento a potenza
bcpowmod --  Effettua l'elevamento a potenza, applicando quindi il modulo.
bcscale --  Imposta il valore di precisione di default per tutte le funzioni matematich BCMath
bcsqrt --  Ottiene la radice quadrata di un numero a precisione arbitraria
bcsub --  Sottrae un numero a precisione arbitraria da un altro


add a note add a note User Contributed Notes
Funzioni Matematiche BCMath a precisione arbitraria
postmaster at notreached-diemarketers dot net
20-Jun-2003 03: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
15-Apr-2003 11: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
01-Mar-2003 04: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 01: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 02: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 02: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
07-Jul-2002 11: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
07-Jul-2002 10: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: Sun, 02 May 2004
show source | credits | sitemap | contact | advertising | mirror sites 
Copyright © 2001-2004 The PHP Group
All rights reserved.
This mirror generously provided by: Italia OnLine S.p.a.
Last updated: Fri May 21 04:11:23 2004 CEST