# counting the digits in a number, exponential format problem

#### Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

•  Subject
• Author
• Posted on
Hi,

I was wondering if anyone had a good way of counting the digits in a
given (general) number.

Obviously this is trivial for certain numbers. For example, the number
of digits in 523 (or any other natural number) can be found either by:

ceil(log10(523)) or strlen(523)=85 and I am sure there are other ways.

Once you start dealing with floats it gets a little more complicated,
but there are solutions. For example, the number of digits in 3.3 can
be found with:

\$value = 3.3;
if ((int)\$value =3D \$value)
{
return strlen(\$value);
} else {
return strlen(\$value)-1; //the -1 removes the count for the.=92
}

In general the above equation SHOULD work for any float or double, but
it does not. My problem arises when PHP uses exponential formatting
and for some reason there is a break down at E-5. For example:

\$value = 3.3E-4;
if ((int)\$value =3D \$value)
{
return strlen(\$value);
} else {
return strlen(\$value)-1;
}

returns the value 6, which is correct. (There are 6 digits in
0.00033). However, if we try:

\$value = 3.3E-5;
if ((int)\$value =3D \$value)
{
return strlen(\$value);
} else {
return strlen(\$value)-1;
}

it returns 5. The reason it does this is because at E-5 it appears
that PHP stops using the full decimal value and leaves it in the
exponential format. Thus strlen no longer makes sense because it does
strlen(3.3E-5) (and treats not only the.=92 but also theE=92 and =
=91-=91
as characters and includes them in the length calculation) instead of
converting the number to a value and performing strlen(0.000033). Even
if I alter the function to cast the value [return strlen((float)
\$value)-1;] it still returns 5.

There is some difference in PHP between numbers which are E-4 and
numbers which are E-5. The numbers I care about go out to E-8.

If anyone knows why PHP does this, how to force PHP to not use
exponential formatting, or how to count digits in an exponentially
formatted float less than E-4 I would appreciate the help.

P.S. I have tried ini_set("precision", "12"); and the like, but that
does not help. My interest is not in adjusting PHP=92s precision, only
how it treats the numbers.

## Re: counting the digits in a number, exponential format problem

On 12/13/2010 1:46 PM, -matt wrote:

