Votre problème est sous-spécifié, vous devez prendre du recul et poser quelques questions.
- Quels types sont vos entrées?
- Quel (s) type (s) souhaitez-vous pour vos sorties?
- Pour des résultats inférieurs à 1, à quoi voulez-vous exactement arrondir? Voulez-vous des puissances réelles de 10 ou des approximations en virgule flottante de puissances de 10? Vous savez que des puissances négatives de 10 ne peuvent pas être exprimées exactement en virgule flottante, n'est-ce pas? Supposons pour l'instant que vous vouliez des approximations en virgule flottante de puissances de 10.
- Si l'entrée est exactement une puissance de 10 (ou l'approximation en virgule flottante la plus proche d'une puissance de 10), la sortie doit-elle être la même que l'entrée? Ou devrait-il être la prochaine puissance de 10? "10 -> 10" ou "10 -> 100"? Supposons le premier pour l'instant.
- Vos valeurs d'entrée peuvent-elles être une valeur possible des types en question? ou sont-ils plus contraints.
Dans une autre réponse, il a été proposé de prendre le logarithme, puis d'arrondir (fonction plafond), puis d'exposer.
def nextpow10(n):
return 10 ** math.ceil(math.log10(n))
Malheureusement, cela souffre d'erreurs d'arrondi. Tout d'abord, n est converti à partir de n'importe quel type de données qu'il se trouve avoir en un nombre à virgule flottante double précision, introduisant potentiellement des erreurs d'arrondi, puis le logarithme est calculé, introduisant potentiellement plus d'erreurs d'arrondi à la fois dans ses calculs internes et dans son résultat.
En tant que tel, il ne m'a pas fallu longtemps pour trouver un exemple où il a donné un résultat incorrect.
>>> 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
Il est également théoriquement possible qu'il échoue dans l'autre sens, bien que cela semble beaucoup plus difficile à provoquer.
Donc, pour une solution robuste pour les flottants et les entiers, nous devons supposer que la valeur de notre logarithme n'est qu'approximative, et nous devons donc tester quelques possibilités. Quelque chose dans le sens de
def nextpow10(n):
p = round(math.log10(n))
r = 10 ** p
if r < n:
r = 10 ** (p+1)
return r;
Je crois que ce code devrait donner des résultats corrects pour tous les arguments dans une gamme sensible de magnitudes réelles. Il se cassera pour de très petits ou très grands nombres de types non entiers et non flottants en raison de problèmes de conversion en virgule flottante. Cas spéciaux Python arguments entiers à la fonction log10 dans le but d'empêcher le débordement, mais toujours avec un entier suffisamment massif, il peut être possible de forcer des résultats incorrects en raison d'erreurs d'arrondi.
Pour tester les deux implémentations, j'ai utilisé le programme de test suivant.
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
Cela trouve beaucoup d'échecs dans l'implémentation naïve, mais aucun dans l'implémentation améliorée.
10
haut, cela aura besoin de quelque chose avec par exemplelog10
.