Incorrect PHP calculation - php

Can someone give me an explanation on why this is happening in PHP:
echo (0.29*100)%100 // result 28
It's probably very simple but logically I do not see any explanation. Probably how PHP works in the background.
I was trying to get the first two decimal positions of a number when I ran into this case. Result should be 29 naturally.
If I round the multiplication the result is fine:
echo (round(0.29*100))%100 // result 29

If you run that code
echo (0.29*100)%100;
in in PHP8.1.1 the error message gives you a clue
PHP 8.1.1
Deprecated: Implicit conversion from float 28.999999999999996 to int loses precision in D:\PHP-SOURCE\Testing\tst.php on line 14
Call Stack:
0.0001 393688 1. {main}() D:\PHP-SOURCE\Testing\tst.php:0
28

Related

Notice: Use of undefined constant ‏ - assumed '‏' in C:\xampp\htdocs\aa.php on line 5 vs Notice a non well former numeric value

I tried running this simple php code in 2 different machines and i get different results for some reason.
the code:
<?php
$a = 5;
$b = "22ff67";
$s = $a - $b;
echo $s;‏
?>
in machine 1 i get the error:
Notice a non well former numeric value encountered in .... on line 4
17
and in machine 2 i get:
-17
Notice: Use of undefined constant ‏ - assumed '‏' in
C:\xampp\htdocs\aa.php on line 5
i run the code using XAMPP apache server...
what could be the reason for the different results?
the output is -17 because it tries to subtract 22 from 5 but because 22 is part of a string it gives the error? (it takes only 22 because it's the number before the first letter in the string (in strings which has signs other than '.', 'e','E' it takes the first number up to a sign other than those)
Thanks.

PHP Division by zero warning with a check

I have a script that does some math and makes an excel sheet but i randomly get a
Warning: Division by zero in myfile.php on line 170
Which throws off my header() changes.. I say that its random because it will work one time but if i refresh the page it breaks the most confusing part is that i also have a check if its zero here is the code
167 if($cartonCount > 0){
168 echo "-----" . $cartonCount . "-----";
169 $mellow = $qty/$cartonCount;
170 $leftovers = $qty % $cartonCount;
171 for($x = 1 ; $x <= $mellow ; $x++){
If the carton count is 0 it shouldn't run at all yet i still get the warning.. if anyone has an idea let me know here is a sample of the out put
-2.38----------7.63----------12----------10----------7.5---------
7.5----------4.5----------4.5----------4.5----------4.5----------7.5-
---------1----------9.5----------7.5----------2.38----------0.06-----
Warning: Division by zero in /nfs/c08/h02/mnt/122022/domains/superstructs.com/html/catalog/test/samples/upsExport.php on line 170
-----2.38----------7.63----------7.5----------7.5----------2.38------
----0.06-----
Then, I'm putting this in as answer:
It might be because the value is NULL which, in fact, is not >0. But it will still give you that error
I notice that the place where it breaks is when $cartonCount is "0.06". I suspect that $cartonCount is being stored as a string, possibly with the European style 0,06 decimal notation. When PHP tries to convert that to a number, it sees it as a zero. I'm not sure why it is acting differently for the modulo operator and not for division or equality checks, but putting $cartonCount = intval($cartonCount) before line 167 should make things act consistently (although it might end up interpreting your 0.06 as a zero).
The modulo operator converts (or rounds) the second number to an integer. 0.06 results in 0 which creates the warning.
Possible options are for example casting to integer or round() before checking > 0, round up using ceil() or check > 1.
Based on the context ceil() seems to be the best option.

Array Offset Encryption

Right now I am developing a cryptography app and I have a problem with this one
$stralphabet=array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z');
As you can see the string above is a string of alphabet. I am making a caesar shift encryption, the algorithm is simple.
Count the number of string and then substitute each letter based from the position, so for example:
string is "AB" after encryption it would be "CD"
The problem is if I have the string YZ" it gives me an error
Notice: Undefined offset: 26 in C:\xampp\htdocs\cryptographer\encrypt.php on line 19
Notice: Undefined offset: 27 in C:\xampp\htdocs\cryptographer\encrypt.php on line 19
Can you help me with this one?
You apparently are accessing $stralphabel without checking for edge case (i.e. $stralp[$i+1]). You should add some checks or use modulo operator, so instead of just:
$stralp[$i+1]
you'd have
$stralp[($i+1) % XXX]
where XXX is number of entries in your stralp array.
PS: this is not even close to cryptography.
Your array has 26 letters indexed from 0 to 25, so something is wrong with your cycle end condition.

Display float value w/o scientific notation

When i make the following multiplication in PHP:
$ret = 1.0 * 0.000000001;
i get the result: 1.0E-9
I want to convert this result into the normal decimal notation, how can i do this?
sprintf('%f',$ret) doesn't work, it returns 0.000000. Overflow?
sprintf('%f',$ret) doesn't work, it returns 0.000000. Overflow?
sprintf works, however you miss some point here.
0.000000 is not overflow. It's just that sprintf for the %f modifier uses 6 digits per default. Also please take care that %f is locale aware, %F is probably better suited.
You might want to use more digits, e.g. let's say 4 000 000 (four million):
$ php -r "printf('%.4000000F', 1*0.000000001);"
Notice: printf(): Requested precision of 4000000 digits was truncated to PHP maximum of 53 digits in Command line code on line 1
Call Stack:
0.0001 319080 1. {main}() Command line code:0
0.0001 319200 2. printf() Command line code:1
0.00000000100000000000000006228159145777985641889706869
As this example shows, there is not only a common value (6 digits) but also a maximum (probably depended on the computer system PHP executes on), here truncated to 53 digits in my case as the warning shows.
Because of your question I'd say you want to display:
0.000000001
Which are nine digits, so you need to write it that way:
sprintf('%.9F',$ret)
However, you might want to do this:
rtrim(sprintf('%.20F', $ret), '0');
which will remove zeroes from the right afterwards:
0.000000001
Hope this is helpful.
You need to add precision specifier (how many decimal digits should be displayed for floating-point numbers). Something like this:
echo sprintf('%.10f',$ret); // 0.0000000010
If you have no idea what number you should specify, just give it a big number and combine it with rtrim().
echo rtrim(sprintf('%.20f', $ret), '0'); // 0.000000001
The code above will strip any 0's from the end of the string.
I suggest the use BCMath for more accuracy when you are calculating with decimal numbers. That makes sure that you actually get the results you want.
To print what you want, you should specify the precision and use %.9f, since it defaults to displaying 6 decimal numbers. That makes it something like this (just like bsdnoobz already said):
sprintf('%.9f',$ret);
To align to your system's settings and limitations, you could use serialize_precision to get the most accurate result possible.
echo rtrim(sprintf('%.'.ini_get('serialize_precision').'f', $ret));
I do not recommend using the non-locale aware %F since your question only makes sense for display purposes. Respecting locale makes for a better UX.

Is there a certain size of the uniqid function?

I'm just wondering, does anyone know, whether uniqid function in PHP has a certain size? And If so, how many strings is it? I'm a bit confused as PHP manual says, that uniqid is 23 characters long when extended entropy used. But based on my observation, it varies between 26 to 28 characters.
I cant confirm this behaviour:
php -r 'for($i = 0; $i < 1000; $i++) print strlen(uniqid("", true)) . "\n";'
Tested on OS X and Ubuntu with PHP 5.3.x yields 23 on each iteration.
What os/PHP version are you using?
As the OP pointed out in the comments to his question: leaving out the prefix should fix the issue ;)
To elaborate a bit more, one can look at the PHP source code: https://svn.php.net/viewvc/php/php-src/tags/php_5_3_8/ext/standard/uniqid.c?view=markup at line 79:
spprintf(&uniqid, 0, "%s%08x%05x%.8F", prefix, sec, usec, php_combined_lcg(TSRMLS_C) * 10);
If no prefix is supplied and one looks up the definition of php_combined_lcg which returns a float with one leading decimal the output of uniqid should always be 23 chars long.

Categories