@@ -235,40 +235,79 @@ public static function equals($a, $b): bool
235
235
return false ;
236
236
}
237
237
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
+
238
254
/**
239
255
* @param $number
240
256
* @param $divisor
241
- * @param int $scale
257
+ * @param int|null $scale
242
258
* @return bool
243
259
*/
244
- public static function isMultipleOf ($ number , $ divisor , int $ scale = 14 ): bool
260
+ public static function isMultipleOf ($ number , $ divisor , ? int $ scale = null ): bool
245
261
{
246
- static $ bcMath = null ;
247
- if ($ bcMath === null ) {
248
- $ bcMath = extension_loaded ('bcmath ' );
262
+ if ($ number == $ divisor ) {
263
+ return true ;
249
264
}
265
+
250
266
if ($ divisor == 0 ) {
251
267
return $ number == 0 ;
252
268
}
253
269
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
257
297
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 , '. ' , '' );
264
300
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 ;
267
304
}
268
305
269
- $ div = $ number / $ divisor ;
306
+ $ x = bcdiv ($ number , $ divisor , 0 );
307
+ $ x = bcmul ($ divisor , $ x , $ scale );
308
+ $ x = bcsub ($ number , $ x , $ scale );
270
309
271
- return $ div == ( int ) $ div ;
310
+ return 0 === bccomp ( $ x , 0 , $ scale ) ;
272
311
}
273
312
274
313
/**
0 commit comments