略微加速

PHP官方手册 - 互联网笔记

PHP - Manual: BC 数学 函数

2024-11-15

BC 数学 函数

目录

  • bcadd — 两个任意精度数字的加法计算
  • bccomp — 比较两个任意精度的数字
  • bcdiv — 两个任意精度的数字除法计算
  • bcmod — 任意精度数字取模
  • bcmul — 两个任意精度数字乘法计算
  • bcpow — 任意精度数字的乘方
  • bcpowmod — Raise an arbitrary precision number to another, reduced by a specified modulus
  • bcscale — 设置/获取所有 bc math 函数的默认小数点保留位数
  • bcsqrt — 任意精度数字的二次方根
  • bcsub — 两个任意精度数字的减法
add a noteadd a note

User Contributed Notes 20 notes

up
21
Bouke Haarsma
14 years ago
Please be aware not to use/have spaces in your strings. It took me a while to find the error in some advanced calculations!

<?php
echo bcadd("1", "2"); // 3
echo bcadd("1", "2 "); // 1
echo bcadd("1", " 2"); // 1
?>
up
7
dawidgarus at gmail dot com
10 years ago
If you too are confused with illegible code like this:
<?php
$a
= "3";
$b = "5";
bcadd(bcmod(bcadd(bcdiv(bcsqrt(bcadd(7, bcpow($a, 2))), 4), $b), "4"), "0.5"); // i might made a mistake somewhere
?>

You may consider use my function, which makes example above look:
<?php
bc
("(sqrt(7 + $1^2) / 4 + $2) % 4 + 0.5", "3", "5");
?>

Code:
<?php

function bc() {
       
$functions = 'sqrt';
       
// list of | separated functions
        // sqrt refer to bcsqrt etc.
        // function must take exactly 1 argument

       
$argv = func_get_args();
       
$string = str_replace(' ', '', '('.$argv[0].')');
       
$string = preg_replace('/\$([0-9\.]+)/e', '$argv[$1]', $string);
        while (
preg_match('/(('.$functions.')?)\(([^\)\(]*)\)/', $string, $match)) {
                while (
                       
preg_match('/([0-9\.]+)(\^)([0-9\.]+)/', $match[3], $m) ||
                       
preg_match('/([0-9\.]+)([\*\/\%])([0-9\.]+)/', $match[3], $m) ||
                       
preg_match('/([0-9\.]+)([\+\-])([0-9\.]+)/', $match[3], $m)
                ) {
                        switch(
$m[2]) {
                                case
'+': $result = bcadd($m[1], $m[3]); break;
                                case
'-': $result = bcsub($m[1], $m[3]); break;
                                case
'*': $result = bcmul($m[1], $m[3]); break;
                                case
'/': $result = bcdiv($m[1], $m[3]); break;
                                case
'%': $result = bcmod($m[1], $m[3]); break;
                                case
'^': $result = bcpow($m[1], $m[3]); break;
                        }
                       
$match[3] = str_replace($m[0], $result, $match[3]);
                }
                if (!empty(
$match[1]) && function_exists($func = 'bc'.$match[1]))  {
                       
$match[3] = $func($match[3]);
                }
               
$string = str_replace($match[0], $match[3], $string);
        }
        return
$string;
}

?>

Note you must define scale with bcscale().
up
9
artefact2 at gmail dot com
11 years ago
Here are some useful functions to convert large hex numbers from and to large decimal ones :

<?php
   
public static function bchexdec($hex) {
        if(
strlen($hex) == 1) {
            return
hexdec($hex);
        } else {
           
$remain = substr($hex, 0, -1);
           
$last = substr($hex, -1);
            return
bcadd(bcmul(16, bchexdec($remain)), hexdec($last));
        }
    }

    public static function
bcdechex($dec) {
       
$last = bcmod($dec, 16);
       
$remain = bcdiv(bcsub($dec, $last), 16);

        if(
$remain == 0) {
            return
dechex($last);
        } else {
            return
bcdechex($remain).dechex($last);
        }
    }
