Skip to content

Commit 809f085

Browse files
authored
calculate factorials as floats (#283)
1 parent 66a9033 commit 809f085

File tree

3 files changed

+12
-4
lines changed

3 files changed

+12
-4
lines changed

classes/local/functions.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -833,11 +833,16 @@ public static function rshuffle(array $ar): array {
833833
* Note: technically, the function accepts a float, because in some
834834
* PHP versions, if one passes a float to a function that expectes an int,
835835
* the float will be converted. We'd rather detect that and print an error.
836+
* Although the returned value is an integer, we use the float type, because
837+
* PHP_FLOAT_MAX is much larger than PHP_INT_MAX.
838+
* Beware: Due to the limited precision of floats (~ 16 digits), factorials
839+
* larger than 27! are not guaranteed to be accurate, or rather, they are
840+
* guaranteed not to be accurate...
836841
*
837842
* @param float $n the number
838-
* @return int
843+
* @return float
839844
*/
840-
public static function fact(float $n): int {
845+
public static function fact(float $n): float {
841846
$n = self::assure_numeric(
842847
$n,
843848
get_string('error_func_nnegint', 'qtype_formulas', 'fact()'),
@@ -848,7 +853,7 @@ public static function fact(float $n): int {
848853
}
849854
$result = 1;
850855
for ($i = 1; $i <= $n; $i++) {
851-
if ($result > PHP_INT_MAX / $i) {
856+
if ($result > PHP_FLOAT_MAX / $i) {
852857
self::die('error_fact_toolarge', $n);
853858
}
854859
$result *= $i;

classes/local/random_variable.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public function how_many(): int {
8989
// TODO: non-capturing catch.
9090
return PHP_INT_MAX;
9191
}
92-
return $result;
92+
return $result >= PHP_INT_MAX ? PHP_INT_MAX : (int) $result;
9393
}
9494
return count($this->reservoir);
9595
}

tests/functions_test.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,9 @@ public static function provide_fact(): array {
268268
[2, 'fact(2)'],
269269
[6, 'fact(3)'],
270270
[720, 'fact(6)'],
271+
[15511210043330985984000000, 'fact(25)'],
272+
[403291461126605635584000000, 'fact(26)'],
273+
[10888869450418352160768000000, 'fact(27)'],
271274
['fact() expects its argument to be a non-negative integer.', 'fact(-2)'],
272275
['fact() expects its argument to be a non-negative integer.', 'fact(2.5)'],
273276
['Cannot compute 250! on this platform, the result is bigger than PHP_MAX_INT.', 'fact(250)'],

0 commit comments

Comments
 (0)