Ваша проблема недостатньо вказана, вам потрібно відступити і задати деякі питання.
- Які види (типи) є вашими вхідними даними?
- Якого типу (-ів) ви хочете для своїх результатів?
- Для результатів менше 1, до чого саме ви хочете округлити? Ви хочете, щоб фактичні потужності 10 або наближення потужностей 10 з плаваючою комою? Ви знаєте, що негативні сили 10 не можуть бути виражені точно в плаваючій точці? Припустимо наразі, що ви хочете наближення з плаваючою точкою потужностей 10.
- Якщо вхід є саме потужністю 10 (або найближчим наближенням плаваючої точки до потужності 10), чи повинен вихід бути таким же, як вхід? Або це має бути наступна потужність на 10 вгору? "10 -> 10" або "10 -> 100"? Припустимо, колишній поки що.
- Чи можуть ваші вхідні значення бути будь-яким можливим значенням відповідних типів? або вони більш обмежені.
В іншій відповіді було запропоновано взяти логарифм, потім округлити (функція стелі), потім викласти.
def nextpow10(n):
return 10 ** math.ceil(math.log10(n))
На жаль, це страждає від помилок округлення. Перш за все n перетворюється з будь-якого типу даних, який має місце з подвійною точністю з плаваючою точкою, потенційно вводячи помилки округлення, потім логарифм обчислюється потенційно, вносячи більше помилок округлення як у його внутрішні обчислення, так і в його результат.
Як такий, мені не знадобилося багато часу, щоб знайти приклад, коли це дало неправильний результат.
>>> 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
Теоретично також можливо, що він провалиться в іншому напрямку, хоча це, здається, набагато важче спровокувати.
Тож для надійного рішення для плавців та ints нам потрібно припустити, що значення нашого логарифму лише приблизне, і тому ми повинні перевірити пару можливостей. Щось по лінії
def nextpow10(n):
p = round(math.log10(n))
r = 10 ** p
if r < n:
r = 10 ** (p+1)
return r;
Я вважаю, що цей код повинен дати правильні результати для всіх аргументів у розумному діапазоні величин. Він порушиться для дуже малої чи дуже великої кількості не цілих чи не плаваючих точок через проблеми перетворення їх у плаваючу крапку. Аргументи цілих випадків Python цілими аргументами до функції log10 у спробі запобігти переповненню, але все-таки при достатньо масивному цілому цілому може бути можливим привести невірні результати через помилки округлення.
Для тестування двох реалізацій я використав наступну програму тестування.
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
Це знаходить багато невдач у наївній реалізації, але жодної в покращеній реалізації.
10
до, це потрібно що - то з напрlog10
.