I'm testing below simple code in PHP:
`<?php
echo 5 % 0.75;
?>`
And I see error division by zero whereas 0.75 is not zero!?
what happens exactly?
The operator % is for int type and 0.75 is float. So PHP changes it to zero first :
https://www.php.net/manual/en/language.operators.arithmetic.php
If you want to work with float type you need to do :
fmod(5,0.75);
https://www.php.net/manual/en/function.fmod.php
Related
My code works on PHP 7:
round(microtime(),3);
but in PHP 8:
Fatal error: Uncaught TypeError: round(): Argument #1 ($num) must be
of type int|float, string given in [...][...]:4 Stack trace: #0
[...]...: round('0.21066100 1646...', 3) #1 {main} thrown in
[...][...] on line 4
If I force cast:
round((float)microtime(),3);
It works but all the force of PHP is autocast and non strict type! How can I use PHP 8 if all native functions in all my billions of lines codes must be edited to force cast everywhere?
Is there a way to preserve automatic type conversion on internal functions?
I take microtime() like an example in my code but:
round("200 42");
As the same problem, so the solution is not just microtime(true), it's not the topic here.
The problem is, if in my code I use a native function, there are potential bugs and I can't know it (error occur only when the script is running), so if I let PHP 8, may be, certain pages of my site don't work and I have no possibility to know it! It's A BIG Problem!
https://www.php.net/manual/en/migration80.other-changes.php
The math functions abs(), ceil(), floor() and round() now properly
heed the strict_types directive. Previously, they coerced the first
argument even in strict type mode.
So this function must be focused to update code and not all native functions!
You don't need to force cast to match native function signatures everywhere, unless strict_types is declared. You do need to ensure that the variables you feed into those functions can be unambiguously typecast into the expected datatype. We have a case in point with the math functions, where you really want to have a valid number as an argument, regardless of datatypes:
php > echo round("200");
200
php > echo round("200 12");
Warning: Uncaught TypeError: round():
Argument #1 ($num) must be of type int|float, string given
Here the string "200" works, because it's an unambiguous number. However, "200 12" will not, since it's ambiguous. Suppose you cast it:
php > echo (int) "200 12";
200
Your "200 12" becomes (int) 200. Is that what you expected? Again:
php > echo (float) "gummy bears";
0
php > echo 200 + "1";
201
php > echo 200 - "gummy bears" + "1";
Warning: Uncaught TypeError: Unsupported operand types: int - string
These are the sorts of anomalous evaluations that would pass in earlier versions of PHP, and it's a blessing we now get a TypeError instead. Variables should only ever be typecast losslessly, "reckless" typecasting and corrupted data has been the source of countless evasive bugs.
Also see: PHP Manual on Numeric Strings ... specifically the sections on what can be interpreted as a number and what can't. Basically, if your variable passes is_numeric(), it's fine for math operations -- and if not, you deserve an error message! Here's the list of samples from the manual:
$foo = 1 + "10.5"; // $foo is float (11.5)
$foo = 1 + "-1.3e3"; // $foo is float (-1299)
$foo = 1 + "bob-1.3e3"; // TypeError as of PHP 8.0.0, $foo is integer (1) previously
$foo = 1 + "bob3"; // TypeError as of PHP 8.0.0, $foo is integer (1) previously
$foo = 1 + "10 Small Pigs"; // $foo is integer (11) and an E_WARNING is raised in PHP 8.0.0, E_NOTICE previously
$foo = 4 + "10.2 Little Piggies"; // $foo is float (14.2) and an E_WARNING is raised in PHP 8.0.0, E_NOTICE previously
$foo = "10.0 pigs " + 1; // $foo is float (11) and an E_WARNING is raised in PHP 8.0.0, E_NOTICE previously
$foo = "10.0 pigs " + 1.0; // $foo is float (11) and an E_WARNING is raised in PHP 8.0.0, E_NOTICE previously
In conclusion, you really do want to update your code at places where ambiguous typecasting used to be valid... In the long run, you'll spend less time updating your code than you would in chasing down anomalies resulting from variable values that were corrupted when "autocasting".
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
I try to convert my working PHP 5.x code into an more modern PHP 7.x code-base, so I added "declare(strict_types=1);" in the first step, but it didn't work as expected.
code: ord(chr(ord("\xE9") / 64) | "\xC0");
demo: https://3v4l.org/680ts
github: https://github.com/voku/portable-utf8/blob/master/src/voku/helper/UTF8.php#L6613
PHP < 7.0 or > 7.0 (without strict_types=1) === 195
PHP > 7.0 (with strict_types=1) === 192
Maybe someone can explain this to me? I think it's because of "chr()" expecting an integer, but we get a float?! But there isn't any warning or something like this...? -> http://php.net/manual/en/migration70.incompatible.php#migration70.incompatible.strings.hex
So, let's break it down.
ord("\xC0");
That's 192. With or without strict types. The breakdown is happening here
chr(ord("\xE9") / 64)
Now ord("\xE9") / 64 works out to 3.640625 and we can see where it breaks down here
var_dump(ord(chr(3.640625)));
This is 0 with strict types, and 3 without. Per the manual for chr
string chr ( int $ascii )
So the result here is a float, not an int. What's happening is that strict types cannot convert the float to an int, so it passes a 0
Per the manual
In strict mode, only a variable of exact type of the type declaration will be accepted, or a TypeError will be thrown. The only exception to this rule is that an integer may be given to a function expecting a float.
We're going the other way. So strict types behaves like all PHP when you pass it a bad argument
var_dump(ord(chr('bob'))); // string 0, in all PHP versions
Sorry for the bad title, but I dunno how to call this.
echo rand(0,10e20) . "\n"; // bad
echo rand(0,10e19) . "\n"; // bad
echo rand(0,10e18) . "\n"; // bad
echo rand(0,10e17) . "\n"; // OK
echo rand(0,10e16) . "\n";
echo rand(0,10e15) . "\n\n";
var_dump(10e20); // float
var_dump(10e15); // float
Output:
Warning: rand() expects parameter 2 to be integer, float given
in /srv/webroot-sandbox/index.php(73) : eval()'d code on line 1
Warning: rand() expects parameter 2 to be integer, float given
in /srv/webroot-sandbox/index.php(73) : eval()'d code on line 2
Warning: rand() expects parameter 2 to be integer, float given
in /srv/webroot-sandbox/index.php(73) : eval()'d code on line 3
578009006101638016
69608699344098568
7596902768127620
float(1.0E+21)
float(1.0E+16)
Can someone explain what's going on? This is PHP 7, it worked fine in PHP 5 (well, at least I didn't get any warnings).
PHP ints are signed 64bit values (unless you're on a 32bit install), so they go (roughly)
-9,223,372,036,854,775,808 -> +9,223,372,036,854,775,808
In scientific notation, -9.2e18 -> +9.2e18
So your "bad" values are simply integers that are too large to store as integers, and PHP is converting to float to try and preserve as much of the value as is possible.
And since you have 10e18, that's actually 1e19, and outside the max_int range.
Your question can be platform dependent as the integer range of a:
32 bit platform is -2,147,483,648 to 2,147,483,647
64 bit platform is -9,223,372,036,854,775,808 to 9,223,372,036,854,775,808
For me, running a 64 bit system it gives the following result.
var_dump(10e20 > PHP_INT_MAX); // true
var_dump(10e19 > PHP_INT_MAX); // true
var_dump(10e18 > PHP_INT_MAX); // true
var_dump(10e17 > PHP_INT_MAX); // false
var_dump(10e16 > PHP_INT_MAX); // false
var_dump(10e15 > PHP_INT_MAX); // false
This output directly correlates with your results and might explain a fiddle or your webhost to show different results.
The reason it behave differently on PHP 7 is explained here:
Previously, internal functions would silently truncate numbers
produced from float-to-integer coercions when the float was too large
to represent as an integer. Now, an E_WARNING will be emitted and NULL
will be returned.
I am new to php and was doing some mathematics and found this weird thing happening.
$numOfDiffChars = 62;
$id = 285355773910;
$remainder = $id % $numOfDiffChars;
echo "Remainder: ".$remainder." ID: ".$id." NumOfElems: ".$numOfDiffChars." ",($id - floor($id/$numOfDiffChars)*$numOfDiffChars);
The answer is as follows:
Remainder: 10 ID: 285355773910 NumOfElems: 62 26
which states that % operator gives the remainder 10 whereas mathematically its 26. What could be the reason for this? Is it just some error that I committed or is there a logic?
I am not quite sure, but if your using a 32-bit machine the problem could be that the integer $id is out of bound and therefore interpreted as a floating point.
http://php.net/manual/en/language.types.integer.php
have you tried fmod function find example on --->
http://www.php.net/manual/en/function.fmod.php
From php.net
Note that operator % (modulus) works just with integers (between -214748348 and 2147483647) while fmod() works with short and large numbers.