← All docs

BCMath

Arbitrary-precision decimal arithmetic with PHP's 14 BCMath functions and immutable Number objects.

elephc implements PHP’s 14 procedural bcmath functions and the immutable BcMath\Number class through a pure-Rust decimal bridge. Operations use base-10 digits directly, so values are not converted through binary floating point and result strings preserve the requested number of fractional digits.

Functions

FunctionSignatureResult
bcadd()bcadd(string $num1, string $num2, ?int $scale = null): stringSum
bcsub()bcsub(string $num1, string $num2, ?int $scale = null): stringDifference
bcmul()bcmul(string $num1, string $num2, ?int $scale = null): stringProduct
bcdiv()bcdiv(string $num1, string $num2, ?int $scale = null): stringQuotient
bcmod()bcmod(string $num1, string $num2, ?int $scale = null): stringRemainder
bcdivmod()bcdivmod(string $num1, string $num2, ?int $scale = null): arrayIndexed [quotient, remainder] pair
bcpow()bcpow(string $num, string $exponent, ?int $scale = null): stringIntegral power
bcpowmod()bcpowmod(string $num, string $exponent, string $modulus, ?int $scale = null): stringIntegral modular power
bcsqrt()bcsqrt(string $num, ?int $scale = null): stringSquare root
bccomp()bccomp(string $num1, string $num2, ?int $scale = null): int-1, 0, or 1
bcscale()bcscale(?int $scale = null): intCurrent scale, or previous scale when setting
bcceil()bcceil(string $num): stringLeast integer greater than or equal to the number
bcfloor()bcfloor(string $num): stringGreatest integer less than or equal to the number
bcround()bcround(string $num, int $precision = 0, int $mode = 1): stringRounded decimal string

The four PHP 8.4 additions, bcceil(), bcfloor(), bcround(), and bcdivmod(), are available in every elephc PHP-version profile, like other registry builtins.

Scale and formatting

The process scale starts at 0. Omitting $scale, or passing null, reads the current value set by bcscale(); an explicit 0 always means zero fractional digits. Setting the scale returns its previous value.

echo bcscale(4);                 // 0
echo bcadd('1.234', '5');        // 6.2340
echo bcadd('1.234', '5', 0);     // 6

bcadd(), bcsub(), bcmul(), bcdiv(), and bcmod() truncate to the selected scale; they do not round. Only bcround(), bcceil(), and bcfloor() apply rounding. Output is normalized without a leading + or negative zero, and is padded with trailing zeros to the selected scale.

bcround() accepts the same integer mode values as elephc’s round(): 1 through 8, with 1 (PHP_ROUND_HALF_UP / RoundingMode::HalfAwayFromZero) as the default.

Accepted numbers and errors

Numeric strings are scanned verbatim and may contain an optional sign plus decimal digits with an optional point. Forms such as .5, 5., and +1.20 are valid. PHP also normalizes digitless forms such as "", +, -, ., +., and -. to zero. Surrounding whitespace, exponent notation such as 1e2, multiple decimal points, and other non-numeric text are not accepted.

Malformed numbers, negative or out-of-range scales, invalid powers or square roots, and unsupported rounding modes throw a catchable ValueError. Division or modulo by zero, including a negative power of zero, throws a catchable DivisionByZeroError. Error messages retain PHP function and argument names.

Linking and eval

Using a bc* function or BcMath\Number auto-links libelephc_bcmath. Use --with-bcmath to force-link the bridge and retain the Number declarations when the surface is reached only through indirection or opaque eval source:

elephc --with-bcmath app.php

extension_loaded('bcmath') reports true when the AOT binary links the bridge. Dynamic eval() also exposes all 14 functions and shares the same process scale with surrounding AOT code. Number methods, operators, and boolean conversion also work on native Number objects inside eval. Opaque eval source that creates Numbers without a visible native class reference requires --with-bcmath.

Immutable Number objects

BcMath\Number is a final readonly class implementing Stringable. Its constructor accepts a decimal string or an integer. The public $value string is normalized, and $scale counts its fractional digits, including trailing zeroes. Each arithmetic result is a fresh Number; aliases retain the old value.

