Skip to content

Commit

Permalink
Implement BigInteger::testBit()
Browse files Browse the repository at this point in the history
  • Loading branch information
BenMorel committed Feb 16, 2020
1 parent a97c0bd commit d6c1421
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 0 deletions.
18 changes: 18 additions & 0 deletions src/BigInteger.php
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,24 @@ public function isOdd() : bool
return in_array($this->value[-1], ['1', '3', '5', '7', '9'], true);
}

/**
* Returns true if and only if the designated bit is set.
*
* Computes ((this & (1<<n)) != 0).
*
* @param int $n The bit to test, 0-based.
*
* @return bool
*/
public function testBit(int $n) : bool
{
if ($n < 0) {
throw new \InvalidArgumentException('The bit to test cannot be negative.');
}

return $this->shiftedRight($n)->isOdd();
}

/**
* {@inheritdoc}
*/
Expand Down
73 changes: 73 additions & 0 deletions tests/BigIntegerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2519,6 +2519,79 @@ public function providerIsOdd() : \Generator
}
}

/**
* @dataProvider providerTestBit
*
* @param BigInteger $number The number in base 2.
* @param int $n The bit to test.
* @param bool $expected The expected result.
*/
public function testTestBit(BigInteger $number, int $n, bool $expected) : void
{
self::assertSame($expected, $number->testBit($n));
}

public function providerTestBit() : \Generator
{
$base2BitsSetTests = [
['0', []],
['1', [0]],
['10', [1]],
['11', [0, 1]],
['100', [2]],
['101', [0, 2]],
['110', [1, 2]],
['111', [0, 1, 2]],
['100000010000000001000000000111', [0, 1, 2, 12, 22, 29]],
['101000010000000000001000100001000001000000100000100000000100000000001', [0, 11, 20, 26, 33, 39, 44, 48, 61, 66, 68]],
];

foreach ($base2BitsSetTests as [$number, $bitsSet]) {
$number = BigInteger::fromBase($number, 2);

// test up to 5 bits after the last bit set
$testBitCount = ($bitsSet[count($bitsSet) - 1] ?? 0) + 5;

for ($n = 0; $n < $testBitCount; $n++) {
$isSet = in_array($n, $bitsSet);
yield [$number, $n, $isSet];
}
}

$base10BitsUnsetTests = [
[-1, []],
[-2, [0]],
[-3, [1]],
[-4, [0, 1]],
[-5, [2]],
[-6, [0, 2]],
[-7, [1, 2]],
[-8, [0, 1, 2]],
[-9, [3]],
['-1181745669222511412225', [10, 20, 30, 40, 50, 60, 70]],
];

foreach ($base10BitsUnsetTests as [$number, $bitsUnset]) {
$number = BigInteger::of($number);

// test up to 5 bits after the last bit set
$testBitCount = ($bitsUnset[count($bitsUnset) - 1] ?? 0) + 5;

for ($n = 0; $n < $testBitCount; $n++) {
$isSet = ! in_array($n, $bitsUnset);
yield [$number, $n, $isSet];
}
}
}

public function testTestNegativeBitThrowsException() : void
{
$number = BigInteger::one();

$this->expectException(\InvalidArgumentException::class);
$number->testBit(-1);
}

/**
* @dataProvider providerCompareTo
*
Expand Down

0 comments on commit d6c1421

Please sign in to comment.