strlen() works on strings, not values (hence the name).  And floating
point numbers are almost never exact values - i.e. 0.00033 is actually
0.00032999999999999999819588758498412062181159853935242 (plus or minus,

This is not PHP - this is how floating point numbers work in most
computers and languages (the exception being those which support BCD
formats).

As for formatting - there are any number of ways to format the data, i.e.

\$s = sprintf("\$12.10f");
echo strlen(\$s) . "->\$s\n";

Prints

12->0.0000033000

Of course, you can also strip trailing zeros, if you wish.

--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
jstucklex@attglobal.net
==================

## Re: counting the digits in a number, exponential format problem

El 13/12/2010 19:46, -matt escribió/wrote:

I'm not sure the whole subject really makes sense. First of all, the
number of digits depends on the base (obviously). Second, a number with
a fixed number of digits in base 10 may not have a representation in
base 2 (e.g. 1.01). Third, there'll be lots of cases where you actually
have infinite digits and you just cut at certain threshold (1/3 = 1.333).

If you absolutely need to do it, I see no other method that handling
numbers as strings rather than floats and pick a maximum number of
decimals when necessary. Compare:

<?php
var_dump( pow(101, 40) );
var_dump( bcpow('101', '40') );
?>

float(1.4888637335882E+80)
string(81)
"148886373358822087497126463801738296202951256788286744534662595050969228887804001"

<?
var_dump(2/3);
var_dump( bcdiv('2', '3', 2) );
var_dump( bcdiv('2', '3', 10) );
var_dump( bcdiv('2', '3', 20) );
?>

float(0.66666666666667)
string(4) "0.66"
string(12) "0.6666666666"
string(22) "0.66666666666666666666"

<?php
var_dump( 10000000000000+0.5 );
?>

float(10000000000000)
string(16) "10000000000000.5"

Whatever, it may help to know the exact reason why you need to count
digits in the first place. Perhaps there's a better solution :-?

--
-- http://alvaro.es - Álvaro G. Vicario - Burgos, Spain
-- Mi sitio sobre programación web: http://borrame.com
-- Mi web de humor satinado: http://www.demogracia.com
--

## Re: counting the digits in a number, exponential format problem

maybe i did not word my question well enough... let me try again.

first of all, this is not a question about machine precision. i am
well aware of the limitations of floating point values and that some
(many) numbers are not actually able to be exactly represented by a
computer. for the sake of argument lets forget that, because i do not
think my question relates to it at all.

at its core, my question really wants to know why there is an
inconsistency in PHP shown by the following example:

strlen(3E-1) = strlen(0.3) = 3
strlen(3E-2) = strlen(0.03) = 4
strlen(3E-3) = strlen(0.003) = 5
strlen(3E-4) = strlen(0.0003) = 6

but then for some reason

strlen(3E-5) = strlen((float)3E-5) = strlen(0.00003) = 6
strlen(3E-6) = strlen((float)3E-5) = strlen(0.000003) = 6

don't get hung up on the numbers. this has happened for any number i
have chosen in the jump between E-4 and E-5. there just seems to be
some inconsistency in how PHP internally represents the variables. and
i would like to know if anyone know what it is, why it is, and/or how
to avoid it?

also, in response to Jerry, PHP is a weakly typed language which means
it doesn't require (nor support for that matter) explicit type
declaration of variables. so saying that strlen only works on strings
doesn't make sense. in PHP a variable is a variable is a variable.
there is no difference.

in response to Alvaro, the reason i would like to count the digits is
because i do not know how wide each number is in a set of numbers and
for each number i need to set a width for a placeholder for the
number. i do not want to force a certain number of digits to always be
outputted so it is constant width, so i would like to adjust my
placeholder width based on the number width.

## Re: counting the digits in a number, exponential format problem

-matt wrote:

well

(a) thats jerry but
(b) internally it does know the difference, The fact that it seamlessly
converts between at its own whim is typical of the noddy approach of
modern languages and software, that likes to make what its designers
consider is the right decision on your behalf, because you are too
stoopid to tell it exactly what to do.

In Jerry's case, this is a fully justified assumption.

well try something like strlen(sprintf("0.03%f",\$mynum)) then..unless
you really want to force it, the language will have at some point a
decision whether to output in decimal or exponential format.

## Re: counting the digits in a number, exponential format problem

On 12/14/2010 10:27 AM, -matt wrote:

Untrue.  There are differences between various types; it's just that PHP
converts between them under the covers.  And sometimes this causes
problems, i.e. 0 == false, but 0 !== false.

If you give strlen() a numeric value, PHP has to convert this to a
string before taking the length.  The result may or may not be what you
want.

http://www.php.net/manual/en/language.types.php .

http://www.php.net/manual/en/language.types.type-juggling.php

--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
jstucklex@attglobal.net
==================

## Re: counting the digits in a number, exponential format problem

certainly at some level PHP must know the difference between a string
and a float, but you can't a define a variable yourself as such. all i
was saying is that strlen() takes a variable, type of that variable
cannot be declared. i understand that strlen is intended for use with
'strings' but it also works for floats up to E-4 after which it breaks
down... all i am wondering is why???

i tried the strlen(sprintf("0.03%f",\$mynum)) suggestion (and several
iterations of it) but no luck. i am not sure where PHP makes the
decision on whether or not to convert to a decimal but that doesn't
appear to help.

@Jerry: i totally agree with you that PHP must convert a numeric value
passed to strlen() to a string at some point. what i do not understand
though is why it makes a difference whether the numeric is 1E-4 or
1E-5. it is like that single order of magnitude drastically changes
the logic/conversion process of the numeric to a string and causes the
answer to not, as you say, 'be what i want'.

it is just not consistent at all. imho a function like strlen() should
pick one way of handling a type of input and do it consistently, not
vary its approach depending on the size of a value passed to it...
especially when it is a weakly typed language.

it appears as though PHP might use something similar to the Linux
function strtod(3) to do its string to float conversions. however, the
man page:
http://linux.die.net/man/3/strtod
does not shed any light on my problem.

## Re: counting the digits in a number, exponential format problem

hi Matt,

The strval function should shed some light here in seeing how php interally
represets the string value of the floats, eg:

echo strval(3E-1); // '0.3'
echo strval(3E-2); // '0.03'
echo strval(3E-3); // '0.003'
echo strval(3E-4); // '0.0003'
echo strval(3E-5); // '3.0E-5'
echo strval(3E-6); // '3.0E-6'

ie after 4 decimal places php will represent the string value of the float
in exponential format.

also see -
http://www.php.net/manual/en/language.types.string.php#language.types.string.casting
"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)."

Cheers
ED

## Re: counting the digits in a number, exponential format problem

@ED: thanks for the reply. at least that helps me understand whats
going on.

i guess what i really want now then is a way to turn off exponential
formatting. i don't like that:

echo floatval(3E-5);    // '3.0E-5'
echo strval(3E-5);      // '3.0E-5'
echo floatval(0.00003); // '3.0E-5'
echo strval(0.00003);   // '3.0E-5'

the strval() output is understandable (now). i could even deal with
the output of floatval(3E-5), but why does it feel the need to convert
to exponential formatting with floatval(0.00003)? 3.0E-5 is much more
'sting like' than 0.00003 is to me, so why would you convert it to the
string form if preforming a numeric operation on the value?

i know that i can can display it however i want with something like
printf("%f",3E-5); but that doesn't help me "count digits" as my

## Re: counting the digits in a number, exponential format problem

Read the description of the (C language, but also applies to PHP)
*printf format conversion %g.  "The argument is printed in style f
or in style e, whichever gives full precision in minimum space".
Guess where it switches?

I assume that in PHP, strlen(\$x), where \$x is a floating-point
number, is equivalent to strlen(sprintf("%g", \$x)), and experimentation
seems to bear this out.

I suggest that you explicitly convert the number into a string using
the format that you want (e.g. %f, not %g, or else use a format
explicitly specifying precision) and apply strlen() to that.  Do
not apply strlen() to floating-point numbers.

I suspect that strlen() does not get to pick anything.  It's done before
strlen() gets its hands on it.

You are concerned with float to string conversions, not the other
way around.

## Re: counting the digits in a number, exponential format problem

On Fri, 23 Dec 2011 13:00:44 -0600, Gordon Burditt wrote:

For the specific case given by the OP, it could switch over at 1.0E-3 /
1.0E-4 instead of 1.0E-4 / 1.0E-5, given that both representations give
the same number of characters.

0.001 = 1.0E-3 <- fixed format shorter
0.0001 = 1.0E-4 <- both same length
0.00001 = 1.0E-5 <- exp format shorter

In the more general case, it won't always switch over at the E-4 / E-5
boundary either, it seems from writing down various decimal fractions in
both formats that E-3 is more commonly the point where both forms take
the same space. Where the exponent is -2 or higher (in the sense that 0
is higher than -1 is higher than -2) then the number will probably be
displayed in fixed format, and where the exponent is -5 or lower (in the
same sense as above) then the number will probably be displayed in
exponential format, but if the exponent is 3 or 4, then it depends on the
number of significant digits. In the latter case, behaviour might change
in future if the underlying c function changes slightly, even though such
a change might not result in the described operation of that function
being any different to the currently described and observed operation.

I guess that when the exponent travels away from 0 in a positive
direction the effect doesn't occur, because if the digits to the left of
the fixed format decimal point are significant, adding an exponent will
always increase the space taken by the space used by the exponential
representation:

1234567890.0123456789
1.2345678900123456789E9

Rgds

Denis McMahon

## Re: counting the digits in a number, exponential format problem

El 14/12/2010 16:27, -matt escribió/wrote:

explanation anyway ;-)