use BcMath\Number;

$price = new Number('19.90');
$tax = ($price * '0.22')->round(2);
$total = $price + $tax;
echo $total->value;              // 24.28
echo $total->scale;              // 2
var_dump($total > 24);           // bool(true)

The methods add(), sub(), mul(), div(), mod(), pow(), and compare() accept a Number, decimal string, or integer followed by an optional nullable scale. pow() calls its operand $exponent. powmod($exponent, $modulus, ?int $scale = null) accepts the same operand types. sqrt(?int $scale = null), ceil(), and floor() return Numbers. divmod() returns an indexed pair of Number objects: an integer quotient and a decimal remainder.

In coercive calls, constructor and method operands follow PHP’s string|int binding: finite floats within the signed 64-bit integer range truncate towards zero, booleans become 0 or 1, and null becomes 0. For example, (new Number('2.50'))->add(1.5)->value is "3.50". Nonfinite and out-of-range floats fail decimal validation with ValueError. Arithmetic operators truncate in-range floats too, but reject nonfinite and out-of-range floats with TypeError.

round(int $precision = 0, RoundingMode $mode = RoundingMode::HalfAwayFromZero) supports all eight PHP rounding modes. __toString(), __serialize(), and __unserialize() preserve the decimal value and its full scale. Serialized data contains the value string; unserialization derives the scale from that string.

An omitted or null method scale is independent of bcscale():

OperationAutomatic scale
Addition, subtraction, moduloMaximum operand scale
MultiplicationSum of operand scales
Division, square root, negative powerReceiver scale plus up to ten extra digits, removing unnecessary expansion zeroes
Nonnegative powerReceiver scale multiplied by the exponent; zero for exponent zero
Modular powerZero
ComparisonFull operand precision
DivmodInteger quotient; remainder uses the maximum operand scale

An explicit scale truncates and pads to exactly that many fractional digits. The arithmetic operators +, -, *, /, %, and ** use automatic scale, as do unary +/-, compound assignments, and immutable ++/-- replacements. Value comparisons ==, !=, <, <=, >, >=, and <=> compare decimals. Strict === and !== compare object identity. A zero Number is false in boolean contexts, including empty(). switch cases and non-strict in_array() use the same decimal equality, so 1.20 and 1.200 match despite their different scales. Strict membership keeps object identity. Boolean comparisons follow PHP 8.5 truthiness: a nonzero Number compares equal to true, and a zero Number compares equal to false.

Current scope

The PHP symbol surface includes all 14 procedural functions and the Number class. The bcmath.scale INI directive remains unsupported; bcscale() is the supported process-scale interface. Procedural bcround() retains its integer mode interface described above; Number’s round() uses PHP’s RoundingMode enum.

Functions {#functions}

Generated from the shared symbol catalog by scripts/docs/gen_module_sections.py; do not edit this section by hand. Each function links to its reference page.

FunctionSignatureReturnsAOTeval()
bcadd()(string $num1, string $num2, ?int $scale = null): stringstring✓✓
bcceil()(string $num): stringstring✓✓
bccomp()(string $num1, string $num2, ?int $scale = null): intint✓✓
bcdiv()(string $num1, string $num2, ?int $scale = null): stringstring✓✓
bcdivmod()(string $num1, string $num2, ?int $scale = null): arrayarray✓✓
bcfloor()(string $num): stringstring✓✓
bcmod()(string $num1, string $num2, ?int $scale = null): stringstring✓✓
bcmul()(string $num1, string $num2, ?int $scale = null): stringstring✓✓
bcpow()(string $num, string $exponent, ?int $scale = null): stringstring✓✓
bcpowmod()(string $num, string $exponent, string $modulus, ?int $scale = null): stringstring✓✓
bcround()(string $num, int $precision = 0, int $mode = 1): stringstring✓✓
bcscale()(?int $scale = null): intint✓✓
bcsqrt()(string $num, ?int $scale = null): stringstring✓✓
bcsub()(string $num1, string $num2, ?int $scale = null): stringstring✓✓

Classes: BcMath\Number.