371

In Python, how do you find the number of digits in an integer?

martineau
  • 119,623
  • 25
  • 170
  • 301
Strigoides
  • 4,329
  • 5
  • 23
  • 25
  • 4
    I don't understand your question. Did you mean the size of an integer? Do you want to find the number of digits? Please clarify. – batbrat Feb 03 '10 at 04:59

31 Answers31

482

If you want the length of an integer as in the number of digits in the integer, you can always convert it to string like str(133) and find its length like len(str(123)).

Alois Mahdal
  • 10,763
  • 7
  • 51
  • 69
GeekTantra
  • 11,580
  • 6
  • 41
  • 55
  • 33
    Of course, if you're looking for the number of digits, this will produce a result that's too large for negative numbers, since it will count the negative sign. – Chris Upchurch Feb 03 '10 at 05:03
  • 81
    Hey, this is a slow solution. I did a factorial of a random 6 digit number, and found its length. This method took **95.891** seconds. And `Math.log10` method took *only* **7.486343383789062e-05** seconds, approximately **1501388** times faster! – FadedCoder Mar 19 '17 at 16:30
  • 8
    This isn't just slow, but consumes way more memory and can cause trouble in large numbers. use `Math.log10` instead. – Peyman Mar 30 '20 at 08:36
  • 7
    But isn't the number of digits in '0' equals to 1? – GeekTantra Aug 17 '21 at 03:39
  • 3
    Use `abs()` to remove negative sign. eg. `len(str(abs(-123))) == 3` – Neil Oct 04 '21 at 17:54
374

Without conversion to string

import math
digits = int(math.log10(n))+1

To also handle zero and negative numbers

import math
if n > 0:
    digits = int(math.log10(n))+1
elif n == 0:
    digits = 1
else:
    digits = int(math.log10(-n))+2 # +1 if you don't count the '-' 

You'd probably want to put that in a function :)

Here are some benchmarks. The len(str()) is already behind for even quite small numbers

timeit math.log10(2**8)
1000000 loops, best of 3: 746 ns per loop
timeit len(str(2**8))
1000000 loops, best of 3: 1.1 µs per loop

timeit math.log10(2**100)
1000000 loops, best of 3: 775 ns per loop
 timeit len(str(2**100))
100000 loops, best of 3: 3.2 µs per loop