Let's have a look at the function definition <http://php.net/strlen :

Description
int strlen ( string \$string )

Returns the length of the given string.

As the manual states, this function works on strings.

As almost all langs out there, PHP *has* data types. Otherwise, how
could do simple math with variables? You can see it yourself if you
inspect stuff with var_dump() which is, by the way, the recommended way
to see the actual contents of variables:

<?php var_dump(0, 0.1, '0', TRUE, FALSE); ?>

int(0)
float(0.1)
string(1) "0"
bool(true)
bool(false)

PHP is, however, *loosely typed*. That means that a variable can hold
any data type, unlike other langs where you must declare a type and are
forced to use it. E.g., you cannot do this in C:

int i = 7;
i = 3.14; /* Error */

... but you can in PHP:

\$i = 7; // int(7)
\$i = 3.14; //float(3.14)

It also means that PHP always performs transparent type casting when
necessary, no matter how stupid it may seem:

\$i = pow(10, "Bunnies") / TRUE; // int(1)

And this is the precise reason why you can actually do this:

strlen(33);

C, Java or other strongly typed languages would never allow you to pass
a number to a function that expects a string. Your code would not even
compile. PHP allows you to strlen(33) and it's not because strlen() can
calculate the length of a number (it cannot); it's because it casts the
argument to string before applying its string abilities.

