Panjang bilangan bulat di Python

233

Dengan Python, bagaimana Anda menemukan jumlah digit dalam bilangan bulat?

Strigoides
sumber
1
Saya tidak mengerti pertanyaan Anda. Apakah maksud Anda ukuran bilangan bulat? Apakah Anda ingin menemukan jumlah digit? Mohon klarifikasi.
batbrat

Jawaban:

317

Jika Anda ingin panjang bilangan bulat seperti dalam jumlah digit dalam bilangan bulat, Anda selalu dapat mengonversinya menjadi string seperti str(133)dan menemukan panjangnya seperti len(str(123)).

GeekTantra
sumber
18
Tentu saja, jika Anda mencari jumlah digit, ini akan menghasilkan hasil yang terlalu besar untuk angka negatif, karena akan menghitung tanda negatif.
Chris Upchurch
37
Hei, ini solusi lambat. Saya melakukan faktorial dari angka 6 digit acak, dan menemukan panjangnya. Metode ini memakan waktu 95.891 detik. Dan Math.log10metode hanya butuh 7,486343383789062e-05 detik, sekitar 1501388 kali lebih cepat!
FadedCoder
1
Ini bukan hanya lambat, tetapi menghabiskan banyak memori dan dapat menyebabkan masalah dalam jumlah besar. gunakan Math.log10saja.
Peyman
246

Tanpa konversi ke string

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

Untuk juga menangani angka nol dan negatif

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

Anda mungkin ingin menempatkan itu dalam suatu fungsi :)

Inilah beberapa tolok ukur. The len(str())sudah di belakang bahkan jumlahnya cukup kecil

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
sumber
5
Menggunakan log10 untuk ini adalah solusi ahli matematika; menggunakan len (str ()) adalah solusi programmer, dan lebih jelas dan sederhana.
Glenn Maynard
68
@ Glenn: Saya tentu berharap Anda tidak menyiratkan ini adalah solusi yang buruk. Solusi naif O (log10 n) programmer berfungsi baik dalam ad-hoc, kode prototyping - tetapi saya lebih suka melihat matematikawan solusi O (1) yang elegan dalam kode produksi atau API publik. +1 untuk gnibbler.
Juliet
5
@gnibbler: +1. Tidak pernah menyadari bahwa log10 dapat digunakan untuk menemukan besarnya angka. Seandainya saya bisa up-vote lebih dari sekali :).
Abbas
14
Hai! Saya melakukan sesuatu yang aneh, bisakah Siapa pun dari Anda tolong jelaskan saya mengapa int(math.log10(x)) +1untuk 99999999999999999999999999999999999999999999999999999999999999999999999( 71 sembilan ) mengembalikan 72 ? Saya berpikir bahwa saya bisa mengandalkan metode log10 tetapi saya harus menggunakan len (str (x)) sebagai gantinya :(
Marecky
6
Saya percaya saya tahu alasan perilaku aneh, itu karena ketidaktepatan floating point misalnya. math.log10(999999999999999)sama dengan 14.999999999999998begitu int(math.log10(999999999999999))menjadi 14. Tapi kemudian math.log10(9999999999999999)sama dengan 16.0. Mungkin menggunakan roundadalah solusi untuk masalah ini.
jamylak
43

Semua solusi math.log10 akan memberi Anda masalah.

math.log10 cepat tetapi memberikan masalah ketika nomor Anda lebih besar dari 999999999999997. Ini karena float memiliki terlalu banyak .9s, menyebabkan hasilnya membulatkan.

Solusinya adalah menggunakan metode penghitung sementara untuk angka di atas ambang batas itu.

Untuk menjadikan ini lebih cepat, buat 10 ^ 16, 10 ^ 17 seterusnya dan simpan sebagai variabel dalam daftar. Dengan begitu, itu seperti pencarian tabel.

def getIntegerPlaces(theNumber):
    if theNumber <= 999999999999997:
        return int(math.log10(theNumber)) + 1
    else:
        counter = 15
        while theNumber >= 10**counter:
            counter += 1
        return counter
Calvintwr
sumber
Terima kasih. Itu adalah contoh yang bagus untuk math.log10. Sangat menarik untuk melihat bagaimana representasi biner membalik nilai yang memberikan hasil yang secara matematis salah.
WloHu
maka len (str (num)) akan lebih baik
Vighnesh Raut
2
@ Vighnesh Raut: Dan magnitude lebih lambat
Chaitanya Bangera
"Berbahaya jika mengandalkan operasi floating-point yang memberikan hasil yang pasti" - Mark Dickinson, anggota tim pengembangan inti Python bugs.python.org/issue3724
Sreeragh AR
26

Python 2.* ints mengambil 4 atau 8 byte (32 atau 64 bit), tergantung pada build Python Anda. sys.maxint( 2**31-1untuk int 32-bit, 2**63-1untuk int 64-bit) akan memberi tahu Anda yang mana dari dua kemungkinan yang diperoleh.

Dalam Python 3, ints (seperti longs dalam Python 2) dapat mengambil ukuran sewenang-wenang hingga jumlah memori yang tersedia; sys.getsizeofmemberikan indikasi yang baik untuk setiap nilai yang diberikan, meskipun tidak juga menghitung beberapa overhead tetap:

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

Jika, seperti jawaban lain menyarankan, Anda berpikir tentang beberapa representasi string dari nilai integer, maka ambil lensaja representasi itu, baik itu di basis 10 atau sebaliknya!

Alex Martelli
sumber
Maaf jawaban ini dikurangi. Ini informatif dan pada titik masuk akal dari pertanyaan (jika hanya lebih spesifik tentang 'len' yang diinginkan). +1
mjv
Ini terlihat menarik tetapi tidak yakin bagaimana mengekstraksi panjangnya
Tjorriemorrie
17

Sudah beberapa tahun sejak pertanyaan ini diajukan, tetapi saya telah menyusun tolok ukur beberapa metode untuk menghitung panjang bilangan bulat.

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

(fungsi libc memerlukan beberapa pengaturan, yang belum saya sertakan)

size_expterima kasih kepada Brian Preslopsky, size_strterima kasih kepada GeekTantra, dan size_mathterima kasih kepada John La Rooy

Inilah hasilnya:

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)

