Passed
Pull Request — master (#1819)
by Nico
52:14 queued 25:19
created

StuRandom   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 48
Duplicated Lines 0 %

Test Coverage

Coverage 50%

Importance

Changes 0
Metric Value
eloc 22
dl 0
loc 48
ccs 12
cts 24
cp 0.5
rs 10
c 0
b 0
f 0
wmc 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A array_rand() 0 3 1
A generateRandomValueStandardNormalDistribution() 0 14 4
A rand() 0 7 2
A randomKeyOfProbabilities() 0 15 3
1
<?php
2
3
namespace Stu\Module\Control;
4
5
use RuntimeException;
6
7
/**
8
 * This class adds the possibility to inject a random generator
9
 */
10
class StuRandom
11
{
12 1
    public function rand(int $min, int $max, bool $useStandardNormalDistribution = false, int $mean = null): int
13
    {
14 1
        if ($useStandardNormalDistribution) {
15 1
            return $this->generateRandomValueStandardNormalDistribution($min, $max, $mean);
16
        }
17
18
        return random_int($min, $max);
19
    }
20
21
    public function array_rand(array $array): string|int
22
    {
23
        return array_rand($array);
0 ignored issues
show
Bug Best Practice introduced by
The expression return array_rand($array) could return the type array which is incompatible with the type-hinted return integer|string. Consider adding an additional type-check to rule them out.
Loading history...
24
    }
25
26
    /** @param array<int, int> $probabilities */
27
    public function randomKeyOfProbabilities(array $probabilities): int
28
    {
29
        $totalProbability = array_sum($probabilities);
30
31
        $randomNumber = random_int(1, $totalProbability);
0 ignored issues
show
Bug introduced by
It seems like $totalProbability can also be of type double; however, parameter $max of random_int() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

31
        $randomNumber = random_int(1, /** @scrutinizer ignore-type */ $totalProbability);
Loading history...
32
        $cumulativeProbability = 0;
33
34
        foreach ($probabilities as $key => $prob) {
35
            $cumulativeProbability += $prob;
36
            if ($randomNumber <= $cumulativeProbability) {
37
                return $key;
38
            }
39
        }
40
41
        throw new RuntimeException('this should not happen');
42
    }
43
44 1
    private function generateRandomValueStandardNormalDistribution(int $min, int $max, ?int $mean): int
45
    {
46 1
        $usedMean = $mean === null ? (($min + $max) / 2) : $mean; // MW
47 1
        $stdDeviation = $usedMean / 2.5; // FWHM
48
49
        do {
50 1
            $value = random_int($min, $max);
51 1
            $probability = exp(-0.5 * (($value - $usedMean) / $stdDeviation) ** 2); // normal distribution
52 1
            $randomProbability = random_int(0, mt_getrandmax()) / mt_getrandmax();
53
54 1
            if ($randomProbability <= $probability) {
55 1
                return $value;
56
            }
57 1
        } while (true);
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return integer. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
58
    }
59
}
60