How to compare large number in PHP? - php

I confuse that how I aseert quite large number by PHPUnit.
I wrote fibonacci number. But in case 100, I wrote below.
http://github.com/sanemat/kata-fibonacci-phpunit/commit/b6b2945d2eff1b95e7e25b8be8c7bff11098d44d
I expect this return TRUE.
It failed.
http://www.php.net/manual/en/language.types.float.php
I understood 'never compare for equality.' and so how to aseert it?
At the end, I compare with to_string each other.
How to compare large number in PHP ?
http://github.com/sanemat/kata-fibonacci-phpunit/commit/70a0e47bc0737be47da8fe8726634edd851d940d
I feel it as bad smell. But I do not know better way.
Please tell me how do you assert it?
====
php > $a = 354224848179261915075;
php > echo $a;
3.5422484817926E+20
php > $b = 3.5422484817926E+20;
php > echo $b;
3.5422484817926E+20
php > echo ($a == $b) ? 'TRUE' : 'FALSE';
FALSE
php > echo gmp_cmp($a, $b);
PHP Warning: gmp_cmp(): Unable to convert variable to GMP - wrong type in php shell code on line 1
php > echo (strval($a) == strval($b)) ? 'TRUE' : 'FALSE';
TRUE
====
environment
$ uname -a
Linux localhost.localdomain 2.6.33.6-147.2.4.fc13.x86_64 #1 SMP Fri Jul 23 17:14:44 UTC 2010 x86_64 x86_64 x86_64 GNU/Linux
$ php --version
PHP 5.3.3 (cli) (built: Jul 22 2010 15:57:00)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies

To work with large numbers, there is BCMath libray of PHP.

Related

Under what circumstances does PHP's openssl_random_pseudo_bytes return false?