(Penafian: fungsi dijalankan pada input 1 hingga 1.000.000)

Berikut adalah hasil untuk sys.maxsize - 100000ke 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)

Seperti yang Anda lihat, mod_size( len("%i" % i)) adalah yang tercepat, sedikit lebih cepat daripada menggunakan str(i)dan secara signifikan lebih cepat daripada yang lain.

Tidak Ada Di Sini
sumber
Anda benar-benar harus memasukkan pengaturan libc, libc = ctyle.CDLL('libc.so.6', use_errno=True)(menebak ini dia). Dan itu tidak berfungsi untuk angka yang lebih besar daripada sys.maxsizekarena angka floating point tidak bisa "sangat besar". Jadi angka apa pun di atas itu, saya kira Anda terjebak dengan salah satu metode yang lebih lambat.
Torxed
15

Biarkan angkanya nmaka jumlah digit ndiberikan oleh:

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

Perhatikan bahwa ini akan memberikan jawaban yang benar untuk + ve integer <10e15. Di luar batas ketepatan jenis pengembalian math.log10tendangan masuk dan jawabannya mungkin tidak aktif oleh 1. Saya hanya akan menggunakan di len(str(n))luar itu; ini membutuhkan O(log(n))waktu yang sama dengan iterasi dari kekuatan 10.

Terima kasih kepada @SetiVolkylany karena telah membawa perhatian saya ke batasan ini. Sungguh menakjubkan betapa solusi yang tampaknya benar memiliki peringatan dalam detail implementasi.

