|
|
 |
IV. Funzioni Matematiche BCMath a precisione arbitrariaIntroduzione
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 | Nome | Default | Modificabile in |
|---|
| bcmath.scale | 0 | PHP_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 risorseQuesta estensione non definisce alcun tipo di risorsa. Costanti predefiniteQuesta 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
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...
| |