Why my mathematical if statement fails? - php

I am writing simple drop formula for player A vs. B fights - level difference determinates drop rate. My issue here is that instead of 0: > 10 ||| 1 vs. 1 = 10% it gives 0: > 10 ||| 1 vs. 1 = 0% - why?
PhpFiddle: http://www.phpfiddle.org/main/code/n1q-dw7
<?php
# lets simulate high level player A attacks low level player B
for ($A = 1; $A <= 100; $A++) {
$B = 1;
calculateMoneyDrop($A,$B);
}
# lets simulate low level player A attacks high level player B
for ($B = 1; $B <= 100; $B++) {
$A = 1;
calculateMoneyDrop($A,$B);
}
function calculateMoneyDrop($A,$B) {
$X = $A - $B;
echo '<strong>', $X, '</strong>: ';
switch ($X) {
case $X > 10:
echo "> 10 ||| ";
$X = 10;
break;
case $X < -90:
echo "< -90 ||| ";
$X = -90;
break;
}
$dropRate = 10 - $X;
echo $A, ' vs. ', $B, ' = ', $dropRate, '%<br>';
}

It's simply how switch-case works. It checks whether $X equals to the value you list in case. Since that value is a boolean (result of a comparison is a boolean!), and PHP has a crazy way to compare different types (in this case int and bool), that block of case will actually be executed.
Use if statements, or use min and max.

