1717## 🚀 Features
1818
1919- ✅ Complete bcmath extension polyfill for PHP 8.1+
20- - ✅ Supports all PHP 8.4+ bcmath functions including ` bcfloor() ` , ` bcceil() ` , and ` bcround ()`
20+ - ✅ Supports all PHP 8.4+ bcmath functions including ` bcfloor() ` , ` bcceil() ` , ` bcround() ` , and ` bcdivmod ()`
2121- ✅ PHP 8.5 compatibility tested and verified
2222- ✅ Zero dependencies in production (uses phpseclib for arbitrary precision math)
2323- ✅ Seamless fallback when bcmath extension is not available
@@ -54,6 +54,13 @@ echo bcround('2.5', 0, \RoundingMode::HalfAwayFromZero); // 3
5454echo bcround('2.5', 0, \RoundingMode::HalfTowardsZero); // 2
5555echo bcround('2.5', 0, \RoundingMode::HalfEven); // 2
5656echo bcround('2.5', 0, \RoundingMode::HalfOdd); // 3
57+ echo bcround('2.5', 0, \RoundingMode::TowardsZero); // 2
58+ echo bcround('2.5', 0, \RoundingMode::AwayFromZero); // 3
59+ echo bcround('2.5', 0, \RoundingMode::PositiveInfinity); // 3
60+ echo bcround('2.5', 0, \RoundingMode::NegativeInfinity); // 2
61+
62+ // bcdivmod() returns [quotient, remainder]
63+ [$quot, $rem] = bcdivmod('17', '5'); // ['3', '2']
5764```
5865
5966## 📋 Supported Functions
@@ -74,20 +81,39 @@ echo bcround('2.5', 0, \RoundingMode::HalfOdd); // 3
7481- ` bcfloor() ` - Round down to the nearest integer
7582- ` bcceil() ` - Round up to the nearest integer
7683- ` bcround() ` - Round to a specified precision with configurable rounding modes
84+ - ` bcdivmod() ` - Get the quotient and remainder of a division in a single call
7785
7886#### RoundingMode Enum Support
79- The ` bcround() ` function supports PHP 8.4's ` RoundingMode ` enum through a polyfill for PHP 8.1-8.3:
87+ The ` bcround() ` function supports PHP 8.4's ` RoundingMode ` enum through a polyfill for PHP 8.1-8.3.
88+ All eight native modes are implemented with exact, arbitrary-precision string arithmetic (no float
89+ fallback), so results match the native ` bcround() ` even for very large or high-precision numbers:
8090
81- ** Supported Modes:**
8291- ` RoundingMode::HalfAwayFromZero ` (equivalent to ` PHP_ROUND_HALF_UP ` )
8392- ` RoundingMode::HalfTowardsZero ` (equivalent to ` PHP_ROUND_HALF_DOWN ` )
8493- ` RoundingMode::HalfEven ` (equivalent to ` PHP_ROUND_HALF_EVEN ` )
8594- ` RoundingMode::HalfOdd ` (equivalent to ` PHP_ROUND_HALF_ODD ` )
95+ - ` RoundingMode::TowardsZero `
96+ - ` RoundingMode::AwayFromZero `
97+ - ` RoundingMode::NegativeInfinity `
98+ - ` RoundingMode::PositiveInfinity `
99+
100+ The legacy integer ` PHP_ROUND_* ` constants are also accepted for the four half-modes.
101+
102+ > ** Note:** The polyfilled ` RoundingMode ` is a * pure* enum, matching native PHP 8.4 (it has no
103+ > backing value; ` ->value ` / ` from() ` / ` tryFrom() ` are intentionally unavailable).
104+
105+ #### Interoperability with ` symfony/polyfill-php84 `
106+
107+ ` symfony/polyfill-php84 ` also declares ` bcceil() ` , ` bcfloor() ` , ` bcround() ` and ` bcdivmod() ` , but only
108+ when the native bcmath extension is ** already loaded** (its purpose is to backport the new PHP 8.4
109+ functions to older PHP that already has bcmath). This package instead provides the full bcmath API for
110+ environments ** without** the extension.
86111
87- ** Not Yet Supported:**
88- - ` RoundingMode::TowardsZero ` - Throws ` ValueError ` (planned for future release)
89- - ` RoundingMode::AwayFromZero ` - Throws ` ValueError ` (planned for future release)
90- - ` RoundingMode::NegativeInfinity ` - Throws ` ValueError ` (planned for future release)
112+ When both packages are installed on an environment that * does* have the bcmath extension and runs
113+ ** PHP 8.2/8.3** , both declare ` bcceil() ` /` bcfloor() ` /` bcround() ` ; whichever autoloads first wins (the
114+ ` function_exists() ` guards prevent a fatal redeclaration). This package's rounding is implemented with a
115+ native-compatible string algorithm, so the numeric results are identical regardless of which
116+ implementation is used. On environments without the extension only this package is active.
91117
92118## ⚡ Performance
93119
@@ -193,34 +219,33 @@ While the polyfill is significantly slower than native bcmath:
193219 - PHP >= 7.3.0: Use ` bcscale() ` without arguments
194220 - PHP < 7.3.0: Use ` max(0, strlen(bcadd('0', '0')) - 2) `
195221
196- ### RoundingMode Enum Limitations
197- - Three ` RoundingMode ` enum values are not yet implemented:
198- - ` RoundingMode::TowardsZero ` - Will throw ` ValueError `
199- - ` RoundingMode::AwayFromZero ` - Will throw ` ValueError `
200- - ` RoundingMode::NegativeInfinity ` - Will throw ` ValueError `
201- - These modes are planned for implementation in a future release
202- - Use traditional ` PHP_ROUND_* ` constants as alternatives when needed
203-
204- ## 🔄 Key Differences from phpseclib/bcmath_compat
205-
206- | Feature | phpseclib/bcmath_compat | bcmath-polyfill |
207- | ---------------------------| --------------------------------| -------------------------------------|
208- | ** PHP 8.4 functions** | ❌ Not supported | ✅ Full support |
209- | ` bcfloor() ` | ❌ | ✅ |
210- | ` bcceil() ` | ❌ | ✅ |
211- | ` bcround() ` | ❌ | ✅ |
212- | ** RoundingMode enum** | ❌ Not supported | ✅ Partial (4/7 modes) |
213- | ` HalfAwayFromZero ` | ❌ | ✅ |
214- | ` HalfTowardsZero ` | ❌ | ✅ |
215- | ` HalfEven ` | ❌ | ✅ |
216- | ` HalfOdd ` | ❌ | ✅ |
217- | ` TowardsZero ` | ❌ | ⏳ Planned |
218- | ` AwayFromZero ` | ❌ | ⏳ Planned |
219- | ` NegativeInfinity ` | ❌ | ⏳ Planned |
220- | ** PHP 8.2+ deprecations** | ⚠️ Warnings | ✅ Fixed |
221- | ** Test suite pollution** | ⚠️ Issues | ✅ Fixed |
222- | ** Active maintenance** | ❌ Limited | ✅ Active |
223- | ** CI/CD (PHP versions)** | GitHub Actions (8.1, 8.2, 8.3) | GitHub Actions (8.1, 8.2, 8.3, 8.4, 8.5) |
222+ ## 🔄 Key Differences from phpseclib/bcmath_compat and symfony/polyfill-php84
223+
224+ The three libraries target different goals. ` phpseclib/bcmath_compat ` is the classic pre-8.4 polyfill.
225+ ` symfony/polyfill-php84 ` backports ** only** the new PHP 8.4 functions and activates them ** only when the
226+ native bcmath extension is already loaded** . ` bcmath-polyfill ` provides the complete bcmath API —
227+ including the PHP 8.4 additions — for environments ** with or without** the extension.
228+
229+ | Feature | phpseclib/bcmath_compat | symfony/polyfill-php84 | bcmath-polyfill |
230+ | ------------------------------------------------| --------------------------------| ---------------------------------| ------------------------------------------|
231+ | Classic bc functions (` bcadd ` , ` bcmul ` , …) | ✅ | ❌ Not provided | ✅ |
232+ | Works ** without** the bcmath extension | ✅ | ❌ Requires the extension | ✅ |
233+ | ` bcfloor() ` / ` bcceil() ` / ` bcround() ` | ❌ | ✅ (extension required) | ✅ |
234+ | ` bcdivmod() ` | ❌ | ✅ (delegates to native bc) | ✅ (works without the extension) |
235+ | ** RoundingMode enum** (all 8 modes) | ❌ | ✅ | ✅ |
236+ | Arbitrary-precision rounding (no float fallback)| ❌ | ✅ (pure string algorithm) | ✅ (pure string algorithm) |
237+ | ` RoundingMode ` is a * pure* enum (native shape) | — | ✅ | ✅ |
238+ | Implementation of rounding | — | Pure string digits | Pure string digits (phpseclib elsewhere) |
239+ | Extra dependency | phpseclib | none | phpseclib |
240+ | ** PHP 8.2+ deprecations** | ⚠️ Warnings | ✅ Fixed | ✅ Fixed |
241+ | ** Active maintenance** | ❌ Limited | ✅ Active | ✅ Active |
242+ | ** CI/CD (PHP versions)** | GitHub Actions (8.1, 8.2, 8.3) | 7.2+ | GitHub Actions (8.1, 8.2, 8.3, 8.4, 8.5) |
243+
244+ > When ` bcmath-polyfill ` and ` symfony/polyfill-php84 ` are installed together on an environment that has
245+ > the bcmath extension and runs PHP 8.2/8.3, both declare ` bcceil() ` /` bcfloor() ` /` bcround() ` and whichever
246+ > autoloads first wins (guarded by ` function_exists() ` , so no fatal redeclaration). Because this package's
247+ > rounding uses a native-compatible string algorithm, the results are identical either way. See
248+ > [ Interoperability with ` symfony/polyfill-php84 ` ] ( #interoperability-with-symfonypolyfill-php84 ) .
224249
225250### Migration from phpseclib/bcmath_compat
226251
0 commit comments