Comparing String to Integer Gives Strange Results

Comparing String to Integer gives strange results

From the PHP manual:

String conversion to numbers

When a string is evaluated in a
numeric context, the resulting value
and type are determined as follows.

The string will be evaluated as a
float if it contains any of the
characters '.', 'e', or 'E'.
Otherwise, it will be evaluated as an
integer.

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.

Confusion in comparing string with a number in php

You can see it in the php manual. https://www.php.net/manual/en/language.operators.comparison.php

When comparing a string, number or resource with another string, number or resource:

Translate strings and resources to numbers, usual math

Btw: '151000' is a string, not a number. 15100 would be a number.

Comparing int to string causes weird results in php?

This is discussed in the PHP Manual.

String conversion to numbers

When a string is evaluated in a numeric context, the resulting value
and type are determined as follows.

The string will be evaluated as a float if it contains any of the
characters '.', 'e', or 'E'. Otherwise, it will be evaluated as an
integer.

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.

Note the part that states

If the string starts with valid numeric data, this will be the value
used.

Since your string starts with 32 PHP will compare if(32 == 32) which will be true.

Use type safe checks, that takes the datatype into consideration, when dealing with types that could be different if this behaviour is not desired. Like

1 === 1:   true
1 == 1: true
1 === "1": false
1 == "1": true
"foo" === "foo": true

Weird behaviour in string comparison C++

bool smaller2 = "44" < "111";  // <- returns true, CORRECT

No. You're just getting lukcy. That's comparing the addresses of string literals, not the same thing as an instance of an std::string. As a matter of fact, you could replace that expression in your code as "111" < "44" and it will likely return true if the compiler aligns the strings in memory in the same order as declared.

Correct way to compare strings lexicographical:

std::string str1 = "44";
std::string str2 = "111";
bool cmp1 = (str1 < str2); // false, since '4' is greater than '1'

Correct way to compare strings as integers:

int val1 = std::stoi(str1);  // 44
int val2 = std::stoi(str2); // 111
bool cmp2 = (val1 < val2); // true since 44 is less than 111

weird results with IF

The reason for this result can be found in documentation of function strtol which is used first on using the comparison operators EQU, NEQ, LSS, LEQ, GTR, GEQ as explained in my answer on Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files.

Return Value

On success, the function returns the converted integral number as a long int value.

If no valid conversion could be performed, a zero value is returned (0L).

If the value read is out of the range of representable values by a long int, the function returns LONG_MAX or LONG_MIN (defined in <climits>), and errno is set to ERANGE.

The last sentence is most important here.

It looks like IF in cmd.exe is coded similar to this C code:

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main (int argc, char* argv[])
{
const char csNo[] = "no";
const char csYes[] = "yes";

char* pcEndValue1;
char* pcEndValue2;
int iExitCode = 2;
int iErrorNumber1;
int iErrorNumber2;
int iStringResult1;
int iStringResult2;
long lIntegerValue1;
long lIntegerValue2;

if(argc > 2)
{
/* Convert the two arguments to 32-bit signed integers. */
lIntegerValue1 = strtol(argv[1],&pcEndValue1,0);
iErrorNumber1 = errno;
lIntegerValue2 = strtol(argv[2],&pcEndValue2,0);
iErrorNumber2 = errno;

/* Failed the conversion for any of the two arguments? */
if(((lIntegerValue1 == 0) && (*pcEndValue1 != '\0')) ||
((lIntegerValue2 == 0) && (*pcEndValue2 != '\0')))
{
/* Compare case-sensitive the two arguments as strings. */
iStringResult1 = strcmp(argv[1],argv[2]);
iStringResult2 = strcmp(argv[2],argv[1]);

printf("String comparing %s (a) with %s (b):\n\n",argv[1],argv[2]);
printf("a GEQ b: %s\n",(iStringResult1 >= 0) ? csYes : csNo);
printf("b GEQ a: %s\n",(iStringResult2 >= 0) ? csYes : csNo);
printf("a LEQ b: %s\n",(iStringResult1 <= 0) ? csYes : csNo);
printf("b LEQ a: %s\n",(iStringResult2 <= 0) ? csYes : csNo);
printf("a EQU b: %s\n",(iStringResult2 == 0) ? csYes : csNo);
iExitCode = 1;
}
else
{
/* Compare the values. */
printf("Value comparing %s/%ld (a) with %s/%ld (b):\n\n",argv[1],lIntegerValue1,argv[2],lIntegerValue2);
printf("a GEQ b: %s\n",(lIntegerValue1 >= lIntegerValue2) ? csYes : csNo);
printf("b GEQ a: %s\n",(lIntegerValue2 >= lIntegerValue1) ? csYes : csNo);
printf("a LEQ b: %s\n",(lIntegerValue1 <= lIntegerValue2) ? csYes : csNo);
printf("b LEQ a: %s\n",(lIntegerValue2 <= lIntegerValue1) ? csYes : csNo);
printf("a EQU b: %s\n",(lIntegerValue2 == lIntegerValue1) ? csYes : csNo);
iExitCode = 0;
}
printf("\nError number a: %d ... %s\n",iErrorNumber1,strerror(iErrorNumber1));
printf("Error number b: %d ... %s\n",iErrorNumber2,strerror(iErrorNumber2));
}
return iExitCode;
}

