-3

This is probably a very easy question for someone experienced but it's driving me nuts.

I am writing a program that needs to draw a specific amount of smilies.

The account is calculated via:

$cer = userinput 1 / userinput 2
$eer = userinput 3 / userinput 4

$arr = $cer-$eer

all userinputs are integers but $cer, $eer and $arr are floats most of the time although they can be integers depending on the inputs. I am not using a static cast here.

I want to represent this as a 10x10 grid of smilies with happy, sad and difference smilies as options.

my code:

$experiment_happy = (int)(100-($eer*100+$arr*100));
$experiment_difference = (int)($arr*100);
$experiment_sad = (int)($eer*100);

echo $experiment_difference."<br>";
echo "<table><tr>";
for ($i = 0; $i < $experiment_happy ; $i++) {
    if ($i % 10 != 0){
       echo "<td><img src='images/happy.gif' width='20' height='20'></td>";
    }else{
        echo "</tr><tr>";
        echo "<td><img src='images/happy.gif' width='20' height='20'></td>";
    } 
}

echo "</tr><tr>";

for ($i = 0; $i < $experiment_difference ; $i++) {
    if ($i % 10 != 0){
        echo "<td><img src='images/difference.gif' width='20' height='20'>   </td>";
    }else{
        echo "</tr><tr>";
        echo "<td><img src='images/difference.gif' width='20' height='20'></td>";
    }
}

echo "</tr><tr>";

for ($i = 0; $i < $experiment_sad ; $i++) {
    if ($i % 10 != 0){
        echo "<td><img src='images/sad.gif' width='20' height='20'></td>";
    }
    else{
        echo "</tr><tr>";
        echo "<td><img src='images/sad.gif' width='20' height='20'></td>";
    }
}

echo"
</tr></table>
";

I am getting problems with the following numbers: userinput 1: 100 userinput 2: 30 userinput 3: 100 userinput 4: 17

The calculations run fine but an incorrect number of smilies is drawn because of some conversion error. arr is calculated to be 0.13 which is multiplied with 100 -> 13 This is then converted to an integer (int)($arr*100) which somehow returns 12.

Where am I going wrong. I suspect it has something to do with floating point comparison or conversion to integer but I just can not seem to fix this..

Any help and explanation would be most appreciated.

A live version can be seen here. http://niederrad.no-ip.org/alex_test/nnt.php. The input boxes represent the userinputs 1-4 from top to bottom and my problem is occuring with the second smilie grid.

Jorge Campos
  • 22,647
  • 7
  • 56
  • 87
  • 6
    tl;dr: [it isn't](http://3v4l.org/5KjhM) – kero Dec 10 '13 at 18:35
  • 2
    `(int)(0.14*100)` = `14` – AbraCadaver Dec 10 '13 at 18:35
  • 2
    `I suspect it has something to do with floating point` you are right, use `round()` instead of casting to int – dev-null-dweller Dec 10 '13 at 18:38
  • using round() solved it. Thank you! – Alexander Langanke Dec 10 '13 at 18:52
  • @JimLewis: That is not a good “original” for this problem. The numbers in this problem arise from user inputs, and there is no reason to think they will always involve powers of 10. The actual issue is not that most decimal numbers are not exactly representable in binary floating-point but that most numbers are not exactly representable (in **any** numerical arithmetic system), and that conversion to integer uses truncation. – Eric Postpischil Dec 10 '13 at 20:12
  • @EricPostpischil: How would a user enter a number that doesn't have a terminating representation in base-10? – dan04 Dec 10 '13 at 23:38
  • 1
    @dan04: As shown in the question, `$cer` and `$eer` are calculated as ratios of user-entered values. The user merely enters, for the denominators, values that are not powers of 10 (or products of powers of 2 and 5). – Eric Postpischil Dec 11 '13 at 00:15

2 Answers2

1

It isn't it === 14.

echo (int)(0.14 * 100);

Output:-

14

Proof

Always keep numbers to full precision as much as you can, only round before presenting them to the user.

You say

all user inputs are integers

One thing to be careful of is that anything in $_GET and $_POST will be a string, explicitly cast it to the type you want rather than relying on PHP's loose typing here.

vascowhite
  • 18,120
  • 9
  • 61
  • 77
0

Two issues combine to produce the results you are seeing:

  • In any numerical arithmetic system (integer or floating-point, binary or decimal, or other), most numbers cannot be represented exactly. Exact mathematical results must be approximated or are outside the bounds of the system.
  • When you convert a floating-point number to integer, the result is the truncated value; the fraction portion is removed.

So, when a calculation produces a number slightly less than what you might desire, then converting it to integer may produce a number one less than what you desire.

If you are doing only a few simple calculations that cannot produce much error, then you can work around this by rounding to an integer, with the round function.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312