Masalah Anda tidak ditentukan, Anda harus mundur dan mengajukan beberapa pertanyaan.
- Apa jenis input Anda?
- Jenis apa yang Anda inginkan untuk output Anda?
- Untuk hasil yang kurang dari 1, apa yang ingin Anda lakukan? Apakah Anda ingin kekuatan aktual 10 atau aproksimasi kekuatan 10 poin mengambang? Anda sadar bahwa kekuatan negatif 10 tidak dapat diekspresikan dengan tepat di floating point, bukan? Mari kita asumsikan untuk sekarang bahwa Anda ingin perkiraan floating point dari kekuatan 10.
- Jika inputnya tepat dengan daya 10 (atau perkiraan titik mengambang terdekat dengan daya 10), haruskah outputnya sama dengan inputnya? Atau haruskah itu kekuatan 10 up berikutnya? "10 -> 10" atau "10 -> 100"? Mari kita asumsikan yang pertama untuk saat ini.
- Bisakah nilai input Anda menjadi nilai yang mungkin dari jenis yang dimaksud? atau mereka lebih dibatasi.
Di jawaban lain diusulkan untuk mengambil logaritma, kemudian mengumpulkan (fungsi langit-langit), kemudian eksponensial.
def nextpow10(n):
return 10 ** math.ceil(math.log10(n))
Sayangnya ini mengalami kesalahan pembulatan. Pertama-tama n dikonversi dari tipe data apa pun yang kebetulan terjadi menjadi angka floating point presisi ganda, yang berpotensi menimbulkan kesalahan pembulatan, kemudian logaritma dihitung berpotensi menimbulkan lebih banyak kesalahan pembulatan baik dalam perhitungan internal maupun dalam hasilnya.
Karena itu tidak butuh waktu lama bagi saya untuk menemukan contoh yang memberikan hasil yang salah.
>>> import math
>>> from numpy import nextafter
>>> n = 1
>>> while (10 ** math.ceil(math.log10(nextafter(n,math.inf)))) > n:
... n *= 10
...
>>> n
10
>>> nextafter(n,math.inf)
10.000000000000002
>>> 10 ** math.ceil(math.log10(10.000000000000002))
10
Secara teori juga mungkin untuk gagal ke arah lain, meskipun ini tampaknya jauh lebih sulit untuk diprovokasi.
Jadi untuk solusi yang kuat untuk float dan int kita perlu mengasumsikan bahwa nilai logaritma kita hanya perkiraan, dan karena itu kita harus menguji beberapa kemungkinan. Sesuatu di sepanjang garis
def nextpow10(n):
p = round(math.log10(n))
r = 10 ** p
if r < n:
r = 10 ** (p+1)
return r;
Saya percaya kode ini harus memberikan hasil yang benar untuk semua argumen dalam jangkauan dunia nyata yang masuk akal. Ini akan pecah untuk jumlah yang sangat kecil atau sangat besar dari tipe non integer dan non-floating point karena masalah mengubahnya menjadi floating point. Argumen integer kasus khusus Python untuk fungsi log10 dalam upaya untuk mencegah overflow, tetapi masih dengan integer yang cukup besar mungkin dapat memaksa hasil yang salah karena kesalahan pembulatan.
Untuk menguji dua implementasi saya menggunakan program tes berikut.
n = -323 # 10**-324 == 0
while n < 1000:
v = 10 ** n
if v != nextpow10(v): print(str(v)+" bad")
try:
v = min(nextafter(v,math.inf),v+1)
except:
v += 1
if v > nextpow10(v): print(str(v)+" bad")
n += 1
Ini menemukan banyak kegagalan dalam implementasi yang naif, tetapi tidak ada dalam implementasi yang ditingkatkan.
10
atas, ini akan membutuhkan sesuatu dengan misalnyalog10
.