The casting is performed with precise rules that are documented:

http://es.php.net/manual/en/language.types.type-juggling.php
http://es.php.net/manual/en/language.types.string.php#language.types.string.casting

It happens that rules are not always intuitive:

\$i = (string)TRUE; // string(1) "1"
\$i = (string)FALSE; // string(0) ""

... which can lead to surprising (yet expected) results:

\$i = strlen(TRUE); // int(1)
\$i = strlen(FALSE); // int(0)

... and also explains why plain echo statements are not a good debugging
tool:

echo 4<3; // Prints nothing
var_dump(4<3); // Prints bool(false)

Alright, you don't really want to know the length of a numeric variable.
You know to want the length of its string representation. That's easy to
calculate but clearly depends of how you want to display the number:

1000
1,000
1,000.00
0001000
...

You just need to pick a string representation, generate such string and
strlen() it:

\$display = number_format(20000/3, 2, '.', ','); // 6,666.67
\$length = strlen(\$display); // 8

If you just strlen() a float variable you're telling PHP: please format
the number to your liking and tell me how room it takes. It won't lie
because that's exactly the number of characters it'll use to echo it.

--
-- http://alvaro.es - Álvaro G. Vicario - Burgos, Spain
-- Mi sitio sobre programación web: http://borrame.com
-- Mi web de humor satinado: http://www.demogracia.com
--

## Re: counting the digits in a number, exponential format problem

@Alvaro: thanks for your reply. i am by no means a PHP expert
(obviously) so this is all good information.

exactly!!! the only problem is that i have no control of how the
number comes to me, nor how it is displayed later. however, it is
always displayed using full decimal form with the least number of
digits and no commas. for example: 1234 not 1,234.0, etc. the problem
i was having is how PHP changes its conversion process to strings for
float from E-4 to E-5. that is what has been really throwing me off.
however, i think i have a working solution now for my original
problem. below is my function if anyone cares to see my solution:

function numberOfDigits(\$value)
{
if(!is_numeric(\$value))
{
return 0;
}
if((int)\$value == \$value)
{
return strlen((int)\$value);
}
for(\$i=1; \$i<=10; \$i+=1)
{
\$temp = \$value * pow(10,\$i);
if((int)\$temp == \$temp)
{
if((int)\$value == 0)
{
return \$i + 1;
}
else
{
return strlen(\$temp);
}
}
}
return strlen((int)\$value) + 10;
}

echo numberOfDigits(1);       // '1'
echo numberOfDigits(123.456); // '6'
echo numberOfDigits(1.0);     // '1'
echo numberOfDigits(0.33);    // '3'
echo numberOfDigits(0.033);   // '4'
echo numberOfDigits(0.0033);  // '5'
echo numberOfDigits(0.00033); // '6'
echo numberOfDigits(3.3E-5);  // '7'
echo numberOfDigits(3.3E-6);  // '8'
echo numberOfDigits(3.3E-7);  // '9'

i use a for loop which only goes to \$i=10 because i really only care
about numbers down to E-9ish. clearly you could change that to a while
loop or something and make the function more general.

thanks again everyone for all the help and information.

## Re: counting the digits in a number, exponential format problem

On 12/15/2010 10:53 AM, -matt wrote:

But you DO have control.  Just format the number yourself, instead of
using the default PHP formatting.

The defaults are there to make life easier.  However, they don't work in
all circumstances.  When that happens, there are (almost, anyway) always
ways to do the job yourself.

--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
jstucklex@attglobal.net
==================