Python'da bir tamsayı uzunluğu


233

Python'da, bir tamsayıdaki basamak sayısını nasıl bulursunuz?


1
Sorunu anlamıyorum. Bir tamsayı boyutu mu demek istediniz? Basamak sayısını bulmak istiyor musunuz? Lütfen açıkla.
batbrat

Yanıtlar:


317

Bir tamsayı uzunluğunun tamsayıdaki hane sayısında olduğu gibi olmasını istiyorsanız, onu her zaman dizeye dönüştürebilir str(133)ve uzunluğunu bulabilirsiniz len(str(123)).


18
Tabii ki, basamak sayısını arıyorsanız, bu negatif sayıyı sayacağından negatif sayılar için çok büyük bir sonuç üretecektir.
Chris Upchurch

37
Hey, bu yavaş bir çözüm. Rastgele 6 haneli bir sayı faktöriyeli yaptım ve uzunluğunu buldum. Bu yöntem 95.891 saniye sürdü . Ve Math.log10yöntem sadece 7.486343383789062e-05 saniye sürdü , yaklaşık 1501388 kat daha hızlı!
FadedCoder

1
Bu sadece yavaş değil, aynı zamanda daha fazla bellek tüketir ve çok sayıda soruna neden olabilir. kullanın Math.log10.
Peyman

246

Dizeye dönüşüm olmadan

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

Sıfır ve negatif sayıları da ele almak için

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 '-' 

Muhtemelen bir fonksiyona koymak istersiniz :)

İşte bazı kriterler. len(str())Hatta oldukça küçük sayılar için geride zaten

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

5
Bunun için log10 kullanmak bir matematikçinin çözümüdür; len (str ()) kullanmak bir programcının çözümüdür ve daha açık ve basittir.
Glenn Maynard

68
@Glenn: Umarım bunun kötü bir çözüm olduğunu ima etmiyorsunuzdur. Programcının naif O (log10 n) çözümü, ad-hoc, prototip kodunda iyi çalışır - ancak matematikçilerin üretim kodunda veya ortak bir API'da zarif O (1) çözümünü görmeyi tercih ederim. Gnibbler için +1.
Juliet

5
@gnibbler: +1. Log10'un bir sayının büyüklüğünü bulmak için kullanılabileceğini hiç fark etmedim. Keşke bir kereden fazla oy verebilseydim :).
Abbas

14
Selam! Ben garip bir şey, neden bana açıklayınız You can herkes gitmek int(math.log10(x)) +1için 99999999999999999999999999999999999999999999999999999999999999999999999( 71 dokuzlu döndürür) 72 ? Log10 yöntemine güvenebileceğimi düşündüm ama bunun yerine len (str (x)) kullanmalıyım :(
Marecky

6
Garip davranışın nedenini bildiğime inanıyorum, bunun nedeni kayan nokta yanlışlıklarından kaynaklanıyor. math.log10(999999999999999)eşittir 14.999999999999998çok int(math.log10(999999999999999))olur 14. Ama sonra math.log10(9999999999999999)eşittir 16.0. Belki de kullanmak roundbu soruna bir çözümdür.
jamylak

43

Tüm math.log10 çözümleri size problemler verecektir.

math.log10 hızlıdır ancak sayınız 999999999999997'den büyük olduğunda sorun çıkarır. Bunun nedeni, kayan noktanın çok fazla .9 olması ve sonucun yuvarlanmasına neden olmasıdır.

Çözüm, bu eşiğin üzerindeki sayılar için while sayacı yöntemi kullanmaktır.

Bunu daha da hızlı yapmak için, 10 ^ 16, 10 ^ 17 vb. Oluşturun ve bir listede değişken olarak saklayın. Bu şekilde, tablo araması gibidir.

def getIntegerPlaces(theNumber):
    if theNumber <= 999999999999997:
        return int(math.log10(theNumber)) + 1
    else:
        counter = 15
        while theNumber >= 10**counter:
            counter += 1
        return counter

Teşekkür ederim. Bu iyi bir karşı örnek math.log10. İkili gösterimin değerleri matematiksel olarak yanlış sonuç vererek nasıl çevirdiğini görmek ilginçtir.
WloHu

o zaman len (str (num)) daha iyi olurdu
Vighnesh Raut

2
@Vighnesh Raut: Ve büyüklükleri daha yavaş
Chaitanya Bangera

"Kesin sonuçlar veren kayan nokta operasyonlarına güvenmek tehlikelidir" - Temel Python geliştirme ekibinin üyesi olan Mark Dickinson bugs.python.org/issue3724
Sreeragh AR

26

Python'lar 2.* int, Python derlemenize bağlı olarak 4 veya 8 bayt (32 veya 64 bit) alır. sys.maxint( 2**31-132 bit girişler 2**63-1için, 64 bit girişler için) size iki olasılıktan hangisinin elde edildiğini söyleyecektir.

Python 3'te, ints ( longPython 2'deki s gibi ) kullanılabilir bellek miktarına kadar keyfi boyutlar alabilir; sys.getsizeofo halde, size herhangi bir değeri için iyi bir gösterge verir vermez de bazı sabit yükü saymak:

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

