PHP modulus operator for doubles - php

I read here that:
Modulus with non integer numbers will give unpredictable results.
However, I tried to play a bit with it, and it seems to give pretty predictable results:
function mod($a, $b) {
echo "$a % $b = " . ($a % $b) . '<br>';
}
mod(10.3, 4);
mod(10.3, 2);
mod(-5.1, 3);
// OUTPUT:
// 10.3 % 4 = 2
// 10.3 % 2 = 0
// -5.1 % 3 = -2
In other words, the double seems to be converted to integer first.
Is there any definition of how % works when the first operand is double?

use:
fmod(10.3, 4)
I too had to do the same thing but I noticed doubles are converted to int and using fmod returns a double.
If this helps
From http://php.net/manual/en/language.operators.arithmetic.php
The result of the modulus operator % has the same sign as the dividend — that is, the result of $a % $b will have the same sign as $a.

Related

Float division returning int - PHP 7

Doing what should be a straight forward calculation in PHP 7. The following never produces a float result. Running var_dump($C) returns int(2)
$A = 0.04;
$B = 0.20;
$C = 3*($A/$B)^2;
echo $C;
I don't need the result to be float type, I need the precision.
I've tried setting the precision using ini_set('precision', n). I've tried the code on three environments and getting the same result. Declaring (float) is also does not work.
What am I doing wrong?
3*($A/$B)^2
Means 3 * (A/B) XOR 2 (^ means xor) so bascially the result you are seeing is the result of a bitwise XOR on the result of your division.
If you want to raise the result to the power 2, you should use the pow() function. You can read about it here: http://php.net/manual/en/function.pow.php .
^ does not calculate the power, but XOR (which casts float to int).
to calculate the power, use pow() or in PHP5.6+ **
<?php
$A = 0.04;
$B = 0.20;
$C = 3*($A/$B)**2;
echo $C; //output: 0.12
You should use pow() instead.
$C = 3 * pow(($A/$B), 2);
var_dump($C); // float(0.12)
try using
<?php
$A = 0.04;
$B = 0.20;
$C = 3 * pow(($A/$B),2);
echo $C; //output: 0.36

Modulo negative floats using "%" and gmp_mod does not work

I try to get the result of -0.15 modulo 5 in PHP.
Following codes always return 0.
$mod = ((-0.15) % 5)
$mod = (-0.15 % 5)
$mod = gmp_mod("-0,15", "5");
$mod = gmp_mod(-0.15, 5);
When I type "-0.15 mod 5" into google, it returns: 4.85
What is wrong with the code I use in PHP?
According to http://php.net/language.operators.arithmetic, "Operands of modulus are converted to integers (by stripping the decimal part) before processing."
So $mod = 0 % 5, which would be 0.

Odd and Even numbers (using & or %)

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.

Why is $a + ++$a == 2?

