I ran across this example in the PHP documentation:
<?php
$tests = array(
"42",
1337,
0x539,
02471,
0b10100111001,
1337e0,
"not numeric",
array(),
9.1
);
foreach ($tests as $element) {
if (is_numeric($element)) {
echo "'{$element}' is numeric", PHP_EOL;
} else {
echo "'{$element}' is NOT numeric", PHP_EOL;
}
}
?>
Output:
'42' is numeric
'1337' is numeric
'1337' is numeric
'1337' is numeric
'1337' is numeric
'1337' is numeric
'not numeric' is NOT numeric
'Array' is NOT numeric
'9.1' is numeric
The five examples after '42' all evaluate to '1337'. I can understand why this is the case for '1337e0' (scientific notation), but I don't understand why that is the case for the rest of them.
I wasn't able to find anyone mentioning it in the comments of the documentation and I haven't found it asked here, so could anyone explain why '0x539', '02471', and '0b10100111001' all evaluate to '1337'.
When outputting all numbers get converted to normal representation. Which is decimal number system, and non-scientific notation (e.g. 1e10 - scientific float).
Hex:
Hex numbers start with 0x and are followed by any of 0-9a-f.
0x539 = 9*16^0 + 3*16^1 + 5*16^2 = 1337
Octal:
Octal numbers start with a 0 and contain only the integers 0-7.
02471 = 1*8^0 + 7*8^1 + 4*8^2 + 2*8^3 = 1337
Binary:
Binary numbers start 0b and contain 0s and/or 1s.
0b10100111001 = 1*2^0 + 1*2^3 + 1*2^4 + 1*2^5 + 1*2^8 + 1*2^10 = 1337
They are octal, hexadecimal and binary numbers.
http://php.net/manual/en/language.types.integer.php
Related
Ref: http://php.net/manual/en/function.is-numeric.php.
Example #1 is_numeric().
Why does the Example #1 routine output 1337 4 times instead of 1 time? My expectation is the routine would ouput the other 3 numeric values that follow 1337. Even if I re-arrange the order of the elements it still outputs 1337 4 times. I understand hex and binary values are not allowed, but why does the routine output 1337 for those values. Also, if I change 1337 to 01337 the ouput is 735.
Why these confusing outputs?
<?php
$tests = array(
"42", 1337, 0x539, 02471, 0b10100111001, 1238.443e2, "not numeric",
array(), 9.1, null
);
foreach ($tests as $element) {
if (is_numeric($element)) {
echo var_export($element, true) . " is numeric", PHP_EOL;
} else {
echo var_export($element, true) . " is NOT numeric", PHP_EOL;
}
}
?>
Output:
'42' is numeric
1337 is numeric
1337 is numeric
1337 is numeric
1337 is numeric
123844.300000000002910383045673370361328125 is numeric
'not numeric' is NOT numeric
array () is NOT numeric
9.0999999999999996447286321199499070644378662109375 is numeric
NULL is NOT numeric
Base-N notation syntax
which you had to know to pull this off
Hexadecimal
A number prefixed with 0x will be interpreted as base-16
Octtal
A number prefixed with 0 will be interpreted as base-8
Binary
A number prefixed with 0b will be interpreted as base-2
Conversion to Decimal
1337 base10 (base10 value: 1337)
0x539 base16 (base10 value: 1337)
02471 base8 (base10 value: 1337)
0b10100111001 base2 (base10 value: 1337)
Numbers in strings are always shown in base-10
Converting these numbers to a string, as with var_export, will convert them to base-10, unless you use number_format.
Because that is your values.
For example, if you start a number with a zero, it is means, this number is in octal number system. 02471 = 1337 in decimal number system. The other is the hexa, the remaining the binary.
This is quite a simple problem, but I don't see a simple and straight forward solution.
I have values that represent numeric values, but are strings. Examples: 0.0, 1.0, 10.0, 1.1.
Most time they represent integers, but there can be fractions.
I want to display these numbers as 0, 1, 10, 1.1.
I thought of these straight forward solutions, but they do not account for the occasional fractions:
$val = (int) val;
--OR--
$val = sprintf('%d', $val);
Obviously there would be long solutions, that test if the number is an integer before formatting, but I'm looking for something simple, as short as possible.
Use this simple trick:
echo 0.0 + 0;
echo 1.0 + 0;
echo 10.0 + 0;
echo 1.1 + 0;
this is equivalent to casting to float with
(float)$num
or
floatval($num)
You could try this:
$val = preg_match("/\.0$/", $number_string) ? (int)$number_string : (float)$number_string;
It uses a regular expression on the original string to match a .0 ending, and if there is a match, type casts the string value to an integer, otherwise casts the value to a float.
For the following code snippet the answer is 15.
$a = '5 USD';
$b = 10;
echo $a + $b;
But in the variable $a, if 5 is in between 'USD' or after 'USD' the output is 10. Why is it so?
From php.net:
When a string is evaluated in a numeric context, the resulting value
and type are determined as follows.
If the string does not contain any of the characters '.', 'e', or 'E'
and the numeric value fits into integer type limits (as defined by
PHP_INT_MAX), the string will be evaluated as an integer. In all other
cases it will be evaluated as a float.
The value is given by the initial portion of the string. If the string
starts with valid numeric data, this will be the value used.
Otherwise, the value will be 0 (zero). Valid numeric data is an
optional sign, followed by one or more digits (optionally containing a
decimal point), followed by an optional exponent. The exponent is an
'e' or 'E' followed by one or more digits.
Literally:
$a + $b means numeric + numeric.
"5 USD" starts with a valid numeric data, so PHP converts it into 5.
"USD 5" or "U5SD" starts with not valid numeric data, so PHP converts it into 0.
UPDv1:
<?php
header('Content-Type: text/plain');
function plus($a, $b){
echo $a, ' + ', $b, ' = ', $a + $b, PHP_EOL;
}
plus('5 frogs', 3); // 5 + 3 = 8
plus('frogs: 5', 3); // 0 + 3 = 3
plus('f5rogs', 3); // 0 (not HEX) + 3 = 3
plus('0xF5', 3); // 245 (HEX) + 3 = 248
plus('0011b', 3); // 11 (not BIN) + 3 = 14
plus('1E5', '1.2xx'); // 100000 (FLOAT) + 1.2 (FLOAT) = 100001.2
plus('true', 2); // 0 (not BOOL) + 2 = 2
?>
Also, check out this: php string number concatenation messed up.
UPDv2:
There is "no way" for PHP to typecast string value to octal, regardless of zero-fill effect. Still, as mentioned before, PHP able to typecast string to hexadecimal.
<?php
header('Content-Type: text/plain');
function plus($a, $b){
echo $a, ' + ', $b, ' = ', $a + $b, PHP_EOL;
}
plus(008, 12); // Invalid octal, PHP assumes it is 0. Result: 12.
plus('008', 12); // Invalid octal? No, it is decimal. Result: 20.
plus(0x0F, 1); // Valid hexadecimal. Result: 16.
plus('0x0F', 1); // Valid hexadecimal. Result: 16.
plus('0x0X', 1); // Invalid hexadecimal, PHP assumes it is 0. Result: 1.
?>
It is not mentioned in "string to number conversion" docs.
See PHP Manual Language.types.string.conversion
String conversion to numbers
When a string is evaluated in a numeric context, the resulting value and type are determined as follows.
If the string does not contain any of the characters '.', 'e', or 'E' and the numeric value fits into integer type limits (as defined by PHP_INT_MAX), the string will be evaluated as an integer. In all other cases it will be evaluated as a float.
The value is given by the initial portion of the string. If the string starts with valid numeric data, this will be the value used. Otherwise, the value will be 0 (zero). Valid numeric data is an optional sign, followed by one or more digits (optionally containing a decimal point), followed by an optional exponent. The exponent is an 'e' or 'E' followed by one or more digits.
Examples can be found in the manual (link above)
$foo = 1 + "bob-1.3e3"; // $foo is integer (1)
$foo = 1 + "bob3"; // $foo is integer (1)
$foo = 1 + "10 Small Pigs"; // $foo is integer (11)
Answering your question
$a = '5 USD'; // The string starts with number, so by an implicit cast to int, it will be 5
$b = 10;
echo $a + $b; // = 15
In the other example you wrote
$a = 'USD 5'; // The string does not start with a number, so by an implicit cast to int, it will be 0
$b = 10;
echo $a + $b; // = 10
For more information on this conversion, see the Unix manual page for strtod(3).
Because
php > echo (int)"a";
0
So if you feed the PHP executable with
php > "USD 5" + "10"
it will cast both operands to integers:
php > (int)"USD 5" + (int)"10"
And thus you will receive result of 0 + 10.
Why this FALSE condition is TRUE?
<?php
if(111111111111111119 == 111111111111111118)
{
echo 'Condition is TRUE!';
}
?>
Quote from:
http://php.net/manual/en/language.operators.comparison.php
$a == $b is TRUE if $a is equal to $b after type juggling
If you compare a number with a string or the comparison involves
numerical strings, then each string is converted to a number and the
comparison performed numerically
So because your strings are both numeric they are being converted to numbers first.
Then on some architectures numbers are so big that are overflowing maximum integer size and you are getting equal results.
PHP DOC
Converting to string
An integer or float is converted to a string representing the number textually (including the exponent part for floats). Floating point numbers can be converted using exponential notation (4.1E+6).
Converting to integer
If the float is beyond the boundaries of integer (usually +/- 2.15e+9 = 2^31 on 32-bit platforms and +/- 9.22e+18 = 2^63 on 64-bit platforms), the result is undefined, since the float doesn't have enough precision to give an exact integer result. No warning, not even a notice will be issued when this happens!
My Guess you are using a 32 bits system so therefore
var_dump(111111111111111119,111111111111111118);
var_dump(111111111111111119 === 111111111111111118); // would be true on 32bit
Output
float 1.1111111111111E+17
float 1.1111111111111E+17
true
Simple Solution
if(bcsub("111111111111111119", "111111111111111118") == "0")
{
// 32 bit true
var_dump("Am Free");
}
since it's converted into a numeric value
if('111111111111111119' == '111111111111111118')
{
echo 'Condition is TRUE!';
} else {
echo 'Condition is FALSE!';
}
// on 64 bit: condition is FALSE! (tested on my mac)
I'd assume that on 32bit machine it'd be true. Even when i remove the quotes on my mac it's shows false.
if('a111111111111111119' == 'a111111111111111118')
{
echo 'Condition is TRUE!';
} else {
echo 'Condition is FALSE!';
}
// condition is FALSE!
PHP's documentation on this function is a bit sparse and I have read that this function compares ASCII values so...
echo strcmp('hello', 'hello');
//outputs 0 as expected - strings are equal.
echo '<hr />';
echo strcmp('Hello', 'hello');
//outputs -32, a negative number is expected as
//uppercase H has a lower ASCII value than lowercase h.
echo '<hr />';
echo strcmp('60', '100');
//outputs 5.
The last example is confusing me. I don't understand why it is outputting a positive number.
ASCII Value of 0 = 48
ASCII Value of 1 = 49
ASCII Value of 6 = 54
Total ASCII value of '60' = (54 + 48) = 102
Total ASCII value of '100' = (49 + 48 + 48) = 145
The strcmp() functions is saying that '60' is "greater" than '100' even though it seems that the ASCII value and string length of '100' is greater than '60'
Can anyone explain why?
Thanks
strcmp() returns the difference of the first non-matching character between the strings.
6 - 1 is 5.
When you look at it, you are probably not seeing the characters or digits—just the numbers
Because strcmp() stops at the first difference it finds. Hence the difference between the ASCII value of '1' and the ASCII value of '6'
6 is 5 "larger" than 1. This is lexical comparison. The first character is different, that's where the comparison stops.