How TypePHP Handles High-Precision Numeric Types: BigInt, Decimal, and BigFloat

TypePHP provides arbitrary-precision arithmetic through three specialized classes—\TypePHP\BigInt, \TypePHP\BigFloat, and \TypePHP\Decimal—backed by GMP and BCMath extensions, while enforcing strict compile-time rules to prevent accidental precision loss.

TypePHP extends PHP with native support for high-precision numeric types critical for financial calculations and scientific computing. In the swoole/typephp repository, these types are implemented as immutable value objects accessible through helper functions defined in src/polyfills.php, offering unlimited precision without sacrificing type safety.

The Three High-Precision Numeric Classes

TypePHP introduces three distinct classes to handle different precision requirements, each residing in the \TypePHP namespace and instantiated via global helper functions.

BigInt for Arbitrary-Length Integers

The BigInt type represents integers of unlimited magnitude, bypassing PHP's native 32-bit or 64-bit integer limits. When the GMP extension is available, operations use native GMP functions; otherwise, a pure-PHP fallback implementation ensures portability.

$largePrime = std::bigInt('123456789012345678901234567890');
$factorial = $largePrime->mul(std::bigInt('2')); // Unlimited precision multiplication

BigFloat for High-Precision Floating-Point

BigFloat handles floating-point numbers with arbitrary precision, avoiding the rounding errors inherent in IEEE 754 doubles. Like BigInt, it prefers the GMP extension but falls back to BCMath or pure-PHP implementations depending on the environment.

$pi = std::bigFloat('3.141592653589793238462643383279');
$circumference = $pi->mul(std::bigFloat('2')); // Maintains full precision throughout

Decimal for Fixed-Point Arithmetic

The Decimal type provides exact fixed-point arithmetic essential for monetary calculations, using BCMath under the hood. Unlike floating-point types, Decimal maintains a specific scale (number of decimal places) to ensure deterministic rounding behavior.

$price = std::decimal('99.99', 2); // Scale of 2 for currency
$total = $price->mul(std::decimal('1.15')); // 114.9885 with exact precision

Internal Implementation and Backing Libraries

The high-precision types in TypePHP leverage PHP's mathematical extensions through a unified abstraction layer. In src/polyfills.php, the helper functions std::bigInt(), std::bigFloat(), and std::decimal() serve as thin wrappers that accept scalar values (strings, integers, or floats) and return immutable instances of their respective classes.

These classes implement PHP's magic methods—such as __add, __sub, __mul, and __div—to support natural arithmetic syntax while delegating actual calculations to GMP or BCMath functions. This architecture ensures that swoole/typephp delivers native performance when extensions are available while maintaining functionality in restricted environments.

Compile-Time Type Safety Rules

TypePHP enforces strict compatibility between high-precision types at compile time to prevent subtle precision bugs. The parser actively rejects code that would implicitly mix incompatible numeric types.

According to the source code in src/Parser/BinaryOpTrait.php (line 65), mixing a BigInt with a Decimal or BigFloat in a binary operation triggers a compile-time error with the message: "Cannot mix BigInt and Decimal implicitly. Use std::decimal() or std::bigInt() to convert explicitly."

Key compatibility constraints include:

  • Same-type operations between two BigInt, two BigFloat, or two Decimal values are permitted and execute with underlying library precision.
  • Implicit scalar conversion is allowed only when a native PHP scalar can be represented exactly in the target type (e.g., integer literals to BigInt).
  • Cross-type arithmetic requires explicit conversion via toBigInt(), toDecimal(), or constructor helpers to ensure developers acknowledge potential precision changes.

Runtime compatibility checks are further implemented in src/TypeSystem/NativeTypeCompatibilityTrait.php, providing additional guards during execution.

Practical Usage Examples

The following patterns demonstrate creation, arithmetic operations, and safe type conversion between high-precision numeric types in TypePHP.

<?php
// Creation with explicit string literals to avoid floating-point contamination
$bigInt   = std::bigInt('123456789012345678901234567890');
$bigFloat = std::bigFloat('3.141592653589793238462643383279');
$decimal  = std::decimal('99.99');

// Arithmetic maintains precision automatically
$sum      = $bigInt->add(std::bigInt('1'));
$product  = $bigFloat->mul(std::bigFloat('2'));
$price    = $decimal->mul(std::decimal('1.15'));

// Explicit conversion required when mixing types
// $illegal = $bigInt + $decimal; // Compile-time error

// Safe conversion paths
$intFromDecimal = $decimal->toBigInt();     // Truncates to 99
$decimalFromInt = $bigInt->toDecimal(0);   // Converts with scale 0

// Interoperability with native scalars
$mixedSum  = $bigInt->add(42);              // Native int auto-converted
$mixedFloat = $bigFloat->add(0.5);         // Native float accepted by BigFloat

Reference implementations and test cases are available in examples/high-precision.php and phpunit/code/big-numeric/mixed-big-comparison.php, which validate comparison semantics and edge cases for these numeric types.

Summary

  • TypePHP implements three high-precision numeric types—BigInt, BigFloat, and Decimal—through the \TypePHP namespace, accessible via std::bigInt(), std::bigFloat(), and std::decimal() helpers defined in src/polyfills.php.
  • BigInt and BigFloat prefer the GMP extension with pure-PHP fallbacks, while Decimal relies on BCMath for fixed-point arithmetic.
  • The compiler prevents implicit mixing of BigInt with Decimal or BigFloat, throwing errors from src/Parser/BinaryOpTrait.php unless explicit conversion methods are used.
  • All three types support natural arithmetic operators through magic methods while maintaining arbitrary precision throughout calculations.

Frequently Asked Questions

What happens when BigInt and Decimal are mixed in the same expression?

TypePHP emits a compile-time error before execution occurs. According to the parser logic in src/Parser/BinaryOpTrait.php, the compiler detects the type mismatch and requires explicit conversion using toDecimal() or toBigInt() methods to ensure the developer intentionally accepts any precision loss from the conversion.

Does TypePHP require the GMP extension to be installed?

No, though GMP is preferred for performance. The BigInt and BigFloat implementations include pure-PHP fallback logic when GMP is unavailable. However, the Decimal type specifically requires BCMath for its fixed-point operations, which is typically available in standard PHP builds.

How do I control the number of decimal places in Decimal calculations?

Pass the desired scale (number of fractional digits) as the second argument to std::decimal(). For example, std::decimal('99.99', 4) creates a Decimal with four decimal places. Arithmetic operations preserve this scale, and rounding behavior follows BCMath's fixed-point semantics to ensure deterministic financial calculations.

Can high-precision types be compared directly with native PHP integers?

Yes, TypePHP permits direct comparison between high-precision types and native PHP scalars when the scalar can be represented exactly. Runtime compatibility checks in src/TypeSystem/NativeTypeCompatibilityTrait.php handle these comparisons, though explicit conversion is recommended for absolute type safety in complex expressions.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →