Completed
Pull Request — master (#58)
by Michele
02:24
created

BinaryMath::reduce()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2
1
<?php
2
3
namespace IPLib\Service;
4
5
/**
6
 * Helper class to work with unsigned binary integers.
7
 */
8
class BinaryMath
9
{
10
    /**
11
     * Trim the leading zeroes from a non-negative integer represented in binary form.
12
     *
13
     * @param string $value
14
     *
15
     * @return string
16
     */
17 1026
    public function reduce($value)
18
    {
19 1026
        $value = ltrim($value, '0');
20
21 1026
        return $value === '' ? '0' : $value;
22
    }
23
24
    /**
25
     * Compare two non-negative integers represented in binary form.
26
     *
27
     * @param string $a
28
     * @param string $b
29
     *
30
     * @return int 1 if $a is greater than $b, -1 if $b is greater than $b, 0 if they are the same
31
     */
32 16
    public function compare($a, $b)
33
    {
34 16
        list($a, $b) = $this->toSameLength($a, $b);
35
36 16
        return $a < $b ? -1 : ($a > $b ? 1 : 0);
37
    }
38
39
    /**
40
     * Add 1 to a non-negative integer represented in binary form.
41
     *
42
     * @param string $value
43
     *
44
     * @return string
45
     */
46 154
    public function increment($value)
47
    {
48 154
        $lastZeroIndex = strrpos($value, '0');
49 154
        if ($lastZeroIndex === false) {
50 13
            return '1' . str_repeat('0', strlen($value));
51
        }
52
53 142
        return ltrim(substr($value, 0, $lastZeroIndex), '0') . '1' . str_repeat('0', strlen($value) - $lastZeroIndex - 1);
54
    }
55
56
    /**
57
     * Calculate the bitwise AND of two non-negative integers represented in binary form.
58
     *
59
     * @param string $operand1
60
     * @param string $operand2
61
     *
62
     * @return string
63
     */
64 515
    public function and($operand1, $operand2)
65
    {
66 515
        $operand1 = $this->reduce($operand1);
67 515
        $operand2 = $this->reduce($operand2);
68 515
        $numBits = min(strlen($operand1), strlen($operand2));
69 515
        $operand1 = substr(str_pad($operand1, $numBits, '0', STR_PAD_LEFT), -$numBits);
70 515
        $operand2 = substr(str_pad($operand2, $numBits, '0', STR_PAD_LEFT), -$numBits);
71 515
        $result = '';
72 515 View Code Duplication
        for ($index = 0; $index < $numBits; $index++) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
73 515
            $result .= $operand1[$index] === '1' && $operand2[$index] === '1' ? '1' : '0';
74
        }
75
76 515
        return $this->reduce($result);
77
    }
78
79
    /**
80
     * Calculate the bitwise OR of two non-negative integers represented in binary form.
81
     *
82
     * @param string $operand1
83
     * @param string $operand2
84
     *
85
     * @return string
86
     */
87 500
    public function or($operand1, $operand2)
88
    {
89 500
        list($operand1, $operand2, $numBits) = $this->toSameLength($operand1, $operand2);
90 500
        $result = '';
91 500 View Code Duplication
        for ($index = 0; $index < $numBits; $index++) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
92 500
            $result .= $operand1[$index] === '1' || $operand2[$index] === '1' ? '1' : '0';
93
        }
94
95 500
        return $result;
96
    }
97
98
    /**
99
     * Zero-padding of two non-negative integers represented in binary form, so that they have the same length.
100
     *
101
     * @param string $num1
102
     * @param string $num2
103
     *
104
     * @return string[],int[] The first array element is $num1 (padded), the first array element is $num2 (padded), the third array element is the number of bits
0 ignored issues
show
Documentation introduced by
The doc-type string[],int[] could not be parsed: Expected "|" or "end of type", but got "," at position 8. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
105
     */
106 516
    private function toSameLength($num1, $num2)
107
    {
108 516
        $num1 = $this->reduce($num1);
109 516
        $num2 = $this->reduce($num2);
110 516
        $numBits = max(strlen($num1), strlen($num2));
111
112
        return array(
113 516
            str_pad($num1, $numBits, '0', STR_PAD_LEFT),
114 516
            str_pad($num2, $numBits, '0', STR_PAD_LEFT),
115 516
            $numBits,
116
        );
117
    }
118
}
119