Diğer yanıtların da belirttiği gibi, tamsayı değerinin dize temsilini düşünürseniz, leno temsili 10 ya da başka şekilde temsil edin!


Üzgünüm bu cevap eksi oldu. Bilgilendirici ve sorunun makul noktasına (hangi 'len' nin istendiği hakkında daha spesifik olsaydı). +1
mjv

Bu ilginç görünüyor ama uzunluğu ayıklamak nasıl emin değilim
Tjorriemorrie

17

Bu sorunun sorulmasından bu yana birkaç yıl geçti, ancak bir tamsayının uzunluğunu hesaplamak için çeşitli yöntemlerin bir ölçütünü derledim.

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

(libc işlevi dahil etmediğim bazı kurulumlar gerektirir)

size_expBrian Preslopsky size_strsayesinde, GeekTantra size_mathsayesinde ve John La Rooy sayesinde

Sonuçlar burada:

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)

(Sorumluluk reddi: fonksiyon 1 ila 1.000.000 girişlerde çalıştırılır)

İşte için sonuçları sys.maxsize - 100000için 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)

Gördüğünüz gibi, mod_size( len("%i" % i)) en hızlı, kullanmaktan biraz daha hızlı str(i)ve diğerlerinden daha hızlı.


Gerçekten libc kurulumunu eklemelisiniz libc = ctyle.CDLL('libc.so.6', use_errno=True)(tahmin etmek budur). Ve daha büyük sayılar için çalışmıyor sys.maxsizekayan nokta sayıları "çok büyük" olamaz çünkü. Bunun üzerinde herhangi bir sayı, sanırım daha yavaş yöntemlerden biri ile sıkışmış.
19:39 tarihinde Torxed

15

Sayısı olsun nbasamak daha sonra sayı nile elde edilir:

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

Bunun + ve tamsayılar <10e15 için doğru cevaplar vereceğini unutmayın. Bunun ötesinde dönüş tipinin hassas limitleri math.log10devreye girer ve cevap 1'de olabilir. Sadece bunun len(str(n))ötesinde kullanırdım; bu gerektirirO(log(n)) 10'lu güçlerin tekrarlanmasıyla aynı zaman .

@SetiVolkylany'a bu kısıtlamaya katıldığım için teşekkürler. Görünüşte doğru çözümlerin uygulama detaylarında dikkat edilmesi şaşırtıcı.


1
Aralık dışında n olursa çalışmaz [-999999999999997, 999999999999997]
PADYMKO 11:17

@SetiVolkylany, python2.7 ve 3.5 için 50 basamağa kadar test ettim. Sadece yap assert list(range(1,51)) == [math.floor(math.log10(n))+1 for n in (10**e for e in range(50))].
BiGYaN