If I try this:
$a = 0;
echo $a + ++$a, PHP_EOL;
echo $a;
I get this output:
2
1
Demo: http://codepad.org/ncVuJtJu
Why is that?
I expect to get this as an output:
1
1
My understanding:
$a = 0; // a === 0
echo $a + ++$a, PHP_EOL; // (0) + (0+1) === 1
echo $a; // a === 1
But why isn't that the output?
All the answers explaining why you get 2 and not 1 are actually wrong. According to the PHP documentation, mixing + and ++ in this manner is undefined behavior, so you could get either 1 or 2. Switching to a different version of PHP may change the result you get, and it would be just as valid.
See example 1, which says:
// mixing ++ and + produces undefined behavior
$a = 1;
echo ++$a + $a++; // may print 4 or 5
Notes:
Operator precedence does not determine the order of evaluation. Operator precedence only determines that the expression $l + ++$l is parsed as $l + (++$l), but doesn't determine if the left or right operand of the + operator is evaluated first. If the left operand is evaluated first, the result would be 0+1, and if the right operand is evaluated first, the result would be 1+1.
Operator associativity also does not determine order of evaluation. That the + operator has left associativity only determines that $a+$b+$c is evaluated as ($a+$b)+$c. It does not determine in what order a single operator's operands are evaluated.
Also relevant: On this bug report regarding another expression with undefined results, a PHP developer says: "We make no guarantee about the order of evaluation [...], just as C doesn't. Can you point to any place on the documentation where it's stated that the first operand is evaluated first?"
A preincrement operator "++" takes place before the rest of the expression it's in evaluates. So it is actually:
echo $l + ++$l; // (1) + (0+1) === 2
a + b
a = 1
b = ++a
:= 2
Why do you expect something else?
In PHP:
$a = 0;
$c = $a + ++$a;
Operator precedence visualized:
$c = ($a) + (++$a);
Evaluation sequence visualized:
$a = 0; ($a = 0)
$a = 1; (++$a)
$c = $a + $a (1 + 1);
Or written out:
The moment the sum operation is performed, $a is already 1 because ++$a has been already evaluated. The ++ operator is evaluated before the + operator.
For the fun:
$a++ + ++$a
Results in 2, too. However if you compare it as an expression, it's not equal:
$a++ + ++$a == $a + ++$a
Where as
$a++ + ++$a == $a-- + --$a
is "equal".
See Also:
Order of evaluation in PHP (Sep 2013; by NikiC) (via)
My Evaluation Order in PHP blog post explain this in detail, but here is the basic idea:
Operator precedence and associativity have nothing to do with evaluation order.
PHP does not guarantee an evaluation order. The order can change between PHP versions without notice and can also be different depending on the surrounding code.
"Normally" PHP will evaluate left-to-right, with the exception of accesses to "simple" variables (like $a). Accesses to simple variables will be executed after more complex expressions, regardless in which order the expressions actually occur.
In this particular case it means that ++$a is run first because it is a complex expression and only then the value of $a is fetched (it is already 1 at this point). So effectively you are summing 1 + 1 = 2.
The reason that simple variables are fetched after complex expressions is the Compiled Variables (CV) optimization. If you disable this optimization, for example by using the # error suppression operator, all expressions are evaluated left-to-right, including simple variable fetches.
In this particular case it means that #($a + ++$a) will result in 1, because first $a is fetched (0 at that time) and incremented only after that.
++ is the higher precedence operator, so it gets applied first.
So now l = 1.
So 1 + 1 = 2.
When you do your ++$l (preincrement), it will be done before your addition -> check operator precedence).
So, the value of $l will be 1 before your addition :
echo $l + ++$l; // $l => 1 because ++$l is done first
So your answer will be 2.
But when you do :
echo $l // you will get your first value which is $l => 1
So your answer will be 1.
This behaviour can be confirmed by inspecting how PHP compiles your script, for example:
$a = 0;
echo $a + ++$a;
Compiles into the following opcodes, which are then executed:
compiled vars: !0 = $a
line # * op fetch ext return operands
---------------------------------------------------------------------------------
1 0 > ASSIGN !0, 0
1 PRE_INC $1 !0
2 ADD ~2 !0, $1
3 ECHO ~2
4 > RETURN null
This translates to the following equivalent script:
$a = 0; // ASSIGN
$tmp = ++$a; // PRE_INC
echo $a + $tmp; // ADD, ECHO
Conclusion
By the time $a is evaluated as the left hand expression of $a + (++$a), it has already been incremented, because ++$a was evaluated first.
Obviously, this behaviour should not be relied upon; in any language for that matter.
Check the increment operator manual:
http://www.php.net/manual/en/language.operators.increment.php
Or see this codepad: http://codepad.org/Y3CnhiLx
<?php
$n = 0;
$m = 0;
echo '++ before:';
echo $n+ ++$n;
echo PHP_EOL;
echo '++ after:';
echo $m+ $m++;
echo PHP_EOL;
echo 'n:'.$n;
echo PHP_EOL;
echo 'm:'.$m;
Outputs:
++ before:2
++ after:1
n:1
m:1
As you may know we have two increment operator, one is pre-increment and second is post-increment. Pre-increment increase the value of integer before it use in expression, on the other hand post increment increase value of number after it used in expression.
suppose you have variable $a and variable $b as below
$a=0;
$b=++$a gives the value of b=1
while
$b=$a++ gives the value b=0
The output of your code varies with PHP version as seen here
Output for 4.3.0 - 5.0.5
1
1
In the above case the left hand side of + operator is evaluated first (0, 1, +).
Output for 5.1.0 - 5.5.0alpha4
2
1
In the above case the right hand side of + operator is evaluated first (1, 1, +).
This is in accordance with interjay's answer that in PHP there is no guarantee about the order of evaluation of sub-expresions. The assumption that the output could be 1, 1 is correct, so are that answers that claim that the output could be 1, 2.
First obvious part is that ++ have higher priority than +.
Second part is that php engine doesn't store value from first operand into another anonymous variable. So $l + ++$l is not an qeuivalent for
$a = $l;
$b = ++$l;
return $a + $b;
As mentioned before there is a difference in x++ and ++x. You can interpret it in the way that
x++;
increments after the semicolon
and
++x;
increments on evaluation of the expression
So it seems that your expression is evaluated from right to left
echo $l + ++$l;
Get $l: $l = 0
Apply ++: ++$l = 1
Get $l: $l = 1
Apply +: $l + $l = 1 + 1 = 2
All statements are executed from right to left.
So the value is first incremented than the value of your variable is = 1 so 1+1=2

