PHP: on 32 bit system INT_MAX displays wrong? - php

I was simply wishing to test for overflow on an integer, such as in C (well, if it were just over integer max anyway). When I looked to see if PHP was actually doing what I told it to, it seems it fails for some reason. Here are my tests of the problem:
define('INT_MAX', 0x7FFFFFFF);
print "In decimal: " . hexdec(INT_MAX) . "<br/>";
print "In decimal: " . hexdec(0x7FFFFFFE) . "<br/>"; //Under int_max
print "In hex: " . dechex(hexdec(INT_MAX)) . "<br/>";
print "Float: " . ((bool)is_float(INT_MAX)?'true':'false') . "<br/>";
Results being:
In decimal: 142929835591
In decimal: 142929835590
In hex: 47483647
Float: false
As I saw on the manual, it will cast to float if overthrown, but it seems to not and is clearly way higher. Am I being insane and missing something here, or is there some odd problem I should really need to know about when working with hexidecimal in PHP?

Your program makes no sense, because you are taking 0x7FFFFFFF which is 2147483647, and then treating it like 0x2147483647, which is 142929835591 in decimal.
Anyway, PHP already has a constant that you can use:
var_dump(PHP_INT_MAX + 1); // converted to float

define('INT_MAX', 0x7FFFFFFF);
This defines INT_MAX to be integer 2147483647. It is unnecessary to interpret it as a hexadecimal number. If you really want to use INT_MAX as a literal hexadecimal value, then you need to declare it as '7FFFFFFF' (inside a string); then the hexdec function will interpret the hexadecimal notation and convert it to a decimal value.
print(dechex(INT_MAX) . "\n");
This prints "7fffffff".

Related

PHP value comparison wrong despite correct typing [duplicate]

This question already has answers here:
Compare floats in php
(17 answers)
Closed 4 years ago.
This piece of code:
$total=$o->cart->getTotalSum();
$subTotal=$o->cart->getSubTotal();
if(floatval($r['sum_total']) != floatval($total) ||
floatval($r['sum_sub']) != floatval($subTotal)) {
echo 'Differs on #' . $r['id'];
echo 'Total: ' . $total . ' / ' . $r['sum_total'];
echo 'Sub: ' . $subTotal . ' / ' . $r['sum_sub'];
}
Gives me this output:
Differs on #697
Total: 19.6 / 19.6
Sub: 19.6 / 19.6
Why? How is that even possible?
I make sure that all values compared are of type float, so no strings could have slipped in.
I must be missing something.
My apologies for not providing really reproducible code, but i wouldn't know how in this case.
If you do it like this they should be the same. But note that a characteristic of floating-point values is that calculations which
seem to result in the same value do not need to actually be identical.
So if $a is a literal .17 and $b arrives there through a calculation
it can well be that they are different, albeit both display the same
value.
Usually you never compare floating-point values for equality like
this, you need to use a smallest acceptable difference:
if (abs(($a-$b)/$b) < 0.00001) { echo "same"; } Something like that.
I think someone else had the exact same problem.
https://stackoverflow.com/a/3148991/2725502

How to flip bits without leading signs in PHP?

