Odd and Even numbers (using & or %) - php

I've always used the following in order to find even and odd numbers:
if( $num % 2 ) { echo "odd"; }
if( !($num % 2) ) { echo "even"; }
But recently I stumbled upon with the following code that works exactly the same:
if( $num & 1 ) { echo "odd"; }
if( !($num & 1) ) { echo "even; }
What's the logic behind the "&" in the second method?
I went to check the PHP: Arithmetic Operators and the ampersand is not part of the options.
Thanks.

It is the bitwise-AND operator. Remember that in the computer, every integer is stored in binary form, and the lowest-significance binary digit is 2^0 == 1. So, every odd number will have the lowest binary digit = 1.
So, the bitwise AND operator compares your value bit-by-bit with the constant 1. Bits that are 1 in both operands are set to 1 in the result, but bits that are 0 in either operand are set to 0 in the result. The final result (which will be either 1 or 0) is coerced to boolean by PHP because you are using it as the clause in an if() statement.
There is a very good reason for checking evenness with & instead of %: Speed! The % operator requires a division operation so the remainder can be calculated, which is computationally much, much more expensive than just comparing the bits directly.
An example:
$num = 9; // 9 == 8 + 1 == 2^3 + 2^0 == 1001b
echo (string)($num & 1); // 1001b & 0001b = 0001b - prints '1'
$num = 10; // 10 == 8 + 2 == 2^3 + 2^1 == 1010b
echo (string)($num & 1); // 1010b & 0001b = 0000b - prints '0'

& is the binary AND.
The binary value of an odd number AND 1 will be 1, and the binary value of an even number AND 1 will be 0.
This happens because the binary value of an odd number always ends with 1 and the binary value of an even number ends with 0. So...
10101101 & 00000001 = 00000001 in the case of an odd number and,
10101100 & 00000000 = 00000000 in the case of an even number.

Related

Arithmetic operation not working php

I am trying to check if a number is odd or not but arithmetic operator % always returns 0.
$gst=($gst)*(100); // here $gst value is 155 after multiplication with 100
if(($gst%2)== 1)
{
$gst_receivable=(($gst-1)/2);
$gst_expense=(($gst-1)/2)+1;
}
else
{
$gst_receivable=($gst)/2;
$gst_expense=($gst)/2;
}
https://3v4l.org/8FQUf
But the above code always return 0 and runs the else part of the code.
You need to round() the variable before doing % 2 on it, because your float might still contain some rounding issues.
So change
if(($gst%2)== 1)
into
if(round($gst) % 2 == 1)

How bitwise operator works [duplicate]

This question already has answers here:
What are bitwise operators?
(9 answers)
Closed 7 years ago.
I dont get how the following codes work?
function odd($var){
return ($var & 1);
}
echo odd(4); /* returns and print 0 */
echo odd(5); /* returns and print 1 */
this function returns true if argument is an odd number
and returns false if argument is an even number. How it works ?
Odd numbers in binary always have a least-significant bit (LSB) of 1. That is why your code
function odd($var){
return ($var & 1);
}
returns true on odd numbers. Here are your examples from your question:
(decimal) 4 & 1 = (binary) 100 & 001 = (binary) 000 = (decimal) 0 = false
(decimal) 5 & 1 = (binary) 101 & 001 = (binary) 001 = (decimal) 1 = true
Another way to think of it is
100 (decimal 4) - an even number
AND 001 (decimal 1)
= 000 (decimal 0) - return false
and
101 (decimal 5) - an odd number
AND 001 (decimal 1)
= 001 (decimal 1) - return true
bitwise comparison already says what it does: it compares the numbers bit by bit.
If we take 4 bits, the bit representation of 4 is: 0100. The bit representation of 5 is 0101. When we compare this with & (and), it returns the bits which are both set.
0100 & 0001 = 0000 (no bits are the same)
0101 & 0001 = 0001 (only Least Significant Bit (LSB) is 1)
It is masking off all bits except 0. & is the and operator. And 1 is 000000000001 in binary. So it works as it is named.

Logic behind php if code

I'm trying to understand this code in the company's system that I am working in but this doesn't make any sense for me.
$k = 48;
if (($k & 2) > 0) {
echo "2 is true";
}
echo "<br />";
if (($k & 4) > 0) {
echo "4 is true";
}
echo "<br />";
if (($k & 8) > 0) {
echo "8 is true";
}
echo "<br />";
if (($k & 16) > 0) {
echo "16 is true";
}
echo "<br />";
if (($k & 32) > 0) {
echo "32 is true";
}
When $k is 10 or 11, both 2 and 8 is true.
When $k is 12 or 13, both 4 and 8 is true.
Please help me figure this out
This code is simply checking if certain bit positions are set in some value $k. See how bitwise airthmetic works.
In the code you've sent us, it doesn't have much context. However, this is a typical pattern for checking values in a bitmask.
In general, however, the > 0 is unnecessary (since anything !0 typically == true).
It is important to note that when I say bit positions, I mean of the binary number. That is, $k & 32 does not check bit number 32, it instead checks the 6th most significant bit (32d == 0b100000).
Short example
Consider the last statement. We already determined that decimal 32 looks like 100000 in binary. Now say that we want to check whether or not the 6th bit is set in some number 33. 33 is represented as 0b100001 in binary. Now we take the bitwise and which works much like multiplication that we're used to seeing in base 10 (i.e. decimal).
0b100000 <--- decimal 32
&
0b100001 <--- decimal 33
--------
0b100000 <--- Result is > 0 and, therefore, this value has the 6th bit set
Now, let's retry this example with a different number. How about decimal 15.
0b100000 <--- decimal 32
&
0b001111 <--- decimal 15
--------
0b000000 <--- Result == 0 and, therefore, the 6th bit is not set
Now, this & (not to be confused with logical and which is represented as &&) works for multiple bits as well. Say you want to check for bits 6 and 4, then you would want to use 0b101000 (decimal 40), but depending on what you wanted to test (i.e. exactly those bits or just one of those bits), your conditional may change.
Just a little bit more
From a style standpoint it is important to note that these masks are typically represented in hexadecimal instead of decimal (or binary because that would be cumbersome). This is mostly because it is somewhat unclear what binary representation a decimal number correlates to when looking at it "at-a-glance." Let us again consider decimal 32. In hexadecimal, a binary number can be represented as a hexadecimal number by simply grouping bits by 4's (from right to left). See below
0b100000 <--- decimal 32
0000 === 0x0 (hexadecimal 0)
10 === 0b0010 (implied leading 0's) === 0x2 (hexadecimal 2)
--------
0x20
As you can see, hex 20 is decimal 32 is binary 100000.
In your code there are just some bitwise AND operation which checks if some bits are set or not.
So if we take a look what's going on in the first one:
$k = 48;
if (($k & 2) > 0) {
echo "2 is true";
}
The expression ($k & 2) a bit more readable:
0011 0000 $k
0000 0010 2
------------ &
0000 0000 = 0
So if (0 > 0) is false
And another example:
if (($k & 16) > 0) {
echo "16 is true";
}
The expression ($k & 16) a bit more readable:
0011 0000 $k
0001 0000 16
------------ &
0001 0000 = 16
So if (16 > 0) is true
FYI information:
Bitwise AND operation table:
A | B | Result
--------------------
0 | 0 | 0
0 | 1 | 0
1 | 0 | 0
1 | 1 | 1
And as a reference to the manual here: http://php.net/manual/en/language.operators.bitwise.php

Is there a clever way to do this with pure math

I've got this spot of code that seems it could be done cleaner with pure math (perhaps a logarigthms?). Can you help me out?
The code finds the first power of 2 greater than a given input. For example, if you give it 500, it returns 9, because 2^9 = 512 > 500. 2^8 = 256, would be too small because it's less than 500.
function getFactor($iMaxElementsPerDir)
{
$aFactors = range(128, 1);
foreach($aFactors as $i => $iFactor)
if($iMaxElementsPerDir > pow(2, $iFactor) - 1)
break;
if($i == 0)
return false;
return $aFactors[$i - 1];
}
The following holds true
getFactor(500) = 9
getFactor(1000) = 10
getFactor(2500) = 12
getFactor(5000) = 13
You can get the same effect by shifting the bits in the input to the right and checking against 0. Something like this.
i = 1
while((input >> i) != 0)
i++
return i
The same as jack but shorter. Log with base 2 is the reverse function of 2^x.
echo ceil(log(500, 2));
If you're looking for a "math only" solution (that is a single expression or formula), you can use log() and then take the ceiling value of its result:
$factors = ceil(log(500) / log(2)); // 9
$factors = ceil(log(5000) / log(2)); // 13
I seem to have not noticed that this function accepts a second argument (since PHP 4.3) with which you can specify the base; though internally the same operation is performed, it does indeed make the code shorter:
$factors = ceil(log(500, 2)); // 9
To factor in some inaccuracies, you may need some tweaking:
$factors = floor(log($nr - 1, 2)) + 1;
There are a few ways to do this.
Zero all but the most significant bit of the number, maybe like this:
while (x & x-1) x &= x-1;
and look the answer up in a table. Use a table of length 67 and mod your power of two by 67.
Binary search for the high bit.
If you're working with a floating-point number, inspect the exponent field. This field contains 1023 plus your answer, except in the case where the number is a perfect power of two. You can detect the perfect power case by checking whether the significand field is exactly zero.
If you aren't working with a floating-point number, convert it to floating-point and look at the exponent like in 3. Check for a power of two by testing (x & x-1) == 0 instead of looking at the significand; this is true exactly when x is a power of two.
Note that log(2^100) is the same double as log(nextafter(2^100, 1.0/0.0)), so any solution based on floating-point natural logarithms will fail.
Here's (nonconformant C++, not PHP) code for 4:
int ceillog2(unsigned long long x) {
if (x < 2) return x-1;
double d = x-1;
int ans = (long long &)d >> 52;
return ans - 1022;
}

Finding if a number is a power of 2

Just out of curiosity, how can you tell if a number x is a power of two (x = 2^n) without using recursion.
Thanks
One way is to use bitwise AND. If a number $x is a power of two (e.g., 8=1000), it will have no bits in common with its predecessor (7=0111). So you can write:
($x & ($x - 1)) == 0
Note: This will give a false positive for $x == 0.
Subtract 1 from the number, then and it with the original number. If the result is zero, it was a power of two.
if (((n-1) & n) == 0) {
// power of two!
}
(sorry, my PHP is rusty...)
If it's a power of 2? Well, one way is to convert it to binary, and verify the presence of only 1 1...:
$bin = decbin($number);
if (preg_match('/^0*10*$/', $bin)) {
//Even Power Of 2
}
For completeness, if the number is a float, you can test if it's a power of two by chacking if the mantissa is all zeros:
<?php
$number = 1.2379400392853803e27;
$d = unpack("h*", pack("d", $number)); $d = reset($d);
$isPowerOfTwo = substr($d, 0, 13) == "0000000000000";
var_dump($isPowerOfTwo); // bool(true)
Exercise for the reader: corner cases and big-endian machines.
In a binary equivalent of any decimal number which is a power of two will have only one occurrence of 1 in its binary equivalent.
<?php
$number = 4096;
$bin = decbin($number);
if ($number != 1 && substr_count($bin,1) == 1) {
echo "Yes";
} else {
echo "No";
}
?>
The top answer:
($x & ($x - 1)) == 0
seemed to have issues with larger numbers for me, this works well for larger numbers using the same logic but with GMP:
gmp_strval(gmp_and($x, gmp_sub($x, 1))) == 0
use mod 2 to determine if a number is a power of 2
def is_power_of_2(n):
if n == 0:
return False
while n % 2 == 0:
n = n / 2
return n == 1
I tried to implement the same thing without bitwise operators. Finally, I ended up with
return (fmod(log($x, 2), 1) === 0.00)
(In PHP)
Math.log(x)/Math.log(2) == Math.floor(Math.log(x)/Math.log(2))

Categories