The PHP documentation for openssl_random_pseudo_bytes says:
Return Values
Returns the generated string of bytes on success, or false on failure.
What would cause openssl_random_pseudo_bytes to fail? Can this be manually triggered for testing purposes? I tried disabling the entire openssl PHP extension, but as expected that raised an error due to the function not being found.
When PHP cannot quantify the integer in a manner that will encrypt the integer, it will, in fact, return false. It goes without saying, it is ASSUMED php uses whole numbers for this function .. However it appears they left room for non-whole numbers (less than 1) and negative integers .. Just in case.
For example:
<?php
echo test_rando(80); // Passes
echo test_rando(80.1); // Passes
echo test_rando(.9); // Fails
echo test_rando(-1); // Faile
function test_rando($rando_in){
$rando = openssl_random_pseudo_bytes($rando_in);
if ($rando === false){
return "\n\n$rando_in | WAS FALSE\n\n ";
}else{
return "\n\n$$rando_in | $rando\n\n";
}
}
Output:
80 | ghg'O8I*%&E(Et(wX"vUH$0
t|5|衖y䰆rW+;
80.1 | &iGkb s`+[byaqvgөrTE݁ᨈ\Ukfb'
0.9 | WAS FALSE
-1 | WAS FALSE
Version of PHP
PHP 8.0.10 (cli) (built: Aug 26 2021 15:50:07) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.10, Copyright (c) Zend Technologies
with Zend OPcache v8.0.10, Copyright (c), by Zend Technologies
--
PHP 7.0.33-0ubuntu0.16.04.16 (cli) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies
with Zend OPcache v7.0.33-0ubuntu0.16.04.16, Copyright (c) 1999-2017, by Zend Technologies
Because PHP was not able to quantify .9 or -1 (anything less than 1), even though IT IS an integer, it will fail. Although this isn't expressly denoted in the documentation, one can assume this prevents fatal errors (division by zero and such) and presents error handling possibility for anyone who might be doing arithmetic on said integer before it's passed through the openssl_random_pseudo_bytes function.

ip2long("012.012.012.012") returns false on Linux

Suppose there are leading zeros in IPv4 address representation such as 012.012.012.012.
To suppress the leading zeros, I simply write the following code, and it works as I expected on my Mac:
% php -r 'var_dump(long2ip(ip2long("012.012.012.012")));'
Command line code:1:
string(11) "12.12.12.12"
% php --version
PHP 7.3.25 (cli) (built: Dec 25 2020 22:03:38) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.25, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.3.25, Copyright (c) 1999-2018, by Zend Technologies
with Xdebug v3.0.1, Copyright (c) 2002-2020, by Derick Rethans
But this simple piece of code doesn't work on CentOS 7, it seems like ip2long("012.012.012.012") returns false value:
$ php -r 'var_dump(long2ip(ip2long("012.012.012.012")));'
string(7) "0.0.0.0"
$ php --version
PHP 7.3.25 (cli) (built: Nov 24 2020 11:10:55) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.25, Copyright (c) 1998-2018 Zend Technologies
$ cat /etc/redhat-release
CentOS Linux release 7.8.2003 (Core)
Both PHP versions are identical and I would expect them to return exact same values. I also read the ip2long docs and tried to find if there is any special options/configurations for this behaviour, but no luck.
Could someone lead me in the right direction?
What makes them different? And what should I do?
OK, I found the culprit. Different implementation of inet_pton(3) between LLVM and GCC leads this behaviour, as Russ-san commented. There was a bug report about the exact same problem 6 years ago. It seems PHP v5.2.10 had started using inet_pton instead of inet_addr according to this patch, that's why older versions of PHP treat each chunks as octal.
test.c
#include <stdio.h>
#include <arpa/inet.h>
#define INADDR "012.012.012.012"
int main() {
struct in_addr inaddr;
if (inet_pton(AF_INET, INADDR, &inaddr) == 0) {
printf("Invalid: %s\n", INADDR);
}
else {
printf("Valid: %s\n", INADDR);
}
return 0;
}
Mac
% cc test.cc && ./a.out
Valid: 012.012.012.012
Linux
$ cc test.cc && ./a.out
Invalid: 012.012.012.012
I gave up using ip2long / long2ip built-in functions and now trying to use https://github.com/mlocati/ip-lib
>>> \IPLib\Address\IPv4::fromString("1.2.3.12")->toString(true);
=> "001.002.003.012"
>>> \IPLib\Address\IPv4::fromString("001.002.003.012")->toString();
=> "1.2.3.12"
No problems so far.

php: is_numeric treats leading and trailing spaces differently

My php version:
➜ ~ php -v
PHP 7.3.1 (cli) (built: Jan 10 2019 13:16:34) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.1, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.3.1, Copyright (c) 1999-2018, by Zend Technologies
I dont understand why spaced value in function is_numeric behaves like this?
➜ ~ php -a
php > var_dump(is_numeric('0012432'));
bool(true)
php > var_dump(is_numeric(' 0012432'));
bool(true)
php > var_dump(is_numeric('0012432 '));
bool(false)
This function handles leading spaces differently than is_int(), is_float(), is_real(), is_long(), and is_double().
is_numeric(" 12345") = true
is_int(" 12345") = false
is_float(" 12345") = false
is_real(" 12345") = false
is_long(" 12345") = false
is_double(" 12345") = false
I found a bug report open for these cases, not sure if they will be working on this,
Bug report
So does every other part of the core PHP language that accepts numeric strings. It's an annoying inconsistency, but it is intentional and has been like this for many years. I am personally intending to fix this in a future version.

modulus operation gives negative value in php

I expects 768 from the following statement. But it echos -360. why?
echo 1364808202768%1000;
UPDATE:
#: php -v
PHP 5.3.2-1ubuntu4.17 with Suhosin-Patch (cli) (built: Jun 19 2012 01:35:33)
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
with Xdebug v2.0.5, Copyright (c) 2002-2008, by Derick Rethans
#: php -r 'echo 1364808202768%1000;'
-360
#: uname -a
Linux tripura 2.6.32-37-generic #81-Ubuntu SMP Fri Dec 2 20:35:14 UTC 2011 i686 GNU/Linux
It is because the number exceeds the maximum that the integer type can hold. You can check if an integer is too big like this:
var_dump('1364808202768' > PHP_INT_MAX);
The built-in function fmod is easy to use, and it should be able to handle big numbers:
echo fmod('1364808202768', 1000);
You can also use one of two common extensions (GMP and BC) if, for whatever reason, fmod is not available, or if you frequently work with large numbers:
// Using the GMP extension
$big = gmp_init('1364808202768', 10);
$val = gmp_strval(gmp_mod($big, 1000));
echo $val;
// Using the BC extension
echo bcmod('1364808202768', 1000);
I think thats because its above the int limit, use fmod(1364808202768,1000);
You should read about the data types and their range. Use this:-
$num = 1364808202768;
echo fmod($num,1000);

Is there a PHP setting that sets whether you can index the result of a function?

I have two servers. They are both running php 5.3.3. This code works on one server and returns a syntax error on the other. Is there a php ini setting that affects this behaviour? I can't find anything related in the PHP documentation, but I may be looking in the wrong place.
Server 1
> php -v
PHP 5.3.3 (cli) (built: Sep 23 2010 14:15:16)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
with Xdebug v2.0.3, Copyright (c) 2002-2007, by Derick Rethans
php > echo explode(" ", " foo ")[1];
foo
Server 2
> php -v
PHP 5.3.3 (cli) (built: Jan 31 2011 15:57:29)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
php > echo explode(" ", " foo ")[1];
Parse error: syntax error, unexpected '[', expecting ',' or ';' in php shell code on line 1
Another idea: PHP on both servers is custom-compiled, so it could also be a different compile flag.
No.
PHP doesn't support this syntax. It's on the trunk, but not yet released (as of PHP 5.3.3).
I have no idea how it's working on your first server, but perhaps this "Xdebug" is making a difference?
Aha! I figured it out.
We installed Facebook's XHP to profile our development server. This syntax (which is quite elegant) was added in in the PHP module. Here's a diff of the php.ini file between server 1 and 2:
> ; XHP https://github.com/facebook/xhp/wiki/Building-XHP
> extension=xhp.so
> ; adds support for the [] operator on the return value of a function
> xhp.idx_expr = 1
> ; Tracking errors in XHP applications is very difficult without annotations.
> xhp.include_debug = 1
I like this syntax, so I'll probably install XHP on the other server. Thanks for the help Michas for suggesting I diff the ini files.

Categories