Dividing with a remainder in PHP

I have a part in my code where I need to divide and have a remainder instead of a decimal answer.
How can I do this?
$quotient = intval($dividend / $divisor);
$remainder = $dividend % $divisor;
Using intval instead of floor will round the quotient towards zero, providing accurate results when the dividend is negative.
You can do what you are describing using the "%" (modulus) operator. The following code is an example of dividing with a remainder.
$remainder=$num % $divideby;
$number=explode('.',($num / $divideby));
$answer=$number[0];
echo $answer.' remainder '.$remainder;
A solution for positive and negative numbers:
$quotient = $dividend / $divison;
$integer = (int) ($quotient < 0 ? ceil($quotient) : floor($quotient));
$remainder = $dividend % $divisor;
The mathematical correct answer is:
remainder = dividend % divisor;
quotient = (dividend - remainder) / divisor;
and the remainder verifies the condition 0 <= remainder < abs(divisor).
Unfortunately, many programming languages (including PHP) don't handle the negative numbers correctly from the mathematical point of view. They use different rules to compute the value and the sign of the remainder. The code above does not produce the correct results in PHP.
If you need to work with negative numbers and get the mathematical correct results using PHP then you can use the following formulae:
$remainder = (($dividend % $divider) + abs($divider)) % abs($divider);
$quotient = ($dividend - $remainder) / $divider;
They rely on the way PHP computes modulus with negative operands and they may not provide the correct result if they are ported to a different language.
Here is a script that implements these formulae and checks the results against the values provided as example in the aforementioned mathematical correct answer.
If you need to look it up, the % operator is called mod (or modulus).
I had to develop this approach because my numerator was a float value and modulus was rounding results.
Using Raffaello's approach offered here for dividing floats and taking from Sam152's solution above came up with the following.
$a = 2.1;
$b = 8;
$fraction = $a / (float) $b;
$parts = explode('.', $fraction);
$int = $parts[0];
$remainder = $score - ($int*$b) ;
Use This Function Its an array
Description
array gmp_div_qr ( resource $n , resource $d [, int $round ] )
The function divides n by d .
reference : http://php.net/manual/en/function.gmp-div-qr.php
An example to show strings like 1 hour 6 minutes using floor() and modulus (%) if only minutes/seconds given:
$minutes=126;
if($minutes < 60) {
$span= $minutes.' min.';
} else {
$rem=$minutes % 60;
$span=floor($minutes/60).' h. '. (($rem>0) ? $rem.' min.':'');
}
// echo 'Hello Jon Doe, we notify you that even will last for 2 h. 6 min.
echo 'Hello Jon Doe, we notify you that event will last for '.$span;
It seems to be an old post, but for those who might be interested here is a very light package that could meet your needs: https://github.com/romainnorberg/residue (feedbacks are welcome)

Categories