PHP: why my switch always picks the same value? - php

function getValue($v) {
$b = 22;
switch ($v) {
case ($v <= $b * 1.2):
$v1 = $b; break;
case ($v1 > $b * 1.2 && $v1 <= $b * 2.2):
$v1 = $b * 2; break;
case ($v1 > $b * 2.2 && $v1 <= $b * 3.2):
$v1 = $b * 3; break;
case ($v1 > $b * 3.2):
$v1 = $b * 4; break;
default:
$v1 = $b;
}
return $v1;
}
the getValue(25) or getValue(45) always returns 22.

I don't think you could use switch like that. It needs values. It does not accept boolean conditions. Check here http://php.net/manual/en/control-structures.switch.php

function getValue($v) {
$b = 22;
switch ($v) {
case ($v <= $b * 1.2):
$v1 = $b; break;
case ($v > $b * 1.2 && $v <= $b * 2.2):
$v1 = $b * 2; break;
case ($v > $b * 2.2 && $v <= $b * 3.2):
$v1 = $b * 3; break;
case ($v > $b * 3.2):
$v1 = $b * 4; break;
default:
$v1 = $b;
}
return $v1;
}
Your using $v1 instead of $v wrongly.
Above code will work.

You're checking the wrong variable, so you should replace $v1 with $v in the case statements throughout. But also, switch statements are designed to accept constant values, so you'd be better to replace them all with if.
In addition, parts of your expressions are redundant because you've already checked for them. After checking that $v <= $b * 1.2 and finding it isn't, there's no need to check that $v > $b * 1.2 in the next expression. Your default clause can never be matched because all values of $v are <= $b * 3.2 or > $b * 3.2.
function getValue($v) {
$b = 22;
if ($v <= $b * 1.2) {
return $b;
} elseif ($v <= $b * 2.2) {
return $b * 2;
} elseif ($v <= $b * 3.2) {
return $b * 3;
} else {
return $b * 4;
}
}

With a switch, you test the given value against the cases.
So your statement does $v == ($v <= $b * 1.2), $v == ($v1 > $b * 1.2 && $v1 <= $b * 2.2), etc.
You can do a switch and test against true:
function getValue($v) {
$b = 22;
switch (true) {
case ($v <= $b * 1.2):
$v1 = $b; break;
case ($v1 > $b * 1.2 && $v1 <= $b * 2.2):
$v1 = $b * 2; break;
case ($v1 > $b * 2.2 && $v1 <= $b * 3.2):
$v1 = $b * 3; break;
case ($v1 > $b * 3.2):
$v1 = $b * 4; break;
default:
$v1 = $b;
}
return $v1;
}
However in this case an if / else seems like the better choice:
function getValue($v) {
$b = 22;
if ($v <= $b * 1.2) {
$v1 = $b;
} elseif ($v1 > $b * 1.2 && $v1 <= $b * 2.2) {
$v1 = $b * 2;
} elseif ($v1 > $b * 2.2 && $v1 <= $b * 3.2) {
$v1 = $b * 3;
} elseif ($v1 > $b * 3.2) {
$v1 = $b * 4;
} else {
$v1 = $b;
}
return $v1;
}

Look at your case labels: they are the results of relational operations, so all of them evaluate to either true or false! %v will be compared to these Boolean values. That's why you're observing such similar output for your input cases.
Replace the switch with an if block and all will be well. And do review your use of $v1; did you mean that?

in your switch I can see variable $v1 in the second and third and fourth case so think of the condition which we don't go through the first case so what is the variable $v1 then ? it is not set yet so it goes to the case default or first case always.

Related

PHP CUSIP Check num