up
1
kmeissen at gmx dot de
5 years ago
/*
* Computes ln(x) very fast even with high resolution
* uses standard log()-function to optimise convergence of
* ln(1+x) = x - x*x/2 + x*x*x/3 - ...
*
* example:
* bcscale(1000);
* $x = bcln("1000000");
*
* result:
* $x = 13.81551055796427410410794872810618524560660893...
* within 0.9 sec, that are 80 iterations
*
* @author Klaus Meissen, Germany
* @license Public domain
*/
function bcln($value) // value > 0
{
    $m = (string)log($value);
    $x = bcsub(bcdiv($value,bcexp($m)),"1");
    $res = "0";
    $xpow = "1";
    $i=0;
    do
    {
        $i++;
        $xpow = bcmul($xpow,$x);
        $sum = bcdiv($xpow, $i);
        if ($i%2==1)
        {
            $res = bcadd($res, $sum);
        }else{
            $res = bcsub($res, $sum);
        }
    }
    while (bccomp($sum, '0'));
    return bcadd($res,$m);
}
up
0
stonehew et g m a i l dut com
17 years ago
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;
}

?>
up
0
robert at scabserver dot com
18 years ago
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;
}
?>
up
0
pulstar at mail dot com
19 years ago
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
up
0
pulstar at mail dot com
19 years ago
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.
up
-1
mgcclx at gmail dot com
15 years ago
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);
}
?>
up
-1
stonehew ut gm a il det com
17 years ago
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;
}

?>
up
-1
Diabolos at GMail dot com
17 years ago
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;
}
up
-2
thomas at tgohome dot com
12 years ago
Some useful bcmath functions:

<?php

/*
* Computes the factoral (x!).
* @author Thomas Oldbury.
* @license Public domain.
*/
function bcfact($fact, $scale = 100)
{
    if(
$fact == 1) return 1;
    return
bcmul($fact, bcfact(bcsub($fact, '1'), $scale), $scale);
}

/*
* Computes e^x, where e is Euler's constant, or approximately 2.71828.
* @author Thomas Oldbury.
* @license Public domain.
*/
function bcexp($x, $iters = 7, $scale = 100)
{
   
/* Compute e^x. */
   
$res = bcadd('1.0', $x, $scale);
    for(
$i = 0; $i < $iters; $i++)
    {
       
$res += bcdiv(bcpow($x, bcadd($i, '2'), $scale), bcfact(bcadd($i, '2'), $scale), $scale);
    }
    return
$res;
}

/*
* Computes ln(x).
* @author Thomas Oldbury.
* @license Public domain.
*/
function bcln($a, $iters = 10, $scale = 100)
{
   
$result = "0.0";
   
    for(
$i = 0; $i < $iters; $i++)
    {
       
$pow = bcadd("1.0", bcmul($i, "2.0", $scale), $scale);
       
//$pow = 1 + ($i * 2);
       
$mul = bcdiv("1.0", $pow, $scale);
       
$fraction = bcmul($mul, bcpow(bcdiv(bcsub($a, "1.0", $scale), bcadd($a, "1.0", $scale), $scale), $pow, $scale), $scale);
       
$result = bcadd($fraction, $result, $scale);
    }
   
   
$res = bcmul("2.0", $result, $scale);
    return
$res;
}

/*
* Computes a^b, where a and b can have decimal digits, be negative and/or very large.
* Also works for 0^0. Only able to calculate up to 10 digits. Quite slow.
* @author Thomas Oldbury.
* @license Public domain.
*/
function bcpowx($a, $b, $iters = 25, $scale = 100)
{
   
$ln = bcln($a, $iters, $scale);
    return
bcexp(bcmul($ln, $b, $scale), $iters, $scale);
}

$precision = 35;

