简体   繁体   中英

Why strlen doesn't work in a paticular digit

I made this function. It seemed it's working but when it comes to 20 digits number, the return value was 19. I'm wondering why this problem happen..

My function

function sumDigits($n) {
    return strlen($n);
}

echo sumDigits(100);  //3
echo sumDigits(1000);  //4
echo sumDigits(12345);  //5
echo sumDigits(1000000000);  //10
echo sumDigits(145874589632);  //12
echo sumDigits(0);  //1
echo sumDigits(12345698745254856320);  //19  <-- Why not 20?

Can you please somebody explain for me?

Thank you so much.

First, I would point out that the name of your function is misleading, as you are not really summing the values of the digits, but are counting the digits. So I would call your function countDigits instead of sumDigits .

The reason why it doesn't work for large numbers, is that the string representation will switch to scientific notation, so you're actually getting the length of "1.2345698745255E+19" not of "12345698745254856320"

If you are only interested in integers, you will get better results with the logarithm:

function countDigits($n) {
    return ceil(log10($n));
}

For numbers that have decimals, there is no good solution, since the precision of 64-bit floating pointing point numbers is limited to about 16 significant digits , so even if you provide more digits, the trailing decimals will be dropped -- this has nothing to do with your function, but with the precision of the number itself. For instance, you'll find that these two literals are equal:

if (1.123456789123456789123456789 == 1.12345678912345678) echo "equal";

Because you function parameter is an integer, exceeding the limit. If you dump it, it actually shows the following: 1.2345698745255E+19 - which is 19 letters.

If you would do the following, it will return 20 - mind the quotes, which declares the input as string.

echo sumDigits("12345698745254856320"); //19 <-- Why not 20? -> now will be 20

As per documentation , strlen() expects a string so a cast happens. With default settings you get 1.2345698745255E+19 :

var_dump((string)12345698745254856320);
string(19) "1.2345698745255E+19"

The root issue is that PHP converts your integer literal to float because it exceeds PHP_INT_MAX so it cannot be represented as integer:

var_dump(12345698745254856320, PHP_INT_MAX);

In 64-bit PHP:

float(1.2345698745254857E+19)
int(9223372036854775807)

You could change display settings to avoid E notation but you've already lost precision at this point.

Computer languages that store integers as a fixed amount of bytes do not allow arbitrary precision. Your best chance is to switch to strings:

var_dump('12345698745254856320', strlen('12345698745254856320'));
string(20) "12345698745254856320"
int(20)

... and optionally use an arbitrary precision library such as BCMath or GMP if you need actual maths.

It's also important to consider that this kind of issues is sometimes a symptom that your input data is not really meant to be an integer but just a very long digit-only string.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM