Dengan Python, bagaimana Anda menemukan jumlah digit dalam bilangan bulat?
Dengan Python, bagaimana Anda menemukan jumlah digit dalam bilangan bulat?
Jawaban:
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))
.
Math.log10
metode hanya butuh 7,486343383789062e-05 detik, sekitar 1501388 kali lebih cepat!
Math.log10
saja.
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
int(math.log10(x)) +1
untuk 99999999999999999999999999999999999999999999999999999999999999999999999
( 71 sembilan ) mengembalikan 72 ? Saya berpikir bahwa saya bisa mengandalkan metode log10 tetapi saya harus menggunakan len (str (x)) sebagai gantinya :(
math.log10(999999999999999)
sama dengan 14.999999999999998
begitu int(math.log10(999999999999999))
menjadi 14
. Tapi kemudian math.log10(9999999999999999)
sama dengan 16.0
. Mungkin menggunakan round
adalah solusi untuk masalah ini.
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
math.log10
. Sangat menarik untuk melihat bagaimana representasi biner membalik nilai yang memberikan hasil yang secara matematis salah.
Python 2.*
int
s mengambil 4 atau 8 byte (32 atau 64 bit), tergantung pada build Python Anda. sys.maxint
( 2**31-1
untuk int 32-bit, 2**63-1
untuk int 64-bit) akan memberi tahu Anda yang mana dari dua kemungkinan yang diperoleh.
Dalam Python 3, int
s (seperti long
s dalam Python 2) dapat mengambil ukuran sewenang-wenang hingga jumlah memori yang tersedia; sys.getsizeof
memberikan 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 len
saja representasi itu, baik itu di basis 10 atau sebaliknya!
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_exp
terima kasih kepada Brian Preslopsky, size_str
terima kasih kepada GeekTantra, dan size_math
terima 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 - 100000
ke 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.
libc = ctyle.CDLL('libc.so.6', use_errno=True)
(menebak ini dia). Dan itu tidak berfungsi untuk angka yang lebih besar daripada sys.maxsize
karena 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.
Biarkan angkanya n
maka jumlah digit n
diberikan 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.log10
tendangan 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.
assert list(range(1,51)) == [math.floor(math.log10(n))+1 for n in (10**e for e in range(50))]
.
>>> math.floor(math.log10(999999999999997))+1 15.0 >>> math.floor(math.log10(999999999999998))+1 16.0
. Lihat jawaban saya stackoverflow.com/a/42736085/6003870 .
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
Seperti disebutkan pengguna yang terhormat @Calvintwr, fungsi tersebut math.log10
memiliki 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
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)
from math import log10
digits = lambda n: ((n==0) and 1) or int(log10(abs(n)))+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!
def length(i):
return len(str(i))
Ini dapat dilakukan untuk bilangan bulat dengan cepat dengan menggunakan:
len(str(abs(1234567890)))
Yang mendapatkan panjang string dari nilai absolut "1234567890"
abs
mengembalikan nomor TANPA negatif (hanya besarnya angka), str
melemparkan / mengubahnya menjadi string dan len
mengembalikan 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.
int
) daripada memotong representasi string desimalnya: len(str(abs(int(0.1234567890))))
mengembalikan 1.
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.
def count_digit(number):
if number >= 10:
count = 2
else:
count = 1
while number//10 > 9:
count += 1
number = number//10
return count
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.
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
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.
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.log10
versi 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 ...
>>> a=12345
>>> a.__str__().__len__()
5
len(str(a))
.