echo
"3^4.5,          precision 15, iters 25 = " . bcpowx('3', '4.5', 25, $precision) . "\n";
echo
"4.5^3,          precision 15, iters 25 = " . bcpowx('4.5', '3', 25, $precision) . "\n";
echo
"8^1/2,          precision 15, iters 25 = " . bcpowx('8', '0.5', 25, $precision) . "\n";
echo
"28^-1,          precision 15, iters 25 = " . bcpowx('28', '-1', 25, $precision) . "\n";
echo
"432^0,          precision 15, iters 25 = " . bcpowx('432', '0', 25, $precision) . "\n";
echo
"0^0,            precision 15, iters 25 = " . bcpowx('0.0', '0', 25, $precision) . "\n";
echo
"9^999,          precision 15, iters 25 = " . bcpowx('9', '999', 25, $precision) . "\n";
echo
"9^9999,         precision 15, iters 25 = " . bcpowx('9', '9999', 25, $precision) . "\n";
echo
"9^99999,        precision 15, iters 25 = " . bcpowx('9', '99999', 25, $precision) . "\n";
echo
"9^999999,       precision 15, iters 25 = " . bcpowx('9', '999999', 25, $precision) . "\n";
echo
"9^9999999,      precision 15, iters 25 = " . bcpowx('9', '9999999', 25, $precision) . "\n";
echo
"9^99999999,     precision 15, iters 25 = " . bcpowx('9', '99999999', 25, $precision) . "\n";
echo
"9^999999999,    precision 15, iters 25 = " . bcpowx('9', '999999999', 25, $precision) . "\n";
echo
"9^9999999999,   precision 15, iters 25 = " . bcpowx('9', '9999999999', 25, $precision) . "\n";
echo
"9^99999999999,  precision 15, iters 25 = " . bcpowx('9', '99999999999', 25, $precision) . "\n";
echo
"9^999999999999, precision 15, iters 25 = " . bcpowx('9', '999999999999', 25, $precision) . "\n";

?>
up
-1
pulstar at mail dot com
19 years ago
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.
up
-2
marcus at synchromedia dot co dot uk
15 years ago
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
up
-3
mail at djordjeungar dot com
8 years ago
Inspired by dawidgarus' implementation, here's my simple bc math helper, it does not support function calls, but supports boolean comparisons and is about ~40% faster.