2
Python2.7 veya Python3.5 ile deneyin >>> math.floor(math.log10(999999999999997))+1 15.0 >>> math.floor(math.log10(999999999999998))+1 16.0. Cevabım bak stackoverflow.com/a/42736085/6003870 .
PADYMKO

12

Peki, dizeye dönüştürmeden şöyle bir şey yaparım:

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

    x = abs(x)

    if x < 10:
        return 1

    return 1 + lenDigits(x / 10)

Minimalist özyineleme FTW


1
Büyük sayılar için özyineleme sınırına ulaşacaksınız.
nog642

9

Tamsayıyı bir dizeye dönüştürmeden basamak sayısını sayın:

x=123
x=abs(x)
i = 0
while x >= 10**i:
    i +=1
# i is the number of digits

Güzel bir dize dönüştürme tamamen önler.
Patrick Mutuku

8

Sevgili kullanıcı @ Calvintwr'den bahsedildiği gibi, fonksiyonun math.log10kayan nokta hataları aldığımız bir aralığın [-999999999999997, 999999999999997] dışında bir sayıda problemi vardır. JavaScript (Google V8 ve NodeJS) ve C (GNU GCC derleyicisi) ile bu sorunu yaşadım, bu yüzden 'purely mathematically'burada bir çözüm imkansız.


Bu özü ve cevabı esas alan sevgili @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

Uzunluğu 20 (dahil) ve tamam olan sayılar üzerinde test ettim. Bu yeterli olmalı, çünkü 64 bit sistemdeki uzunluk maksimum tamsayı sayısı 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

Python 3.5 ile test edilen tüm kod örnekleri


3

Gelecek nesiller için şüphesiz bu soruna en yavaş çözüm:

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)


1

Bir tamsayıda saklayabileceğiniz en büyük sayıyı istediğinizi varsayarsak, değer uygulamaya bağlıdır. Python kullanırken böyle düşünmemenizi öneririm. Her durumda, bir python 'tamsayı' içinde oldukça büyük bir değer saklanabilir. Unutma, Python ördek yazmayı kullanıyor!

Edit: Ben cevap rakam asker sayısını istedi açıklama önce verdim. Bunun için kabul edilen cevabın önerdiği yönteme katılıyorum. Eklenecek başka bir şey yok!


1
def length(i):
  return len(str(i))

1

Tamsayılar için aşağıdakiler kullanılarak hızlı bir şekilde yapılabilir:

len(str(abs(1234567890)))

Hangi "1234567890" mutlak değerinin dizesinin uzunluğunu alır

absnegatif olmayan sayıyı (yalnızca sayının büyüklüğünü) döndürür, strbir dizgeye çevirir / dönüştürür velen döndürür, bu dizenin dize uzunluğunu döndürür.

Şamandıralar için çalışmasını istiyorsanız, aşağıdakilerden birini kullanabilirsiniz:

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

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

İleride başvurmak için.


Ben intondalık dize temsilini kısaltmak için giriş numarasını kendisi (örneğin bir döküm ile ) kısaltmak için daha basit olacağını düşünüyorum : 1 len(str(abs(int(0.1234567890))))döner.
David Foerster

Hayır, bu işe yaramaz. 0.17 değerini bir tamsayıya çevirirseniz 0 elde edersiniz ve bunun uzunluğu 0.17'nin uzunluğundan farklı olur
Frogboxe

İlk durumda, dize temsilinden ondalık noktadan her şeyi kısaltarak ve dahil ederek sayının integral bölümünün uzunluğunu etkili bir şekilde hesaplarsınız , bu da benim önerim de yapar. 0.17 için her iki çözüm de 1'e döner.
David Foerster

0

Bilimsel gösterimde biçimlendirin ve üssü koparın:

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

Hızı bilmiyorum, ama bu basit.