timeit math.log10(2**10000)
1000000 loops, best of 3: 844 ns per loop
timeit len(str(2**10000))
100 loops, best of 3: 10.3 ms per loop
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
  • 2
    Perhaps `digits = n and 1 + int(math.log(abs(n), 10))` –  Feb 03 '10 at 05:50
  • 13
    Using log10 for this is a mathematician's solution; using len(str()) is a programmer's solution, and is clearer and simpler. – Glenn Maynard Feb 03 '10 at 07:01
  • 100
    @Glenn: I certainly hope you aren't implying this is a bad solution. The programmer's naive O(log10 n) solution works well in ad-hoc, prototyping code -- but I'd much rather see mathematicians elegant O(1) solution in production code or a public API. +1 for gnibbler. – Juliet Feb 03 '10 at 08:48
  • It's better to be correct than to be wrong and fast. len(str(abs(x))) has the advantage that it's pretty bloody hard to get wrong. Heck, even len(str(x)) is only wrong to some people ;). – Devin Jeanpierre Apr 24 '10 at 18:00
  • 6
    @gnibbler: +1. Never realized that log10 can be used to find the magnitude of a number. Wish I could up-vote more then once :). – Abbas Dec 20 '10 at 18:10
  • 18
    Hi! I go something strange, can Anyone of You please explain me why `int(math.log10(x)) +1` for `99999999999999999999999999999999999999999999999999999999999999999999999` (**71 nines**) returns **72** ? I thought that I could rely on log10 method but I have to use len(str(x)) instead :( – Marecky Mar 04 '12 at 01:19
  • It seems to add one like you said once there is 16 digits or more, I would also like to know why this happens. – jamylak Apr 06 '12 at 01:09
  • 9
    I believe i know the reason for the strange behaviour, it is due to floating point inaccuracies eg. `math.log10(999999999999999)` is equal to `14.999999999999998` so `int(math.log10(999999999999999))` becomes `14`. But then `math.log10(9999999999999999)` is equal to `16.0`. Maybe using `round` is a solution to this problem. – jamylak Apr 06 '12 at 01:22
  • 3
    @Juliet I love mathematics, but I don't think log10 is a good solution. In addition to the issues already pointed out, it's not `O(1)` time as you claim, either. (Similarly, the explicit mathematical formula for the Fibonacci sequence is slower to compute than the iterative solution.) For any sane purpose `len(str(n))` is fast enough, much more Pythonic, and much less obscure. – gengkev Jul 27 '15 at 03:39
  • 2
    In fact, log10 probably performs in slower than `O(log n)` time, [according to Wikipedia](https://en.wikipedia.org/wiki/Computational_complexity_of_mathematical_operations)! Still, because math is fun: for a faster `O(log n)` mathematical solution, first approximate with `b = int(n.bit_length() * math.log10(2))`, then round up if necessary by checking if `n == 0 or abs(n) >= 10**b`. – gengkev Jul 27 '15 at 04:09
  • 3
    My bad: technically floating-point math is greater than `O(log n)`, but very, very fast. As for my approximation, turns out that `n.bit_length() * math.log10(2)` is only very marginally faster than `math.log10(n)`. However, my approximation requires exponentiation for its check (`10**b`) which takes up most of the time. `math.log10(n)` requires the same check at around `999999999999999`, but at that small of a value, `len(str(n))` is still competitive. ¯\_(ツ)_/¯ – gengkev Jul 27 '15 at 05:26
  • 11
    With some more testing: under `10**12`, `len(str(n))` is the fastest. Above that, plain log10 is always the fastest, but above `10**15`, it's incorrect. Only at around `10**100` does my solution (~log10 with the `10**b` check) begins to beat out `len(str(n))`. In conclusion, **use `len(str(n))`** ! – gengkev Jul 27 '15 at 06:04
  • See @Seti's example below for an explanation of what to do with more than 15 digits: https://stackoverflow.com/a/42736085/3732147 – Conor Livingston Feb 26 '18 at 16:39
  • You should benchmark your final function, which handles `n < 1`, instead `math.log10` and compare with function that uses `len(str(...))`. – WloHu Aug 28 '18 at 12:20
  • 3
    I believe it should be `digits = int(math.floor(math.log10(abs(n))))+1`. This covers 100 giving 2 when it's actually three digits. Likewise for 1000. For n=0 return 1 instead. Same count of digits in a negative number as a positive, so normalize with absolute value. Edge cases matter. – ingyhere Apr 16 '19 at 08:08
  • 2019 update: I tried this solution bare (no floor, no anything) with a number with random 144 digits and it still returned 144. Does anyone know what changed? – Filip Feb 21 '20 at 01:11
  • I think that Banker's rounding in Python 3 will make this logarithm solution less accurate. – Bee May 12 '20 at 15:07
  • For whom it may concern: In C using the log function is not the prepared solution: (https://stackoverflow.com/questions/1068849/how-do-i-determine-the-number-of-digits-of-an-integer-in-c) – Avizipi Mar 15 '21 at 13:26
  • How about using abs() instead? The goal is to find no of digits! – Harshil Modi Apr 01 '21 at 09:46
  • Relying on int() behaviour being similar of math.floor() is not a good idea, but to begin with, relying on floor with floating points is always bad. I prefer the `len(str(0))` solution which works, will always work and does what the OP asked – Iuri Guilherme Jan 17 '23 at 20:02
64

All math.log10 solutions will give you problems.

math.log10 is fast but gives problem when your number is greater than 999999999999997. This is because the float have too many .9s, causing the result to round up.

Therefore, to get the best performance, use math.log for smaller numbers and only len(str()) beyond what math.log can handle:

def getIntegerPlaces(theNumber):
    if theNumber <= 999999999999997:
        return int(math.log10(theNumber)) + 1
    else:
        return len(str(theNumber))
Calvintwr
  • 8,308
  • 5
  • 28
  • 42
  • Thank you. That is a good counter-example for `math.log10`. It's interesting to see how binary representation flips the values giving mathematically incorrect result. – WloHu Aug 28 '18 at 12:31
  • 1
    then len(str(num)) would be better – vighnesh153 Jul 27 '19 at 13:07
  • 2
    @Vighnesh Raut: And magnitudes slower – javapyscript Jan 15 '20 at 13:31
  • 1
    "It is dangerous to rely on floating-point operations giving exact results" - Mark Dickinson, a member of core Python development team https://bugs.python.org/issue3724 – Sreeragh A R Jun 06 '20 at 05:18
  • def getIntegerPlaces(theNumber): if theNumber <= 999999999999997: return int(math.log10(abs(theNumber))) + 1 else: return int(math.log10(abs(theNumber))) – Harshil Modi Apr 01 '21 at 09:42
  • 1
    @ChaitanyaBangera *"And magnitudes slower"* - You misspelled ["faster"](https://tio.run/##vZFNbsMgEIX3nGKWmFiRqVU1iUqO0CtYTgI1Ej8WHqvK6V1wkEN6gL4dM9@8NyPGOw7etYcxLIsK3gJqKzWCtqMPmF@E3KQCxSkO8mu2FxmqE4EorWArwaeA44s@HlBSkDgHB9ohtT0Oe@O/eVPYVbADvtLSTPI5d/Wzw@gtgL9vxZ9BG1kEn2O3YSyzz@HSYCeyf7FN7uXr3v7jukwa6eiEoUQIUVM8U/E6rkKIg795B2AMWqJ8ADW7a0wDNaUdxpCCU4261eeFYG1iUDx@kpreXm79CTJeg1vzBW@iqs0N65XYd53rrey6all@AQ) there. – Kelly Bundy Feb 09 '22 at 16:54
  • 3
    Jesus christ that's inefficient. how is that at 60 score? It's orders of magnitudes slower than even string conversion. For a 1040598 digit number (`2**3456789`), `len(str(number))` took about 12 seconds. I forgot this in the background for minutes and it was still not done – itsTyrion Aug 25 '22 at 01:14
43

It's been several years since this question was asked, but I have compiled a benchmark of several methods to calculate the length of an integer.

def libc_size(i): 
    return libc.snprintf(buf, 100, c_char_p(b'%i'), i) # equivalent to `return snprintf(buf, 100, "%i", i);`

def str_size(i):
    return len(str(i)) # Length of `i` as a string

def math_size(i):
    return 1 + math.floor(math.log10(i)) # 1 + floor of log10 of i

def exp_size(i):
    return int("{:.5e}".format(i).split("e")[1]) + 1 # e.g. `1e10` -> `10` + 1 -> 11

def mod_size(i):
    return len("%i" % i) # Uses string modulo instead of str(i)

def fmt_size(i):
    return len("{0}".format(i)) # Same as above but str.format

(the libc function requires some setup, which I haven't included)

size_exp is thanks to Brian Preslopsky, size_str is thanks to GeekTantra, and size_math is thanks to John La Rooy

Here are the results:

Time for libc size:      1.2204 μs
Time for string size:    309.41 ns
Time for math size:      329.54 ns
Time for exp size:       1.4902 μs
Time for mod size:       249.36 ns
Time for fmt size:       336.63 ns
In order of speed (fastest first):
+ mod_size (1.000000x)
+ str_size (1.240835x)
+ math_size (1.321577x)
+ fmt_size (1.350007x)
+ libc_size (4.894290x)
+ exp_size (5.976219x)

(Disclaimer: the function is run on inputs 1 to 1,000,000)

Here are the results for sys.maxsize - 100000 to sys.maxsize:

Time for libc size:      1.4686 μs
Time for string size:    395.76 ns
Time for math size:      485.94 ns
Time for exp size:       1.6826 μs
Time for mod size:       364.25 ns
Time for fmt size:       453.06 ns
In order of speed (fastest first):
+ mod_size (1.000000x)
+ str_size (1.086498x)
+ fmt_size (1.243817x)
+ math_size (1.334066x)
+ libc_size (4.031780x)
+ exp_size (4.619188x)

As you can see, mod_size (len("%i" % i)) is the fastest, slightly faster than using str(i) and significantly faster than others.

Jack Moody
  • 1,590
  • 3
  • 21
  • 38
NoOneIsHere
  • 1,054
  • 16
  • 28
  • 1
    You really should include the libc setup, `libc = ctyle.CDLL('libc.so.6', use_errno=True)` (guessing this is it). And it doesn't work for numbers greater than `sys.maxsize` because floating point numbers can't be "very large". So any number above that, I guess you're stuck with one of the slower methods. – Torxed Oct 27 '19 at 00:39
  • Can someone translate `len("%i" % i)` to C++. I want test tis in C++. – Tom Tom Apr 06 '23 at 14:27
28

Python 2.* ints take either 4 or 8 bytes (32 or 64 bits), depending on your Python build. sys.maxint (2**31-1 for 32-bit ints, 2**63-1 for 64-bit ints) will tell you which of the two possibilities obtains.

In Python 3, ints (like longs in Python 2) can take arbitrary sizes up to the amount of available memory; sys.getsizeof gives you a good indication for any given value, although it does also count some fixed overhead:

>>> import sys
>>> sys.getsizeof(0)
12
>>> sys.getsizeof(2**99)
28

If, as other answers suggests, you're thinking about some string representation of the integer value, then just take the len of that representation, be it in base 10 or otherwise!

Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • 1
    Sorry this answer got minus-ed. It is informative and to the plausible point of the question (if it were only more specific about which 'len' is desired). +1 – mjv Feb 03 '10 at 05:36
  • 3
    This looks interesting but not sure how to extract the length – Tjorriemorrie Jul 18 '18 at 02:14
16

Let the number be n then the number of digits in n is given by:

math.floor(math.log10(n))+1

Note that this will give correct answers for +ve integers < 10e15. Beyond that the precision limits of the return type of math.log10 kicks in and the answer may be off by 1. I would simply use len(str(n)) beyond that; this requires O(log(n)) time which is same as iterating over powers of 10.

Thanks to @SetiVolkylany for bringing my attenstion to this limitation. Its amazing how seemingly correct solutions have caveats in implementation details.

BiGYaN
  • 6,974
  • 5
  • 30
  • 43
  • 1
    It does not work if n outside of range [-999999999999997, 999999999999997] – PADYMKO Mar 11 '17 at 13:16
  • @SetiVolkylany, I tested it till 50 digits for python2.7 and 3.5. Just do a `assert list(range(1,51)) == [math.floor(math.log10(n))+1 for n in (10**e for e in range(50))]`. – BiGYaN Mar 12 '17 at 19:28
  • 2
    try it with the Python2.7 or the Python3.5 ```>>> math.floor(math.log10(999999999999997))+1 15.0 >>> math.floor(math.log10(999999999999998))+1 16.0```. Look my answer http://stackoverflow.com/a/42736085/6003870. – PADYMKO Mar 13 '17 at 09:11
14

Well, without converting to string I would do something like:

def lenDigits(x): 
    """
    Assumes int(x)
    """

    x = abs(x)

    if x < 10:
        return 1

    return 1 + lenDigits(x / 10)

Minimalist recursion FTW

odradek
  • 993
  • 7
  • 14
12

As mentioned the dear user @Calvintwr, the function math.log10 has problem in a number outside of a range [-999999999999997, 999999999999997], where we get floating point errors. I had this problem with the JavaScript (the Google V8 and the NodeJS) and the C (the GNU GCC compiler), so a 'purely mathematically' solution is impossible here.


Based on this gist and the answer the dear user @Calvintwr

import math


def get_count_digits(number: int):
    """Return number of digits in a number."""

    if number == 0:
        return 1

    number = abs(number)

    if number <= 999999999999997:
        return math.floor(math.log10(number)) + 1

    count = 0
    while number:
        count += 1
        number //= 10
    return count

I tested it on numbers with length up to 20 (inclusive) and all right. It must be enough, because the length max integer number on a 64-bit system is 19 (len(str(sys.maxsize)) == 19).

assert get_count_digits(-99999999999999999999) == 20
assert get_count_digits(-10000000000000000000) == 20
assert get_count_digits(-9999999999999999999) == 19
assert get_count_digits(-1000000000000000000) == 19
assert get_count_digits(-999999999999999999) == 18
assert get_count_digits(-100000000000000000) == 18
assert get_count_digits(-99999999999999999) == 17
assert get_count_digits(-10000000000000000) == 17
assert get_count_digits(-9999999999999999) == 16
assert get_count_digits(-1000000000000000) == 16
assert get_count_digits(-999999999999999) == 15
assert get_count_digits(-100000000000000) == 15
assert get_count_digits(-99999999999999) == 14
assert get_count_digits(-10000000000000) == 14
assert get_count_digits(-9999999999999) == 13
assert get_count_digits(-1000000000000) == 13
assert get_count_digits(-999999999999) == 12
assert get_count_digits(-100000000000) == 12
assert get_count_digits(-99999999999) == 11
assert get_count_digits(-10000000000) == 11
assert get_count_digits(-9999999999) == 10
assert get_count_digits(-1000000000) == 10
assert get_count_digits(-999999999) == 9
assert get_count_digits(-100000000) == 9
assert get_count_digits(-99999999) == 8
assert get_count_digits(-10000000) == 8
assert get_count_digits(-9999999) == 7
assert get_count_digits(-1000000) == 7
assert get_count_digits(-999999) == 6
assert get_count_digits(-100000) == 6
assert get_count_digits(-99999) == 5
assert get_count_digits(-10000) == 5
assert get_count_digits(-9999) == 4
assert get_count_digits(-1000) == 4
assert get_count_digits(-999) == 3
assert get_count_digits(-100) == 3
assert get_count_digits(-99) == 2
assert get_count_digits(-10) == 2
assert get_count_digits(-9) == 1
assert get_count_digits(-1) == 1
assert get_count_digits(0) == 1
assert get_count_digits(1) == 1
assert get_count_digits(9) == 1
assert get_count_digits(10) == 2
assert get_count_digits(99) == 2
assert get_count_digits(100) == 3
assert get_count_digits(999) == 3
assert get_count_digits(1000) == 4
assert get_count_digits(9999) == 4
assert get_count_digits(10000) == 5
assert get_count_digits(99999) == 5
assert get_count_digits(100000) == 6
assert get_count_digits(999999) == 6
assert get_count_digits(1000000) == 7
assert get_count_digits(9999999) == 7
assert get_count_digits(10000000) == 8
assert get_count_digits(99999999) == 8
assert get_count_digits(100000000) == 9
assert get_count_digits(999999999) == 9
assert get_count_digits(1000000000) == 10
assert get_count_digits(9999999999) == 10
assert get_count_digits(10000000000) == 11
assert get_count_digits(99999999999) == 11
assert get_count_digits(100000000000) == 12
assert get_count_digits(999999999999) == 12
assert get_count_digits(1000000000000) == 13
assert get_count_digits(9999999999999) == 13
assert get_count_digits(10000000000000) == 14
assert get_count_digits(99999999999999) == 14
assert get_count_digits(100000000000000) == 15
assert get_count_digits(999999999999999) == 15
assert get_count_digits(1000000000000000) == 16
assert get_count_digits(9999999999999999) == 16
assert get_count_digits(10000000000000000) == 17
assert get_count_digits(99999999999999999) == 17
assert get_count_digits(100000000000000000) == 18
assert get_count_digits(999999999999999999) == 18
assert get_count_digits(1000000000000000000) == 19
assert get_count_digits(9999999999999999999) == 19
assert get_count_digits(10000000000000000000) == 20
assert get_count_digits(99999999999999999999) == 20

All example of codes tested with the Python 3.5

Community
  • 1
  • 1
PADYMKO
  • 4,217
  • 2
  • 36
  • 41
12

Count the number of digits w/o convert integer to a string:

x=123
x=abs(x)
i = 0
while x >= 10**i:
    i +=1
# i is the number of digits
datanew
  • 279
  • 3
  • 14
5

Here is a bulky but fast version :

def nbdigit ( x ):
    if x >= 10000000000000000 : # 17 -
        return len( str( x ))
    if x < 100000000 : # 1 - 8
        if x < 10000 : # 1 - 4
            if x < 100             : return (x >= 10)+1 
            else                   : return (x >= 1000)+3
        else: # 5 - 8                                                 
            if x < 1000000         : return (x >= 100000)+5 
            else                   : return (x >= 10000000)+7
    else: # 9 - 16 
        if x < 1000000000000 : # 9 - 12
            if x < 10000000000     : return (x >= 1000000000)+9 
            else                   : return (x >= 100000000000)+11
        else: # 13 - 16
            if x < 100000000000000 : return (x >= 10000000000000)+13 
            else                   : return (x >= 1000000000000000)+15

Only 5 comparisons for not too big numbers. On my computer it is about 30% faster than the math.log10 version and 5% faster than the len( str()) one. Ok... no so attractive if you don't use it furiously.

And here is the set of numbers I used to test/measure my function:

n = [ int( (i+1)**( 17/7. )) for i in xrange( 1000000 )] + [0,10**16-1,10**16,10**16+1]

NB: it does not manage negative numbers, but the adaptation is easy...

Captain'Flam
  • 479
  • 4
  • 12
  • It is crazy how we can get so caught up on the fastest smart solution. There aren't even that many if checks, it massively improves everything, it is not ugly, yet this is not the favorite solution. If we are worrying about number accuracy we wouldn't be using python integers to begin with. It's not even that much code! We should be making things easier AND simpler. Thank you for reminding me of that Captain'Flam :D – Jaacko Torus Jul 20 '23 at 05:01
4

For posterity, no doubt by far the slowest solution to this problem:

def num_digits(num, number_of_calls=1):
    "Returns the number of digits of an integer num."
    if num == 0 or num == -1:
        return 1 if number_of_calls == 1 else 0
    else:
        return 1 + num_digits(num/10, number_of_calls+1)
Stefan van den Akker
  • 6,661
  • 7
  • 48
  • 63
3
from math import log10
digits = lambda n: ((n==0) and 1) or int(log10(abs(n)))+1
2

Assuming you are asking for the largest number you can store in an integer, the value is implementation dependent. I suggest that you don't think in that way when using python. In any case, quite a large value can be stored in a python 'integer'. Remember, Python uses duck typing!

Edit: I gave my answer before the clarification that the asker wanted the number of digits. For that, I agree with the method suggested by the accepted answer. Nothing more to add!

batbrat
  • 5,155
  • 3
  • 32
  • 38
2

It can be done for integers quickly by using:

len(str(abs(1234567890)))

Which gets the length of the string of the absolute value of "1234567890"

abs returns the number WITHOUT any negatives (only the magnitude of the number), str casts/converts it to a string and len returns the string length of that string.

If you want it to work for floats, you can use either of the following:

# Ignore all after decimal place
len(str(abs(0.1234567890)).split(".")[0])

# Ignore just the decimal place
len(str(abs(0.1234567890)))-1

For future reference.

Frogboxe
  • 386
  • 4
  • 12
  • I think it would be simpler to truncate the input number itself (e. g. with a cast to `int`) than to truncate its decimal string representation: `len(str(abs(int(0.1234567890))))` returns 1. – David Foerster Jul 12 '17 at 11:21
  • No, that wouldn't work. If you turn 0.17 into an integer you get 0 and the length of that would be different to the length of 0.17 – Frogboxe Jul 12 '17 at 11:26
  • In the first case, by truncating everything from and including the decimal point off the string representation you're effectively calculating the length of the *integral* part of the number, which is what my suggestion does too. For 0.17 both solutions return 1. – David Foerster Jul 12 '17 at 11:32
2
def length(i):
  return len(str(i))
2

Format in scientific notation and pluck off the exponent:

int("{:.5e}".format(1000000).split("e")[1]) + 1

I don't know about speed, but it's simple.

Please note the number of significant digits after the decimal (the "5" in the ".5e" can be an issue if it rounds up the decimal part of the scientific notation to another digit. I set it arbitrarily large, but could reflect the length of the largest number you know about.

2
def count_digit(number):
  if number >= 10:
    count = 2
  else:
    count = 1
  while number//10 > 9:
    count += 1
    number = number//10
  return count
Del_sama
  • 61
  • 3
  • While this code may solve the question, [including an explanation](//meta.stackexchange.com/q/114762) of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please [edit] your answer to add explanations and give an indication of what limitations and assumptions apply. – Adrian Mole Apr 21 '20 at 16:57
2
def digits(n)
    count = 0
    if n == 0:
        return 1
    
    if n < 0:
        n *= -1

    while (n >= 10**count):
        count += 1
        n += n%10

    return count

print(digits(25))   # Should print 2
print(digits(144))  # Should print 3
print(digits(1000)) # Should print 4
print(digits(0))    # Should print 1
vsminkov
  • 10,912
  • 2
  • 38
  • 50
2

Here is another way to compute the number of digit before the decimal of any number

from math import fabs

len(format(fabs(100),".0f"))
Out[102]: 3

len(format(fabs(1e10),".0f"))
Out[165]: 11

len(format(fabs(1235.4576),".0f"))
Out[166]: 4

I did a brief benchmark test, for 10,000 loops

num     len(str(num))     ----  len(format(fabs(num),".0f")) ---- speed-up
2**1e0  2.179400e-07 sec  ----     8.577000e-07 sec          ---- 0.2541
2**1e1  2.396900e-07 sec  ----     8.668800e-07 sec          ---- 0.2765
2**1e2  9.587700e-07 sec  ----     1.330370e-06 sec          ---- 0.7207
2**1e3  2.321700e-06 sec  ----     1.761305e-05 sec          ---- 0.1318

It is slower but a simpler option.

But even this solution does give wrong results from 9999999999999998

len(format(fabs(9999999999999998),".0f"))
Out[146]: 16
len(format(fabs(9999999999999999),".0f"))
Out[145]: 17
2

A fast solution that uses a self-correcting implementation of floor(log10(n)) based on "Better way to compute floor of log(n,b) for integers n and b?".

import math

def floor_log(n, b):
    res = math.floor(math.log(n, b))
    c = b**res
    return res + (b*c <= n) - (c > n)

def num_digits(n):
    return 1 if n == 0 else 1 + floor_log(abs(n), 10)

This is quite fast and will work whenever n < 10**(2**52) (which is really really big).

jodag
  • 19,885
  • 5
  • 47
  • 66
  • 1
    For your linked question, you might be interested in [my answer](https://stackoverflow.com/a/74099536) below which uses binary instead of logarithms. It is based on the same theory and generalizes to other bases as well. – Simply Beautiful Art Oct 17 '22 at 15:26
2

As shown by other answers, using log10 leads to incorrect results for large n while using len(str(...)) or manual looping leads to slow performance for large n. Jodag's answer provides a really good alternative which only fails for integers that will likely crash your computer, but we can do a bit better and even faster (for n small enough that math.log2 is guaranteed to be accurate) by avoid logarithms altogether and using binary instead:

def num_digits(n: int) -> int:
    assert n > 0
    i = int(0.30102999566398114 * (n.bit_length() - 1)) + 1
    return (10 ** i <= n) + i

Let's break this down. First, there's the weird n.bit_length(). This calculates the length in binary:

assert 4 == (0b1111).bit_length()
assert 8 == (0b1011_1000).bit_length()
assert 9 == (0b1_1011_1000).bit_length()

Unlike logarithms, this is both fast and precise for integers. As it turns out, this results in exactly floor(log2(n)) + 1. In order to get the floor(log2(n)) on its own, we subtract 1, hence the n.bit_length() - 1.

Next, we multiply by 0.30102999566398114. This is equivalent to log10(2) slightly rounded down. This takes advantage of logarithmic rules in order to calculate an estimate of floor(log10(n)) from floor(log2(n)).

Now, you might be wondering how off we might be at this point, because although 0.30102999566398114 * log2(n) ~ log10(n), the same is not true for floor(0.30102999566398114 * floor(log2(n))) ~ floor(log10(n)). Recall that x - 1 < floor(x) <= x so that we can do some quick math:

log2(n) - 1 < floor(log2(n)) <= log2(n)

log10(n) - 0.30102999566398114 < 0.30102999566398114 * floor(log2(n)) <= log10(n)

floor(log10(n) - 0.30102999566398114) < floor(0.30102999566398114 * floor(log2(n))) <= floor(log10(n))

Note then that floor(log10(n) - 0.30102999566398114) is at least floor(log10(n)) - 1, meaning we are at most 1 off from our result. This is where the final correction comes in, where we check 10 ** i <= n, which results in an extra 1 + when the result is too small or 0 + when the result is just right.

Similar to Jodag's answer, this approach actually fails for very very large n, somewhere around 10 ** 2 ** 52 where i is off by more than -1. However, integers of that size will likely crash your computer, so this should suffice.

Simply Beautiful Art
  • 1,284
  • 15
  • 16
1

My code for the same is as follows;i have used the log10 method:

from math import *

def digit_count(number):

if number>1 and round(log10(number))>=log10(number) and number%10!=0 :
    return round(log10(number))
elif  number>1 and round(log10(number))<log10(number) and number%10!=0:
    return round(log10(number))+1
elif number%10==0 and number!=0:
    return int(log10(number)+1)
elif number==1 or number==0:
    return 1

I had to specify in case of 1 and 0 because log10(1)=0 and log10(0)=ND and hence the condition mentioned isn't satisfied. However, this code works only for whole numbers.

1

Top answers are saying mathlog10 faster but I got results that suggest len(str(n)) is faster.

arr = []
for i in range(5000000):
    arr.append(random.randint(0,12345678901234567890))
%%timeit

for n in arr:
    len(str(n))
//2.72 s ± 304 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%%timeit

for n in arr:
    int(math.log10(n))+1
//3.13 s ± 545 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Besides, I haven't added logic to the math way to return accurate results and I can only imagine it slows it even more.

I have no idea how the previous answers proved the maths way is faster though.

1
n = 3566002020360505
count = 0
while(n>0):
  count += 1
  n = n //10
print(f"The number of digits in the number are: {count}")

output: The number of digits in the number are: 16

Khaled
  • 45
  • 7
1

If you are looking for a solution without using inbuilt functions. Only caveat is when you send a = 000.

def number_length(a: int) -> int:
    length = 0
    if a == 0:
        return length + 1
    else:
        while a > 0:
            a = a // 10
            length += 1
        return length
    

if __name__ == '__main__':
    print(number_length(123)
    assert number_length(10) == 2
    assert number_length(0) == 1
    assert number_length(256) == 3
    assert number_length(4444) == 4
san1512
  • 914
  • 1
  • 9
  • 16
1

Here is the simplest approach without need to be convert int into the string:

suppose a number of 15 digits is given eg; n=787878899999999;

n=787878899999999 
n=abs(n) // we are finding absolute value because if the number is negative int to string conversion will produce wrong output

count=0 //we have taken a counter variable which will increment itself till the last digit

while(n):
    n=n//10   /*Here we are removing the last digit of a number...it will remove until 0 digits will left...and we know that while(0) is False*/
    count+=1  /*this counter variable simply increase its value by 1 after deleting a digit from the original number
print(count)   /*when the while loop will become False because n=0, we will simply print the value of counter variable

Input :

n=787878899999999

Output:

15
0

If you have to ask an user to give input and then you have to count how many numbers are there then you can follow this:

count_number = input('Please enter a number\t')

print(len(count_number))

Note: Never take an int as user input.

Paul Roub
  • 36,322
  • 27
  • 84
  • 93
  • A rather specific case you describe here as it is actually related to the length of a string. Also, I could enter any non-numeric character and you would still believe it is a number. – Ben May 01 '20 at 18:01
0

Solution without imports and functions like str()

def numlen(num):
    result = 1
    divider = 10
    while num % divider != num:
        divider *= 10
        result += 1
    return result
0

You can use this solution:

n = input("Enter number: ")
print(len(n))
n = int(n)
elnaz nasiri
  • 155
  • 1
  • 4
-1
coin_digit = str(coin_fark).split(".")[1]
coin_digit_len = len(coin_digit)
print(coin_digit_len)
alpc
  • 598
  • 3
  • 6
  • This answer is for float values (because of the `.split(".")`) while the question is for integers. And it assumes the input number is already a string. Though the solution to get `len(digits)` is already answered [in the accepted answer](https://stackoverflow.com/a/2189814/2745495). – Gino Mempin May 24 '21 at 23:47
  • While this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value. – Buddy Bob May 25 '21 at 00:03
-12
>>> a=12345
>>> a.__str__().__len__()
5
ghostdog74
  • 327,991
  • 56
  • 259
  • 343
  • 8
    Do not directly call special methods. That is written `len(str(a))`. – Mike Graham Feb 03 '10 at 05:33
  • 1
    yes i know. what's the big problem? if its there, i can use it. – ghostdog74 Feb 03 '10 at 05:41
  • 12
    @ghostdog74 Just because there's an electrical socket, doesn't mean you have to stick your fingers in it. –  Feb 03 '10 at 05:48
  • 3
    so if you are so against it, why don't you tell me what's wrong with using it? – ghostdog74 Feb 03 '10 at 05:51
  • 12
    "Magic" __ methods are there for Python internals to call back into, not for your code to call directly. It's the Hollywood Framework pattern: don't call us, we'll call you. But the intent of this framework is that these are magic methods for the standard Python built-ins to make use of, so that your class can customize the behavior of the built-in. If it is a method for your code to call directly, give the method a non-"__" name. This clearly separates those methods that are intended for programmer consumption, vs. those that are provided for callback from Python built-ins. – PaulMcG Feb 03 '10 at 06:08
  • 1
    still, you don't say why its especially bad to use special methods. – ghostdog74 Feb 03 '10 at 06:28
  • 8
    It'sa bad idea because *everyone else in the known universe* uses str() and len(). This is being different for the sake of being different, which is inherently a bad thing--not to mention it's just ugly as hell. -1. – Glenn Maynard Feb 03 '10 at 07:04
  • 3
    that's so twisted. Just because majority of u uses str,len does not mean i have to follow. these methods are exposed to the programmer when the int object is instantiated, and i can jolly well use as i please. did GVR specifically sat we cannot use them? – ghostdog74 Feb 03 '10 at 07:24
  • Calling magic methods directly is not the recommended practice. Instead use len(), str() which in turn invokes the magic methods with some sanity checking. Please read this [answer](https://stackoverflow.com/a/2481631/7477462) for a few more details. – Premkumar chalmeti Nov 18 '19 at 18:03