i need to be able to validate CUSIP numbers based on thier check digit. I have the psudocode for the process thanks to wikipedia, but i have so far been unable to replicate it in PHP.
Psudocode can be found here.
My PHP:
<?php
/**
* function to return the check digit value of a cusip
* #param $cusip
* the cusip for processing.
* #return Int
* cusip check digit.
*/
function cusip_checksum($cusip){
$sum = 0;
$rebuiltcusip = '';
for($i = 1; $i <= 8; $i++){
$c = substr($cusip, ($i - 1), 1); //$i needs to be 0, so as we start at 1, take 1 off.
$rebuiltcusip .= $c;
switch(true){
case $c == '0': // ctype_digit(0) returns false, so checking for 0 here.
$v = $c;
watchdog("case 0: ", $v);
break;
case ctype_digit($c): //check if numeric
$v = $c;
watchdog("case ctype_digit: ", $v);
break;
case $c == '*':
$v = 36;
watchdog("case *: ", $v);
break;
case $c == '#':
$v = 37;
watchdog("case #: ", $v);
break;
case $c == '#':
$v = 38;
watchdog("case #: ", $v);
break;
case !ctype_digit($c): //check letter last as this check would pass with * # or # so allow them to be checked first
$v = (ord($c) - 64) + 9; //set ordinal number, -64 as this returns ASKII value, then add 9.
watchdog("case not ctype_digit: ", $v);
break;
}
if(($i % 2) == 0){ //check if odd
$v = $v * 2;
watchdog("case odd: ", $v);
}
$sum = $sum + ($v / 10) + ($v % 10);
watchdog("sum end loop: ", $sum);
}
$ncd = (10 - ($sum % 10)) % 10;
$rebuiltcusip .= $ncd;
watchdog("rebuilt cusip: ", "Cusip: ".$cusip." Rebuilt: ".$rebuiltcusip);
return $ncd;
}
?>
watchdog is simply me logging the process.
Passing in a CUSIP of: 98986T108 which has a check digit value of 8, actually returns a value of 98986T104 (check digit value of 4).
so:
<?php
print cusip_checksum('98986T108');
?>
should return 8, it returns 4.
Can anyone spot the reason for this?
Wrap the division in a floor() function and you are there:
$sum = $sum + floor($v / 10) + ($v % 10);
Now a Q in the CUSIP will have a value of 26. This will add 2 and 6 to the $sum instead of adding 2.6 and 6.
Here's the final function with the correction. I've run this through a Reuters extract of 17614 CUSIPs and there were 11 that did not match up. That's about the level of error I usually see from Reuters data so I have confidence in the routine.
/**
* function to return the check digit value of a cusip
* #param $cusip
* the cusip for processing.
* #return Int
* cusip check digit.
*/
function cusip_checksum($cusip){
$sum = 0;
$rebuiltcusip = '';
for($i = 1; $i <= 8; $i++){
$c = substr($cusip, ($i - 1), 1); //$i needs to be 0, so as we start at 1, take 1 off.
$rebuiltcusip .= $c;
switch(true){
case $c == '0': // ctype_digit(0) returns false, so checking for 0 here.
$v = $c;
watchdog("case 0: ", $v);
break;
case ctype_digit($c): //check if numeric
$v = $c;
watchdog("case ctype_digit: ", $v);
break;
case $c == '*':
$v = 36;
watchdog("case *: ", $v);
break;
case $c == '#':
$v = 37;
watchdog("case #: ", $v);
break;
case $c == '#':
$v = 38;
watchdog("case #: ", $v);
break;
case !ctype_digit($c): //check letter last as this check would pass with * # or # so allow them to be checked first
$v = (ord($c) - 64) + 9; //set ordinal number, -64 as this returns ASKII value, then add 9.
watchdog("case not ctype_digit: ", $v);
break;
}
if(($i % 2) == 0){ //check if odd
$v = $v * 2;
watchdog("case odd: ", $v);
}
$sum = $sum + floor($v / 10) + ($v % 10);
watchdog("sum end loop: ", $sum);
}
$ncd = (10 - ($sum % 10)) % 10;
$rebuiltcusip .= $ncd;
watchdog("rebuilt cusip: ", "Cusip: ".$cusip." Rebuilt: ".$rebuiltcusip);
return $ncd;
}

