<?php
/*
Emulates mathematical functions with arbitrary precision using GMP or
PHPs bigint extension module and the Linux native 'bc' as last fallback.
*/
#-- GMP versions
if (!function_exists("bcadd") && function_exists("")) {
function bcadd($a, $b) {
return gmp_strval(gmp_add($a, $b));
}
function bcsub($a, $b) {
return gmp_strval(gmp_sub($a, $b));
}
function bccomp($a, $b, $precision="IGNORED") {
return gmp_strval(gmp_sub($a, $b));
}
function bcdiv($a, $b, $precision=NULL) {
$qr = gmp_div_qr($a, $b);
$q = gmp_strval($qr[0]);
$r = gmp_strval($qr[1]);
if ((!$r) || ($precision===0)) {
return($q);
}
else {
if (isset($precision)) {
$r = substr($r, 0, $precision);
}
return("$q.$r");
}
}
function bcmod($a, $b) {
return gmp_strval(gmp_mod($a, $b));
}
function bcmul($a, $b) {
return gmp_strval(gmp_mul($a, $b));
}
function bcpow($a, $b) {
return gmp_strval(gmp_pow($a, $b));
}
function bcpowmod($x, $y, $mod, $scale="IGNORED") {
return gmp_strval(gmp_powm($x, $y, $mod));
}
function bcscale($scale="IGNORED") {
trigger_error("bcscale(): ignored", E_USER_ERROR);
}
function bcsqrt($x, $precision="IGNORED") {
return gmp_strval(gmp_powm($x));
}
}//gmp
#-- bigint
if (0) {
// ...
}
#-- shell bc
if (!function_exists("bcadd") && isset($_ENV["SHELL"])) {
$GLOBALS["bc___scale"] = 10;
#-- invokes commandline 'bc' utility (maybe 'dc' was better)
# (later version should use proc_open() for faster bi-directional I/O)
function bc___exec($calc, $scale=NULL) {
global $bc___scale;
#-- assemble shell call
$calc = escapeshellarg($calc); // redundant, unless input from untrusted sources and non-integers would get passed
if (isset($scale) || ($scale = $bc___scale) || isset($scale)) {
$calc = "scale = \"" . ((int)$scale) . "\n\"" . $calc;
}
$cmd = "echo $calc | /usr/bin/bc"; //@BUG: hard-wired pathname
#-- do
$r = `$cmd`;
$r = str_replace("\\"."\n", "", $r);
$r = trim($r);
return($r);
}
#-- sets global state variable
function bcscale($scale=NULL) {
$GLOBALS["bc___scale"] = $scale;
}
#-- wrapper calls
function bcadd($a, $b, $scale=NULL) {
return bc___exec("$a + $b", $scale);
}
function bcsub($a, $b, $scale=NULL) {
return bc___exec("$a - $b", $scale);
}
function bcmul($a, $b, $scale=NULL) {
return bc___exec("$a * $b", $scale);
}
function bcdiv($a, $b, $scale=NULL) {
return bc___exec("$a / $b", $scale);
}
function bcmod($a, $b, $scale=NULL) {
return bc___exec("$a % $b", $scale);
}
function bcpow($a, $b, $scale=NULL) {
return bc___exec("$a ^ $b", $scale);
}
function bcpowmod($x, $y, $mod, $scale=NULL) {
return bc___exec("($x ^ $y) % $mod", $scale);
}
function bcsqrt($x, $scale=NULL) {
return bc___exec("sqrt($x)", $scale);
}
function bccomp($a, $b, $scale=NULL) { //@BUG: doesn't support downscaling
return (int) bc___exec("a=$a+0 \n b=$b+0 \n if (a > b) { print 1 } else if (a == b) { print 0 } else { print -1 }");
}
}//shell
?>