On flipping/inverting bits in PHP using the ~-operator the output contains a lot of leading signs, which are obviously unnecessary, if you output the raw integer. On parsing the binary-value back to an integer, you will see that the values are not equal. See the example attached below.
$integer = 0b11110; // raw integer
echo "{$integer}: " . decbin($integer) . PHP_EOL; // print integer-value before flipping
$integer = ~$integer; // flipping/inverting the integer
$binary = decbin($integer);
echo "{$integer}: " . $binary . PHP_EOL; // print integer-value after flipping
echo bindec($binary) . PHP_EOL; // print parsed binary-value
see result on 3v4l.org
Is it possible to remove the leading signs, so that the second usage of echo will output something like 100001 (or just 00001, if you don't take the plus/minus sign into account), because -31 is obviously not the same as 1111111111111111111111111111111111111111111111111111111111100001.

Creating Short Links using intval and base_convert

I found a question about making short codes like TinyURL (https://stackoverflow.com/a/960364/1778465), and I am not sure if what I am doing is working.
I have the following test code:
<?php
$val = intval('murwaresuperchainreaction', 36);
echo $val."\n";
echo base_convert($val, 10, 36) . "\n";
echo "---\n";
$val = intval('murwarebarnstormers', 36);
echo $val."\n";
echo base_convert($val, 10, 36) . "\n";
echo "---\n";
$val = intval('murwarenightmare', 36);
echo $val."\n";
echo base_convert($val, 10, 36) . "\n";
and I am getting these results:
9223372036854775807
1y2p0ij32e8e7
---
9223372036854775807
1y2p0ij32e8e7
---
9223372036854775807
1y2p0ij32e8e7
The question I have, is why are all the results the same? according to the answer I linked to above I should be getting "collision-proof" results, but they are all the same...
As per the Documentation of intval,
The maximum value depends on the system. 32 bit systems have a maximum signed integer range of -2147483648 to 2147483647. So for example on such a system, intval('1000000000000') will return 2147483647. The maximum signed integer value for 64 bit systems is 9223372036854775807.
When you try this method with shorter strings, you'll get collision free results. But large strings will return the maximum value. Hence this method is not suitable to create short codes from large strings.
The value being encoded in the answer you linked is an integer - an ID that references that shortened link's record. By Base 64 or Base 36 encoding the ID, the string is becomes a lot shorter:
echo base_convert(1234567, 10, 36);
// output qglj
intval can then be used to convert the shortened string back to the ID:
echo intval('qglj', 36);
// output 1234567

php session echo intval with decimals

Hello now my code looks like:
echo number_format($_SESSION['price_summ']."<br>");
But I need to have numbers with decimals... I know it should look something like this:
$row['price'] = intval(($row['price']*100))/100;
But it Does not work.
The simplest way is to store your data in database with type of DECIMAL or FLOAT or DOUBLE. And when you will output data from database it will already be in decimal format. Which type to use is relative. Look threw the web to find optimal solution for your situation.
If you want to use PHP use number_format()
$num = "18";
echo number_format((float)$num, 2, '.', ''); //echo will output 105.00
Its really a lot confusing line
echo number_format($_SESSION['price_summ']."<br>");
I guess you want to convert $_SESSION['price_summ'] to float .
Use floatval() for it.
echo number_format(floatval($_SESSION['price_summ']))."<br>";
Alsi you put the bracket after "<br>" which is wrong. In your second code segment you ate simply doing nothing if you $row['price'] is an integer. If it is an integer, go for this
$row['price'] = intval(($row['price']*100.0))/100;

from 1.297503E+17 to 129750300000000000

How can I get php to not use 1.297503E+17 on large int but 129750300000000000
code:
$dag = 29;
$maand = 03;
$jaar = 2012;
$expdate = $dag . "-" . $maand . "-" . $jaar;
$unixstamp = strtotime($expdate);
echo $unixstamp."<br />";
$winstamp = ($unixstamp + 11644560000) * 10000000;
I'm trying to use the number for a Timestamp in ldap.
That's what I would do (tested on 32b platform)
>> number_format(1.297503E+17,0,'.','')
'129750300000000000'
just be aware, that what you get back is a string, an will be converted back to float if you try doing any arithemtics on it. If you need to do math on large integers look into bc_math extension
PHP internally uses big enough integers. Your problem here is the use of echo:
printf ("%d", $winstamp);
$winstamp++;
printf ("%d", $winstamp);
output:
129775320000000000
129775320000000001
Hope this helps
echo rtrim(sprintf("%0.15f", $winstamp), "0.");
This uses sprintf to print a maximum of 15 decimal places, and then trims off any trailing 0 or . chars. (Of course, there's no guarantee that everything will be rounded nicely with trailing zeros as you might expect.)
If you just want a fixed size, then you can adjust the 15 and remove the rtrim.
Apparently, when PHP encounters a number that exceeds the upper limit of 2,147,483,647 for an integer, it automatically converts the number’s type from integer into a double.
Fortunately, we can format these numbers in scientific notation back to their standard integer form using the number_format() function. Here is how to do it:
$winstamp = 1202400000;
$formatted_stamp = number_format($winstamp , 0, '.', '');
echo $formatted_stamp; //outputs 1202400000 as expected

Categories