Loop not working correctly (floats and integer issue?) -- PHP [duplicate]

This question already has answers here:
Double? Integer? -- PHP
(2 answers)
Closed 8 years ago.
The code below generates two random decimal values, then subtracts them to get $c.
The do-while loop is trying to ensure that $c will not be a whole number. But I keep getting times where $c actually is a whole number.
do{
unset($a);
unset($b);
unset($c);
unset($adjuster);
unset($c_is_int);
$a = mt_rand(5, 75);
$b = mt_rand(5, 75);
$adjuster = mt_rand(2, 20);
$decimal_selector = mt_rand(1, 6);
if ($decimal_selector == 1){
$a = $a / 10;
$b = $b / 10;
}
if ($decimal_selector == 2){
$a = $a / 10;
$b = $b / 100;
}
if ($decimal_selector == 3){
$a = $a / 100;
$b = $b / 10;
}
if ($decimal_selector == 4){
$a = $a / 100;
$b = $b / 100;
}
if ($decimal_selector == 5){
$a = $a / 1000;
$b = $b / 1000;
}
if ($decimal_selector == 6){
$a = $a / 1000;
$b = $b / 100;
}
if($b < $a){
$b = $b + ($a - $b) + $adjuster;
}
$c = $b - $a;
if(intval($c) == $c) {
$c_is_int = 1;
} else {
$c_is_int = 0;
}
echo $a . '<br><br>';
echo $b . '<br><br>';
echo intval($c) . '<br>';
echo $c_is_int . '<br>';
echo $c . '<br><br>';
} while($c_is_int == 1);
The attached image shows the results of one of these failing times. Any ideas on where this is going wrong?
Why not check to see if the number has a decimal?
$c = 123.456;
if(strpos((string) $c, '.') !== FALSE) {
// is decimal/float/double
}
You can also just check to see if it's an int
if(is_int($c))
You want to keep in mind that the integer 3 and float 3.0 will compare as equal when using the ==.
Consider:
$c_is_int = $c == floor( $c );
...
while( $c_is_int )

Double? Integer? -- PHP

The following code generates two random decimal values, then subtracts them to get $c.
$a = mt_rand(5, 75);
$b = mt_rand(5, 75);
$adjuster = mt_rand(2, 20);
do {
$decimal_selector = mt_rand(1, 6);
if ($decimal_selector == 1) {
$a = $a / 10;
$b = $b / 10;
}
if ($decimal_selector == 2) {
$a = $a / 10;
$b = $b / 100;
}
if ($decimal_selector == 3) {
$a = $a / 100;
$b = $b / 10;
}
if ($decimal_selector == 4) {
$a = $a / 100;
$b = $b / 100;
}
if ($decimal_selector == 5) {
$a = $a / 1000;
$b = $b / 1000;
}
if ($decimal_selector == 6) {
$a = $a / 1000;
$b = $b / 100;
}
if($b < $a)
$b = $b + ($a - $b) + $adjuster;
$c = $b - $a;
} while((is_int($a) == true && is_int($b) == true) || is_int($c) == true);
The do-while loop is trying to ensure that $a and $b are both not integers, and also that $c is not an integer. But I keep getting times where $c actually is an integer.
If I use gettype it keeps saying $c is a "double". Why, when $c ends up being something like 7?
EDIT:
I keep getting random infinite loops from this code below. Any ideas why?
do{
$a = mt_rand(5, 75);
$b = mt_rand(5, 75);
$adjuster = mt_rand(2, 20);
$decimal_selector = mt_rand(1, 6);
if ($decimal_selector == 1){
$a = $a / 10;
$b = $b / 10;
}
if ($decimal_selector == 2){
$a = $a / 10;
$b = $b / 100;
}
if ($decimal_selector == 3){
$a = $a / 100;
$b = $b / 10;
}
if ($decimal_selector == 4){
$a = $a / 100;
$b = $b / 100;
}
if ($decimal_selector == 5){
$a = $a / 1000;
$b = $b / 1000;
}
if ($decimal_selector == 6){
$a = $a / 1000;
$b = $b / 100;
}
if($b < $a){
$b = $b + ($a - $b) + $adjuster;
}
$c = $b - $a;
if(intval($c) == $c) {
$c_is_int = 1;
} else {
$c_is_int = 0;
}
echo intval($c) . '<br>';
echo $c_is_int . '<br>';
echo $c . '<br><br>';
} while($c_is_int == 1);
A double subtracting a double results in a double, even if that number is a whole number
$c = (int) ($b - $a);
Do something like this to see if $c is a whole number (possibly stored as a double):
if(intval($c) == $c) {
echo "I'm a whole number";
}
See here: http://3v4l.org/ubPK4

