Ihr Problem ist unterbestimmt. Sie müssen einen Schritt zurücktreten und einige Fragen stellen.
- Welche Art (en) sind Ihre Eingaben?
- Welche Art (en) möchten Sie für Ihre Ausgaben?
- Auf was genau möchten Sie bei Ergebnissen unter 1 runden? Möchten Sie tatsächliche Potenzen von 10 oder Gleitkomma-Annäherungen von Potenzen von 10? Sie wissen, dass negative Potenzen von 10 nicht genau in Gleitkomma ausgedrückt werden können, oder? Nehmen wir zunächst an, dass Sie Gleitkomma-Approximationen von Potenzen von 10 wünschen.
- Wenn der Eingang genau eine Potenz von 10 ist (oder die nächste Gleitkomma-Annäherung an eine Potenz von 10), sollte der Ausgang mit dem Eingang identisch sein? Oder sollte es die nächste Potenz von 10 sein? "10 -> 10" oder "10 -> 100"? Nehmen wir vorerst das erstere an.
- Können Ihre Eingabewerte ein möglicher Wert der betreffenden Typen sein? oder sind sie eingeschränkter.
In einer anderen Antwort wurde vorgeschlagen, den Logarithmus zu nehmen, dann aufzurunden (Deckenfunktion) und dann zu potenzieren.
def nextpow10(n):
return 10 ** math.ceil(math.log10(n))
Leider weist dies Rundungsfehler auf. Zunächst wird n von einem beliebigen Datentyp in eine Gleitkommazahl mit doppelter Genauigkeit konvertiert, wodurch möglicherweise Rundungsfehler auftreten. Anschließend wird der Logarithmus berechnet, wodurch möglicherweise mehr Rundungsfehler sowohl in den internen Berechnungen als auch im Ergebnis auftreten.
Daher habe ich nicht lange gebraucht, um ein Beispiel zu finden, bei dem ein falsches Ergebnis erzielt wurde.
>>> 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
Es ist auch theoretisch möglich, dass es in die andere Richtung versagt, obwohl dies viel schwieriger zu provozieren scheint.
Für eine robuste Lösung für Floats und Ints müssen wir also davon ausgehen, dass der Wert unseres Logarithmus nur ungefähr ist, und wir müssen daher einige Möglichkeiten testen. Etwas in der Art von
def nextpow10(n):
p = round(math.log10(n))
r = 10 ** p
if r < n:
r = 10 ** (p+1)
return r;
Ich glaube, dieser Code sollte korrekte Ergebnisse für alle Argumente in einem vernünftigen realen Größenbereich liefern. Es wird für sehr kleine oder sehr große Anzahlen von nicht ganzzahligen und nicht Gleitkommatypen unterbrochen, da Probleme beim Konvertieren in Gleitkommatypen auftreten. Python-Sonderfälle Ganzzahlargumente für die Funktion log10, um einen Überlauf zu verhindern. Bei einer ausreichend massiven Ganzzahl können jedoch möglicherweise falsche Ergebnisse aufgrund von Rundungsfehlern erzwungen werden.
Um die beiden Implementierungen zu testen, habe ich das folgende Testprogramm verwendet.
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
Dies findet viele Fehler in der naiven Implementierung, aber keine in der verbesserten Implementierung.
10
oben funktionieren . Dies erfordert etwas mit zlog10
.