Lütfen ondalık basamaktan sonraki önemli basamakların sayısına dikkat edin (".5e" deki "5", bilimsel gösterimin ondalık kısmını başka bir rakama yuvarlarsa bir sorun olabilir. bildiğiniz en büyük sayının uzunluğu.


0
def count_digit(number):
  if number >= 10:
    count = 2
  else:
    count = 1
  while number//10 > 9:
    count += 1
    number = number//10
  return count

Bu kod, sorunun nasıl ve neden çözüldüğüne dair bir açıklama da dahil olmak üzere soruyu çözebilir, ancak gönderinizin kalitesini artırmaya yardımcı olabilir ve muhtemelen daha fazla oyla sonuçlanır. Sadece şimdi soran kişi için değil, gelecekte okuyucular için soruyu cevapladığınızı unutmayın. Lütfen açıklama eklemek için yanıtınızı düzenleyin ve hangi sınırlamaların ve varsayımların geçerli olduğunu belirtin.
Adrian Mole

0

Bir kullanıcıdan giriş vermesini istemeniz gerekiyorsa ve orada kaç sayı olduğunu saymanız gerekiyorsa, bunu takip edebilirsiniz:

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

print(len(count_number))

Not: Kullanıcı girişi olarak asla int kullanmayın.


Burada tanımladığınız oldukça özel bir durum, aslında bir dizenin uzunluğu ile ilgilidir. Ayrıca, sayısal olmayan herhangi bir karakter girebilirim ve yine de bir sayı olduğuna inanırsınız.
Ben

0
def digits(n)
    count = 0
    if n == 0:
        return 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

0

Aynı benim kod aşağıdaki gibidir; ben log10 yöntemini kullandık:

from math import *

def digit_count (sayı):

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

Log10 (1) = 0 ve log10 (0) = ND olduğu için 1 ve 0 durumunda belirtmek zorunda kaldım ve dolayısıyla belirtilen koşul karşılanmadı. Ancak, bu kod yalnızca tam sayılar için çalışır.


0

İşte hantal ama hızlı bir sürüm:

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

Çok büyük sayılar için sadece 5 karşılaştırma. Bilgisayarımda math.log10sürümden yaklaşık% 30 daha hızlı ve sürümden% 5 daha hızlılen( str()) . Tamam ... öfkeyle kullanmazsan çok çekici olmaz.

İşte fonksiyonumu test etmek / ölçmek için kullandığım sayılar kümesi:

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

Not: negatif sayıları yönetmez, ancak adaptasyon kolaydır ...


-13
>>> a=12345
>>> a.__str__().__len__()
5

6
Doğrudan özel yöntemleri aramayın. Bu yazılı len(str(a)).
Mike Graham

8
@ ghostdog74 Elektrik prizi olduğu için, parmaklarınızı sokmanız gerektiği anlamına gelmez.

3
öyleyse buna karşıysanız, neden kullanmanın neyin yanlış olduğunu söylemiyorsunuz?
ghostdog74

11
"Magic" __ yöntemleri, kodunuzun doğrudan arayacağı Python içlerinin geri arayacağı yöntemlerdir. Bu Hollywood Framework modeli: bizi arama, seni arayacağız. Ancak bu çerçevenin amacı, standart Python yerleşiklerinin kullanması için sihirli yöntemler olmasıdır, böylece sınıfınız yerleşik davranışı özelleştirebilir. Kodunuzun doğrudan çağrılması için bir yöntemse, yönteme "__" olmayan bir ad verin. Bu, programcı tüketimi için tasarlanan yöntemleri ve geri arama için sağlanan yöntemleri Python yerleşiklerinden açıkça ayırır.
PaulMcG

7
Bu kötü bir fikir çünkü bilinen evrendeki herkes str () ve len () kullanıyor. Bu farklı olmak uğruna farklı olmaktır, bu da doğal olarak kötü bir şeydir - cehennem kadar çirkin olduğunu söylememek. -1.
Glenn Maynard
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.