Skip to content

Commit 1138e26

Browse files
committed
Updated isMultipleOf helper
1 parent 7a1e9a5 commit 1138e26

File tree

1 file changed

+57
-18
lines changed

1 file changed

+57
-18
lines changed

src/Helper.php

Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)