BiGYaN
sumber
1
Tidak berfungsi jika n di luar kisaran [-999999999999997, 999999999999997]
PADYMKO
@SetiVolkylany, saya mengujinya hingga 50 digit untuk python2.7 dan 3.5. Lakukan saja assert list(range(1,51)) == [math.floor(math.log10(n))+1 for n in (10**e for e in range(50))].
BiGYaN
2
coba dengan Python2.7 atau Python3.5 >>> math.floor(math.log10(999999999999997))+1 15.0 >>> math.floor(math.log10(999999999999998))+1 16.0. Lihat jawaban saya stackoverflow.com/a/42736085/6003870 .
PADYMKO
12

Nah, tanpa mengkonversi ke string saya akan melakukan sesuatu seperti:

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

    x = abs(x)

    if x < 10:
        return 1

    return 1 + lenDigits(x / 10)

Rekursi Minimalis FTW

odradek
sumber
1
Anda akan mencapai batas rekursi untuk jumlah besar.
nog642
9

Hitung jumlah digit tanpa konversi bilangan bulat ke string:

x=123
x=abs(x)
i = 0
while x >= 10**i:
    i +=1
# i is the number of digits
datanew
sumber
Bagus sekali menghindari konversi string sepenuhnya.
Patrick Mutuku
8

Seperti disebutkan pengguna yang terhormat @Calvintwr, fungsi tersebut math.log10memiliki masalah di sejumlah di luar rentang [-999999999999997, 999999999999997], di mana kita mendapatkan kesalahan titik apung. Saya punya masalah dengan JavaScript (Google V8 dan NodeJS) dan C (kompiler GNU GCC), jadi 'purely mathematically'solusinya tidak mungkin di sini.


Berdasarkan intisari ini dan jawabannya adalah pengguna terkasih @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

Saya mengujinya pada angka dengan panjang hingga 20 (inklusif) dan baik-baik saja. Itu harus cukup, karena angka integer panjang maks pada sistem 64-bit adalah 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

Semua contoh kode diuji dengan Python 3.5

PADYMKO
sumber
3

Untuk anak cucu, tidak diragukan lagi sejauh ini solusi paling lambat untuk masalah ini:

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
sumber
2
from math import log10
digits = lambda n: ((n==0) and 1) or int(log10(abs(n)))+1
Robert William Hanks
sumber
1

Dengan asumsi Anda meminta angka terbesar yang dapat Anda simpan dalam bilangan bulat, nilainya tergantung pada implementasi. Saya menyarankan agar Anda tidak berpikir seperti itu ketika menggunakan python. Bagaimanapun, nilai yang cukup besar dapat disimpan dalam 'integer' python. Ingat, Python menggunakan mengetik bebek!

Sunting: Saya memberi jawaban saya sebelum klarifikasi bahwa penanya menginginkan jumlah digit. Untuk itu, saya setuju dengan metode yang disarankan oleh jawaban yang diterima. Tidak ada lagi yang ditambahkan!

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

sumber
1

Ini dapat dilakukan untuk bilangan bulat dengan cepat dengan menggunakan:

len(str(abs(1234567890)))

Yang mendapatkan panjang string dari nilai absolut "1234567890"

absmengembalikan nomor TANPA negatif (hanya besarnya angka), strmelemparkan / mengubahnya menjadi string dan lenmengembalikan panjang string dari string itu.

Jika Anda ingin itu berfungsi untuk float, Anda dapat menggunakan salah satu dari berikut ini:

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

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

Untuk referensi di masa mendatang.

Kotak Frog
sumber
Saya pikir akan lebih mudah untuk memotong nomor input itu sendiri (misalnya dengan gips ke int) daripada memotong representasi string desimalnya: len(str(abs(int(0.1234567890))))mengembalikan 1.
David Foerster
Tidak, itu tidak akan berhasil. Jika Anda mengubah 0,17 menjadi bilangan bulat, Anda mendapatkan 0 dan panjangnya akan berbeda dengan panjang 0,17
Frogboxe
Dalam kasus pertama, dengan memotong segala sesuatu dari dan termasuk titik desimal dari representasi string, Anda secara efektif menghitung panjang bagian integral dari angka, yang juga merupakan saran saya. Untuk 0,17 kedua solusi kembali 1.
David Foerster
0

Format dalam notasi ilmiah dan cabut eksponen:

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