Do-While Loop with Multiple Conditions

Can a do-while loop have multiple conditions? If so, I can't figure out why the code below is failing on all but the first condition.
Functions used...
function gcf($a,$b) {
$a = abs($a); $b = abs($b);
if( $a < $b) list($b,$a) = Array($a,$b);
if( $b == 0) return $a;
$r = $a % $b;
while($r > 0) {
$a = $b;
$b = $r;
$r = $a % $b;
}
return $b;
}
function factors($n){
$factors_array = array();
for ($x = 1; $x <= sqrt(abs($n)); $x++)
{
if ($n % $x == 0)
{
$z = $n/$x;
array_push($factors_array, $x, $z);
}
}
return $factors_array;
}
Code...
$a = $b;
do{
$a = mt_rand(8, 100);
$a_factors_array = factors($a);
$b = mt_rand(8, 100);
$b_factors_array = factors($b);
} while ($a == $b && count($a_factors_array) < 4 && count($b_factors_array) < 4 && gcf($a, $b) == 1);
echo $a . '<br>';
echo $b . '<br>';
echo count($a_factors_array) . '<br>';
echo count($b_factors_array) . '<br>';
echo gcf($a, $b) . '<br>';
I keep getting numbers for $a and $b that have less than 4 factors and have a GCF of 1. Any ideas?
You'll need || instead of &&. You want to repeat the loop as long as any one of your conditions is met. Currently the loop is only repeated if all of the conditions are met.
I think you have an ANDs where you meant an ORs:
do{
$a = mt_rand(8, 100);
$a_factors_array = factors($a);
$b = mt_rand(8, 100);
$b_factors_array = factors($b);
} while ($a == $b || count($a_factors_array) < 4 || count($b_factors_array) < 4 || gcf($a, $b) == 1);
With your way, the while stops if $a !== $b which is probably not what you want.

PHP use string as operator

Say I have a string, $char. $char == "*".
I also have two variables, $a and $b, which equal "4" and "5" respectively.
How do I get the result of $a $char $b, ie 4 * 5 ?
Thanks :)
You can use eval() as suggested by #konforce, however the safest route would be something like:
$left = (int)$a;
$right = (int)$b;
$result = 0;
switch($char){
case "*":
$result = $left * $right;
break;
case "+";
$result = $left + $right;
break;
// etc
}
safest method is a switch construct:
function my_operator($a, $b, $char) {
switch($char) {
case '=': return $a = $b;
case '*': return $a * $b;
case '+': return $a + $b;
etc...
}
}
The easiest but most dangerous method is to use eval.
$c = eval("return $a $char $b;");
take a look at the eval() function. you will need to build a proper php command and run inside the eval() to extract out the result.
You can do with eval however I would not suggest using eval.
If there is case operator can by anything you should check what operator is before using
switch($char)
{
case '*':
$result= $a * $b;
break;
case '+':
$result= $a + $b;
break;
}
<?php
$a = 'alex';
$b = "alex";
$c = "==";
function abc($a,$b,$c){
$d = 'return ($a '.$c.' $b) ? true : false;';
return eval($d);
}
if(abc($a,$b,$c)){
echo "condition true";
}else{
echo "condition false";
}
// echo $e;
?>

Categories