If you change your switch to
switch (true) {
the original code runs correctly.
Perhaps someone with better php than me can explain why!
http://www.phpfiddle.org/main/code/6pg-nwc

Well, in your $X > 10 case you set $X = 10 and later calculate $dropRate as 10 - $X, which is 10 - 10, which is 0.
Either the $dropRate should be $X if the desired outcome is 10. It also strikes me funny that the output says $X == 0 first, but then enters the switch case $X > 10... Are you sure that you're showing us all the code?
Also I don't think it's good practice to use the switch case like that. This is a typical candidate for an if block.

Your switch block does the same as:
if(($X > 10)==$X){
echo "> 10 ||| ";
$X = 10;
}
else if(($X < -90)==$X){
echo "< -90 ||| ";
$X = -90;
}
It compares whatever you have at "case" to whatever you have in the switches parentheses.
Switch is used only for "equals" comparisons.
so, to make it work, use:
if($X > 10){
echo "> 10 ||| ";
$X = 10;
}
else if($X < -90){
echo "< -90 ||| ";
$X = -90;
}

Related

Test whenever a value x is greater by exactly 1 compared to a value y modulo 3

How do I check that x is 1 greater (ahead) of y in a modulo sense (mod 3)?
This is when x = 0 and y = 2, when x = 1, y = 0 and when x = 2, y = 1.
I tried testing like this:
php -a
php > $x = 0;
php > $y = 2;
php > echo ($x - $y) % 3;
-2
php > $x = 1;
php > $y = 0;
php > echo ($x - $y) % 3;
1
php > $x = 2;
php > $y = 1;
php > echo ($x - $y) % 3;
1
It is not working for the case where x = 0 and y = 2. How can I calculate this so that $x is 'ahead' of $y by 1 in a modulo sense?
I will first explain my understanding of your following sentence:
How do I check that x is 1 greater (ahead) of y in a modulo sense (mod 3)?
Following the examples provided, I assume you mean that, if 1 is added to $y, and we take the mod 3 of $y, we would get the mod 3 of $x.
With that in mind, we could write the following code, witch would return true if $x is "ahead" of $y by 1. (I hope you can abstract that example to whatever situation you are facing):
function check($x, $y, $mod) {
return $x % $mod == ($y + 1) % $mod;
}
//$x = 0 and $y = 2
echo check(0,2,3); //returns true
//$x = 1 and $y = 0
echo check(1,0,3); //returns true
//$x = 2 and $y = 1
echo check(2,1,3); //returns true
//$x = 0 and $y = 1
echo check(0,1,3); //returns false because $x is 2 "ahead" of $y
If you want a more generalized version of the function, with an arbitrary difference, you can use this (it should work with positive and negative differences):
function check($x, $y, $mod, $diff) {
return $x % $mod == ($y + $diff) % $mod;
}
Why is it that you used 0 for x and 2 for y? (Sorry, but I'm not much of an algebraist.)
Although your situations are pretty much clarified, it doesn't make sense (at least for me) that x would be 1 bit ahead of y when it is clearly 0 < 2.
As we know, the statement (0 - 2) % 3 would be -2 because the mod is 3, and 0 - 2 is -2, so the result is -2.
Mathematics can have some illogical sense (in my opinion) sometimes, so its worth noting that 0 isn't ahead of 2 (in the sense of programming variables) at all.
And to actually answer your question on calculation, you could have x = 0 and y = -1 as your variables instead, as per se the logic of your statement, then just increment by 1 for both variables, and the result is still the same.
Proof:
<?php
$x = 0
$y = -1
echo ($x - $y) % 3 // outputs 1
echo (++$x - ++$y) % 3 // still outputs 1
echo (++$x - ++$y) % 3 // also outputs 1
echo (++$x - ++$y) % 3 // yep, still the same
echo (++$x - ++$y) % 3 // alright, you get the deal
?>

Another FizzBuzz solution [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I was in a job interview and was asked to solve FizzBuzz with PHP.
Write a program that prints the numbers from 1 to 100. But for multiples of three print “Fizz” instead of the number and for the multiples of five print “Buzz”. For numbers which are multiples of both three and five print “FizzBuzz”.
I never heard of FizzBuzz before but here is how I solved it because I didn't know modulo or how to use it.:
for ($i = 1; $i <= 100; $i++){
if($i / 3 == round($i / 3) && $i / 5 == round($i / 5)){
echo $i . " is FizzBuzz<br />";
}
else if($i / 3 == round($i / 3)){
echo $i . " is Fizz<br />";
}
else if($i / 5 == round($i / 5)){
echo $i . " is Buzz<br />";
}
else {
echo $i."<br />";
}
}
I googled and didn't find any solution with round and that got me thinking that maybe there is something wrong with it, this is one of the solutions I found that is close to mine:
for ($i = 1; $i <= 100; $i++){
if($i % 3 == 0 && $i % 5 ==0){
echo "FizzBuzz<br />";
}
else if($i % 3 == 0){
echo "Fizz<br />";
}
else if($i % 5 == 0){
echo "Buzz<br />";
}
else {
echo $i."<br />";
}
}
My code is working fine but is there anything wrong with it that I don't see?
Actually they are testing how you will solve such simple task. It should be increadibly optimized, the code shouldbe clean and easy readable.
Your version of code is not good.
The version you've found in the internet is better, but it's not ideal from the point of the optimization.
Try to think how to get the goal with less actions.
Some tips:
do not use functions (such as range) for this task - it will only slow down the script execution time
use operator "for" for this task, do not use any other (while, do-while, foreach), because operator "for" the best fits in this case (you know how many iterations you need).
do not use round function, use modulus operator "%", because any function works slower than any operator
in the result you need to get code, in which the number of operations will be the least as possible (the number of "if" statements, the number of operators like "==" or "%"
Use 15 instead of % 3 && % 5 - less calculations - faster execution time.
My example of code:
for ($i = 1; $i <= 100; $i++) {
if ($i % 15 == 0) {
echo 'FizzBuzz<br>';
} elseif ($i % 3 == 0) {
echo 'Fizz<br>';
} elseif ($i % 5 == 0) {
echo 'Buzz<br>';
} else {
echo $i . '<br>';
}
}
Code style and lack of optimization gives impression of a newbie to the interviewer. My tips are:
Follow PSR-2
Never use else (restructure, use early returns/continues)
Always try to reduce the number of ifs (code complexity)
Use "identical" operators for comparison when dealing with integers and nulls (and any other type)
Do not use <br/> when HTML is never mentioned
Try to keep maintainability:
Extract match calculations in variables/functions, so they can be easily changed
Do not overcomplicate.
Try to optimize mathematically:
Use %15 instead of %3 and %5 check
You can also skip the above at all (check for %15), as you already have calculated that. Boolean operations are much faster.
Try not to calculate something twice.
IMHO, to follow all good practices your code should look like this:
for ($i = 1; $i <= 100; $i++) {
$isFizz = (0 === $i % 3);
$isBuzz = (0 === $i % 5);
if (!$isFizz && !$isBuzz) {
echo $i . PHP_EOL;
continue;
}
if ($isFizz) {
echo 'Fizz';
}
if ($isBuzz) {
echo 'Buzz';
}
echo PHP_EOL;
}
Test
There is yet another tricky solution
for ($i = 1; $i <= 100; $i++) {
switch ($i % 15) {
case 3:
case 6:
case 9:
echo 'Fizz';
break;
case 5:
case 10:
echo 'Buzz';
break;
case 0:
echo 'FizzBuzz';
break;
default:
echo $i;
break;
}
echo PHP_EOL;
}
if you read carefully it says "instead".
this is another short and clean solution of the FizzBuzz problem :
foreach (range(1, 100) as $number) {
if(0 !== $number % 3 && 0 !== $number % 5) {
echo $number.'<br>';
continue;
}
if(0 === $number % 3) {
echo 'Fizz';
}
if(0 === $number % 5) {
echo 'Buzz';
}
echo '<br>';
}
the output is :
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16

"break" doesn't work as expected

I want to check the string length of comment array.
Once any of them is equal or higher than 4, I want to echo the relevant value, and then stop.
I guessed that using while should be good,
but if I break the loop at 4 or more, nothing gets echoed.
If I will break it at 5 or more, the previous two 4-string values will be echoed, but I want only the first 4-string value to get echoed, and then stop.
$comment[1] = "abc"; // add comment below text button
$comment[2] = "xyz"; // add comment below text button
$comment[3] = "abcd"; // add comment below text button
$comment[4] = "xyza"; // add comment below text button
$comment[5] = "abcde"; // add comment below text button
$comment[6] = "xyzab"; // add comment below text button
$x = 1;
while ($x <= 10) {
if (strlen((string)$comment[$x]) >= 4 ) {
echo $comment[$x];
echo "<br/>";
}
$x = $x + 1;
if (strlen((string)$comment[$x]) >= 4) break; // Nothing get echoed
// if (strlen((string)$comment[$x]) >= 5) break; // two values get echoed
}
Also, is there maybe a better/shorter practice to check this thing, maybe some built in function like in_array?
The problem with your code is that your loop body checks/prints one element and breaks on different one because you increment the pointer between those two points. You could have moved your break statement above the increment, or even put it into that if statement (much like #A-2-A suggested). Then it should work as expected.
With break above the increment:
while ($x <= 10) {
if (strlen((string)$comment[$x]) >= 4 ) {
echo $comment[$x];
echo "<br/>";
}
if (strlen((string)$comment[$x]) >= 4) break;
$x = $x + 1;
}
With combined echo/break:
while ($x <= 10) {
if (strlen((string)$comment[$x]) >= 4 ) {
echo $comment[$x];
echo "<br/>";
break;
}
$x = $x + 1;
}
Also you may want to iterate the array up to it's length instead of hardcoded limit of 10:
$x = 0;
$length = count($comment);
while ($x < $length) {
// ...
}

Find what 2 numbers add to something and multiply to something

Hey so I'm making a factoring program and I'm wondering if anyone can give me any ideas on an efficient way to find what two numbers multiple to a specified number, and also add to a specified number.
for example I may have
(a)(b) = 6
a + b = 5
So essentially i just need a way to find the a and b values. In this case they would be 2 and 3.
Can anyone give me any ideas on where to start? Negative numbers must also be considered for use.
There is no need to loop, just use simple math to solve this equation system:
a*b = i;
a+b = j;
a = j/b;
a = i-b;
j/b = i-b; so:
b + j/b + i = 0
b^2 + i*b + j = 0
From here, its a quadratic equation, and it's trivial to find b (just implement the quadratic equation formula) and from there get the value for a.
There you go:
function finder($add,$product)
{
$inside_root = $add*$add - 4*$product;
if($inside_root >=0)
{
$b = ($add + sqrt($inside_root))/2;
$a = $add - $b;
echo "$a+$b = $add and $a*$b=$product\n";
}else
{
echo "No real solution\n";
}
}
Real live action:
http://codepad.org/JBxMgHBd
Here is how I would do that:
$sum = 5;
$product = 6;
$found = FALSE;
for ($a = 1; $a < $sum; $a++) {
$b = $sum - $a;
if ($a * $b == $product) {
$found = TRUE;
break;
}
}
if ($found) {
echo "The answer is a = $a, b = $b.";
} else {
echo "There is no answer where a and b are both integers.";
}
Basically, start at $a = 1 and $b = $sum - $a, step through it one at a time since we know then that $a + $b == $sum is always true, and multiply $a and $b to see if they equal $product. If they do, that's the answer.
See it working
Whether that is the most efficient method is very much debatable.
With the multiplication, I recommend using the modulo operator (%) to determine which numbers divide evenly into the target number like:
$factors = array();
for($i = 0; $i < $target; $i++){
if($target % $i == 0){
$temp = array()
$a = $i;
$b = $target / $i;
$temp["a"] = $a;
$temp["b"] = $b;
$temp["index"] = $i;
array_push($factors, $temp);
}
}
This would leave you with an array of factors of the target number.
That's basically a set of 2 simultaneous equations:
x*y = a
X+y = b
(using the mathematical convention of x and y for the variables to solve and a and b for arbitrary constants).
But the solution involves a quadratic equation (because of the x*y), so depending on the actual values of a and b, there may not be a solution, or there may be multiple solutions.

PHP why is continue n slower than using break

Please consider the following code:
$start = microtime();
for($i = 2; $i < 100; $i++)
{
for($y = 2; $y <= sqrt($i); $y++)
{
if($i%$y != 0)
{
continue;
}
else
{
continue 2;
}
}
echo $i.',';
}
echo "\nFinished in " . (microtime() - $start);
Given that the above code effectively uses continue 2 to break the inner loop and skip any code post the inner loop, why does the following code on average execute faster when it appears to do more:
$start = microtime();
for($i = 2; $i < 100; $i++)
{
$flag = true;
for($y = 2; $y <= sqrt($i); $y++)
{
if($i%$y != 0)
{
continue;
}
else
{
$flag = false;
break;
}
}
if($flag === true) echo $i.',';
}
echo "\nFinished in " . (microtime() - $start);
Thanks for any input.
_____ Update ____________
Thanks for the feedback but we seem to have missed the point. Regardless of if this is good programming practice I was trying to understand why the performance difference (which is tiny but consistent) is not within the bias I expected.
The passing of true to microtime seems insignificant as both samples are measured using the same method with the same overhead and the same inaccuracy.
More than one run was tested, as implied by use of the word average.
Just for illustration please consider the following small samples using microtime(true) which shows the same pattern as using microtime().
I know this is a small sample but the pattern is quite clear:
Continue
0.00037288665771484
0.00048208236694336
0.00046110153198242
0.00039386749267578
0.0003662109375
Break
0.00033903121948242
0.00035715103149414
0.00033307075500488
0.00034403800964355
0.00032901763916016
Thanks for looking, and thanks for any further feedback.
______ UPDATE Further investigation ____________
Interestingly if the echo statements are removed from the code the continue performs faster, with the echo statements in place break is faster.
Please consider the following code sample, and consider that the results are in conflict dependant on if the echo statements are removed or not:
<?php
$breakStats = array();
$continueStats = array();
ob_start();
for($i = 0; $i < 10000; $i++)
{
$breakStats[] = doBreakTest();
$continueStats[] = doContinueTest();
}
ob_clean();
echo "<br/>Continue Mean " . (array_sum($continueStats) / count($continueStats));
echo "<br/>Break Mean " . (array_sum($breakStats) / count($breakStats));
function doBreakTest()
{
$start = microtime(true);
for($i = 2; $i < 100; $i++)
{
$flag = true;
$root = sqrt($i);
for($y = 2; $y <= $root; $y++)
{
if($i%$y != 0)
{
continue;
}
else
{
$flag = false;
break;
}
}
}
if($flag === true) echo $i . '';
return microtime(true) - $start;
}
function doContinueTest()
{
$start = microtime(true);
for($i = 2; $i < 100; $i++)
{
$root = sqrt($i);
for($y = 2; $y <= $root; $y++)
{
if($i%$y != 0)
{
continue;
}
else
{
echo $i . '';
continue 2;
}
}
}
return microtime(true) - $start;
}
Echo statements present :
Continue Mean 0.00014134283065796
Break Mean 0.00012669243812561
Echo statements not present :
Continue Mean 0.00011746988296509
Break Mean 0.00013022310733795
Note that by removing the echo statement from the break and flag test we also remove the ($flag === true) check, so the load should reduce, but continue in this case still wins. W
So in a pure continue n versus break + flag scenario, it appears that continue n is the faster contstruct. But add an equal number of identical echo statements, and the continue n performance flags.
This makes sense to me logically that continue n should be faster, but I would have expected to see the same with the echo statements present.
This is clearly a difference in the generated opcodes, and the position of the echo statement (inner loop vs outer loop) does anyone know a way of seeing the opcodes generated? This I suppose is ultimatley what I need as I am trying to understand what is happening internally.
Thanks :)
Yes, first one is bit faster. It's because it just jumps out on continue 2 and prints $i.
2nd example has more job to do... assign value to $flag variable, jumps out of loop, checks $flag's value, checks $flag's type (compares too) and then prints out $i. It's bit slower (simple logic).
Anyways, has it any purpose?
Some of my results for comparing
0.0011570 < 0.0012173
0.0011540 < 0.0011754
0.0011820 < 0.0012036
0.0011570 < 0.0011693
0.0011970 < 0.0012790
Used: PHP 5.3.5 # Windows (1000 attempts; 100% first was faster)
0.0011570 < 0.0012173
0.0005000 > 0.0003333
0.0005110 > 0.0004159
0.0003900 < 0.0014029
0.0003950 > 0.0003119
0.0003120 > 0.0002370
Used: PHP 5.3.3 # Linux (1000 attempts; 32% first : 68% second was faster)
0.0006700 > 0.0004863
0.0003470 > 0.0002591
0.0005360 > 0.0004027
0.0004720 > 0.0004229
0.0005300 > 0.0004366
Used: PHP 5.2.13 # Linux (1000 attempts; 9% first : 91% second was faster)
Sorry, I don't have any more servers for testing :) Now I think it mostly depends of hardware (and maybe depends of OS too).
Generally: It proves only that Linux server is faster than one run at Windows :)
The continue 2 version is slightly faster for me. But these aren't the types of things you generally need to concern yourself with. Consider:
for($y = 2; $y <= sqrt($i); $y++)
Here you are calculating the sqrt on every iteration. Just changing that to:
$sqrt = sqrt($i);
for($y = 2; $y <= $sqrt; $y++)
will give you a much better improvement than switching between two nearly identical loop styles.
The continue 2 should be used if you find that it's easier for you to understand. The computer doesn't really care.
To address your update regarding looking at opcodes, see:
http://pecl.php.net/package/vld
php -d vld.active=1 -d vld.execute=0 -f foo.php

Categories