@@ -235,40 +235,79 @@ public static function equals($a, $b): bool
235235 return false ;
236236 }
237237
238+
239+ /**
240+ * @var bool|null True if bcmath extension is available
241+ */
242+ private static ?bool $ hasBCMath = null ;
243+
244+ /**
245+ * @var bool True to use bcmath
246+ */
247+ public static bool $ useBCMath = true ;
248+
249+ /**
250+ * @var int Number scale to used when using comparisons
251+ */
252+ public static int $ numberScale = 14 ;
253+
238254 /**
239255 * @param $number
240256 * @param $divisor
241- * @param int $scale
257+ * @param int|null $scale
242258 * @return bool
243259 */
244- public static function isMultipleOf ($ number , $ divisor , int $ scale = 14 ): bool
260+ public static function isMultipleOf ($ number , $ divisor , ? int $ scale = null ): bool
245261 {
246- static $ bcMath = null ;
247- if ($ bcMath === null ) {
248- $ bcMath = extension_loaded ('bcmath ' );
262+ if ($ number == $ divisor ) {
263+ return true ;
249264 }
265+
250266 if ($ divisor == 0 ) {
251267 return $ number == 0 ;
252268 }
253269
254- if ($ bcMath ) {
255- $ number = number_format ($ number , $ scale , '. ' , '' );
256- $ divisor = number_format ($ divisor , $ scale , '. ' , '' );
270+ if ($ divisor == 1 && !is_string ($ number )) {
271+ return is_int ($ number ) || !fmod ($ number , 1 );
272+ }
273+
274+ // maybe we get lucky
275+ if (!fmod ($ number , $ divisor )) {
276+ return true ;
277+ }
278+
279+ // int mod
280+ if (is_int ($ number ) && is_int ($ divisor )) {
281+ return !($ number % $ divisor );
282+ }
283+
284+ // Use global scale if null
285+ $ scale ??= self ::$ numberScale ;
286+
287+ if (
288+ !self ::$ useBCMath ||
289+ !(self ::$ hasBCMath ??= extension_loaded ('bcmath ' ))
290+ ) {
291+ // use an approximation
292+ $ div = $ number / $ divisor ;
293+ return abs ($ div - round ($ div )) < (10 ** -$ scale );
294+ }
295+
296+ // use bcmath
257297
258- /** @noinspection PhpComposerExtensionStubsInspection */
259- $ x = bcdiv ($ number , $ divisor , 0 );
260- /** @noinspection PhpComposerExtensionStubsInspection */
261- $ x = bcmul ($ divisor , $ x , $ scale );
262- /** @noinspection PhpComposerExtensionStubsInspection */
263- $ x = bcsub ($ number , $ x , $ scale );
298+ $ number = number_format ($ number , $ scale , '. ' , '' );
299+ $ divisor = number_format ($ divisor , $ scale , '. ' , '' );
264300
265- /** @noinspection PhpComposerExtensionStubsInspection */
266- return 0 === bccomp ($ x , 0 , $ scale );
301+ // number can be zero after formatting
302+ if (!(float )$ divisor ) {
303+ return $ number === $ divisor ;
267304 }
268305
269- $ div = $ number / $ divisor ;
306+ $ x = bcdiv ($ number , $ divisor , 0 );
307+ $ x = bcmul ($ divisor , $ x , $ scale );
308+ $ x = bcsub ($ number , $ x , $ scale );
270309
271- return $ div == ( int ) $ div ;
310+ return 0 === bccomp ( $ x , 0 , $ scale ) ;
272311 }
273312
274313 /**
0 commit comments