Saya tidak tahu tentang kecepatan, tapi itu sederhana.

Harap perhatikan jumlah digit signifikan setelah desimal ("5" di ".5e" dapat menjadi masalah jika itu membulatkan bagian desimal dari notasi ilmiah ke angka lain. Saya menetapkannya secara besar-besaran, tetapi dapat mencerminkan panjang angka terbesar yang Anda ketahui.

Brian Preslopsky
sumber
0
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
sumber
Sementara kode ini dapat menyelesaikan pertanyaan, termasuk penjelasan tentang bagaimana dan mengapa ini menyelesaikan masalah akan sangat membantu untuk meningkatkan kualitas posting Anda, dan mungkin menghasilkan lebih banyak suara. Ingatlah bahwa Anda menjawab pertanyaan untuk pembaca di masa depan, bukan hanya orang yang bertanya sekarang. Harap edit jawaban Anda untuk menambahkan penjelasan dan berikan indikasi tentang batasan dan asumsi apa yang berlaku.
Adrian Mole
0

Jika Anda harus meminta pengguna untuk memberi masukan dan kemudian Anda harus menghitung berapa banyak angka yang ada di sana maka Anda dapat mengikuti ini:

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

print(len(count_number))

Catatan: Jangan pernah menggunakan int sebagai input pengguna.

Sagar Biswas
sumber
Kasus yang agak spesifik yang Anda jelaskan di sini karena sebenarnya terkait dengan panjang string. Juga, saya bisa memasukkan karakter non-numerik dan Anda masih percaya itu adalah angka.
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
Jahedul Anowar
sumber
0

Kode saya untuk hal yang sama adalah sebagai berikut; saya telah menggunakan metode log10:

from math import *

def digit_count (angka):

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

Saya harus menentukan dalam kasus 1 dan 0 karena log10 (1) = 0 dan log10 (0) = ND dan karenanya kondisi yang disebutkan tidak terpenuhi. Namun, kode ini hanya berfungsi untuk bilangan bulat.

Devvrat Chaubal
sumber
0

Berikut ini versi besar tapi cepat:

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

Hanya 5 perbandingan untuk angka yang tidak terlalu besar. Di komputer saya sekitar 30% lebih cepat dari math.log10versi dan 5% lebih cepat dari versi len( str()). Ok ... tidak begitu menarik jika Anda tidak menggunakannya dengan marah.

Dan ini adalah himpunan angka yang saya gunakan untuk menguji / mengukur fungsi saya:

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

NB: tidak mengelola angka negatif, tetapi adaptasinya mudah ...

Kapten'Flam
sumber
-13
>>> a=12345
>>> a.__str__().__len__()
5
ghostdog74
sumber
6
Jangan langsung memanggil metode khusus. Itu tertulis len(str(a)).
Mike Graham
8
@ ghostdog74 Hanya karena ada soket listrik, tidak berarti Anda harus memasukkan jari Anda ke dalamnya.
3
jadi jika Anda menentangnya, mengapa Anda tidak memberi tahu saya apa yang salah dengan menggunakannya?
ghostdog74
11
"Magic" metode __ ada untuk internal Python untuk memanggil kembali, bukan untuk kode Anda untuk memanggil secara langsung. Ini adalah pola Kerangka Hollywood: jangan panggil kami, kami akan menghubungi Anda. Tetapi maksud dari kerangka kerja ini adalah bahwa ini adalah metode ajaib untuk menggunakan standar Python built-in, sehingga kelas Anda dapat menyesuaikan perilaku built-in. Jika ini adalah metode untuk memanggil kode Anda secara langsung, berikan metode itu bukan nama "__". Ini jelas memisahkan metode-metode yang dimaksudkan untuk konsumsi programmer, vs yang disediakan untuk panggilan balik dari Python built-in.
PaulMcG
7
Itu ide yang buruk karena semua orang di alam semesta yang dikenal menggunakan str () dan len (). Ini menjadi berbeda demi menjadi berbeda, yang pada dasarnya adalah hal yang buruk - belum lagi itu hanya jelek sekali. -1.
Glenn Maynard