<?php
function bc() {
   
$argv = func_get_args();
   
$string = str_replace(' ', '', "({$argv[0]})");

   
$operations = array();
    if (
strpos($string, '^') !== false) $operations[] = '\^';
    if (
strpbrk($string, '*/%') !== false) $operations[] = '[\*\/\%]';
    if (
strpbrk($string, '+-') !== false) $operations[] = '[\+\-]';
    if (
strpbrk($string, '<>!=') !== false) $operations[] = '<|>|=|<=|==|>=|!=|<>';

   
$string = preg_replace('/\$([0-9\.]+)/e', '$argv[$1]', $string);
    while (
preg_match('/\(([^\)\(]*)\)/', $string, $match)) {
        foreach (
$operations as $operation) {
            if (
preg_match("/([+-]{0,1}[0-9\.]+)($operation)([+-]{0,1}[0-9\.]+)/", $match[1], $m)) {
                switch(
$m[2]) {
                    case
'+'$result = bcadd($m[1], $m[3]); break;
                    case
'-'$result = bcsub($m[1], $m[3]); break;
                    case
'*'$result = bcmul($m[1], $m[3]); break;
                    case
'/'$result = bcdiv($m[1], $m[3]); break;
                    case
'%'$result = bcmod($m[1], $m[3]); break;
                    case
'^'$result = bcpow($m[1], $m[3]); break;
                    case
'==':
                    case
'='$result = bccomp($m[1], $m[3]) == 0; break;
                    case
'>'$result = bccomp($m[1], $m[3]) == 1; break;
                    case
'<'$result = bccomp($m[1], $m[3]) ==-1; break;
                    case
'>=': $result = bccomp($m[1], $m[3]) >= 0; break;
                    case
'<=': $result = bccomp($m[1], $m[3]) <= 0; break;
                    case
'<>':
                    case
'!=': $result = bccomp($m[1], $m[3]) != 0; break;
                }
               
$match[1] = str_replace($m[0], $result, $match[1]);
            }
        }
       
$string = str_replace($match[0], $match[1], $string);
    }

    return
$string;
}
?>
up
-1
eyadbere at gmail dot com
1 year ago
If your calculations involves input from users don't forget to set a limit on the range and/or the length of the input because very huge numbers requires intensive processing and you might reach a point where your server can't do any further processing
up
-3
francois dot barbier at gmail dot com
12 years ago
As "benjcarson at digitaljunkies dot ca" (http://www.php.net/ref.bc.php#23038) noted in the first two comments, bcmath doesn't accept exponential notation.

Moreover, you might have other problems if you feed the bcmath functions directly with floating point numbers.
Consider the following example:
<?php
bcscale
(1);
$a = 0.8;
$b = 0.7;
var_dump((string) $a);   // string(3) "0.8"
var_dump((string) $b);   // string(3) "0.a"
var_dump(bcadd($a, $b)); // string(3) "1.5"
setLocale(LC_ALL, 'fr_BE.UTF-8');
var_dump((string) $a);   // string(3) "0,8" --> note the comma
var_dump((string) $b);   // string(3) "0,7" --> note the comma
var_dump(bcadd($a, $b)); // string(3) "0.0"
?>
The floating point numbers passed to the bcadd() function are automatically converted to string using the localized decimal separator. However, the bcmath functions always use a full stop, which results in the last result being incorrect.

Below is a function to convert floating point numbers to strings correctly. It takes care of the decimal separator and the exponential notation. It also preserve the precision without drifting away (e.g. 1.0 doesn't become 0.99999...)
<?php
/**
* Convert a number to locale independent string without E notation and without
* loosing precision
*
* @param      int/float/double $fNumber The number to convert.
* @return     string The locale independent converted number.
*/
function bcconv($fNumber)
{
   
$sAppend = '';
   
$iDecimals = ini_get('precision') - floor(log10(abs($fNumber)));
    if (
0 > $iDecimals)
    {
       
$fNumber *= pow(10, $iDecimals);
       
$sAppend = str_repeat('0', -$iDecimals);
       
$iDecimals = 0;
    }
    return
number_format($fNumber, $iDecimals, '.', '').$sAppend;
}
?>

Example:
<?php
setLocale
(LC_ALL, 'fr_BE.UTF-8'); // decimal separator is now a comma
$precision = ini_get('precision') + 2; // should give 16
bcscale($precision);
$big = pow(10, $precision);
$small = 1 / $big;
var_dump(bcconv($big + $small));               // string(17) "10000000000000000"
var_dump(bcadd($big, $small));                 // string(18) "0.0000000000000000"
var_dump(bcadd(bcconv($big), bcconv($small))); // string(34) "10000000000000000.0000000000000001"
?>
The first result's precision loss is due to PHP's internal floating point numbers' representation.
The second result is wrong because of the localized decimal separator.
Finally, the last result is correct.
up
-2
udochen at gmail dot com
15 years ago
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.
up
-4
Charles
13 years ago
Function to round bc string:

<?php
function bcround($strval, $precision = 0) {
    if (
false !== ($pos = strpos($strval, '.')) && (strlen($strval) - $pos - 1) > $precision) {
       
$zeros = str_repeat("0", $precision);
        return
bcadd($strval, "0.{$zeros}5", $precision);
    } else {
        return
$strval;
    }
}
?>
up
-3
oliver at summertime dot net
19 years ago
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);

官方地址:https://www.php.net/manual/en/ref.bc.php

北京半月雨文化科技有限公司.版权所有 京ICP备12026184号-3