Compiling this C code as console application and running the executable with the parameters 333333333333 444444444444 results for example in output:

Value comparing 333333333333/2147483647 (a) with 444444444444/2147483647 (b):

a GEQ b: yes
b GEQ a: yes
a LEQ b: yes
b LEQ a: yes
a EQU b: yes

Error number a: 2 ... Output of function out of range (ERANGE)
Error number b: 2 ... Output of function out of range (ERANGE)

And running the executable with the parameters 333333333333 222222222222 results for example in output:

Value comparing 333333333333/2147483647 (a) with 222222222222/2147483647 (b):

a GEQ b: yes
b GEQ a: yes
a LEQ b: yes
b LEQ a: yes
a EQU b: yes

Error number a: 2 ... Output of function out of range (ERANGE)
Error number b: 2 ... Output of function out of range (ERANGE)

Note: The error number and the corresponding error string can differ depending on used C compiler respectively standard library.

In both test cases both arguments resulted in a 32-bit signed integer overflow on conversion from string to long int. Therefore strtol returned for all four values LONG_MAX and set errno to ERANGE. But the overflow condition is not evaluated by code of IF in cmd.exe. It is just checked the conversion result and on which character the end pointer points to for both arguments like by the C code above.

In other words IF processes on usage of comparison operators EQU, NEQ, LSS, LEQ, GTR, GEQ always an integer comparison as long as conversion from string to integer does not fail for any of the two arguments because of an invalid character in argument strings. An out of range condition is no reason for IF not doing an integer comparison.

A string comparison is done only if one of the two argument strings contains an invalid character for an integer.

PHP : Comparing string to true returns strange results

When using the comparison (==) operator anything that cannot be converted to false will evaluate to true. This includes any non-empty string. This is because of type juggling in PHP. So "discontinued" evaluates to true because it is not an empty string. If you use the the identical operator (===) type conversions are not done so "discontinued" is treated a literal string and your statement will then evaluate to false.

The following will evaluate to false when type juggling is performed. Everything else will be evaluated as true:

  • "" (an empty string)
  • 0 (0 as an integer)
  • 0.0 (0 as a float)
  • "0" (0 as a string)
  • NULL
  • FALSE
  • array() (an empty array)
  • $var; (a variable declared, but without a value)

Unexpected result when comparing ints

You're comparing the objects' identities. For values lower than 128 the Integer class caches its objects. That's why it is equal in the first example. The other example is with higher values that are not cached.

As @niklon pointed out there is also a lower border of -128 for caching.

Upper border can be adjusted with a VM arg -Djava.lang.Integer.IntegerCache.high=4711.

Further reading in Peter's interesting blog post:
http://vanillajava.blogspot.co.uk/2012/01/surprising-results-of-autoboxing.html



Related Topics



Leave a reply



Submit