math.ceil
数値が次に高い10の累乗に割り当てられるようにするにはどうすればよいですか?
# 0.04 -> 0.1
# 0.7 -> 1
# 1.1 -> 10
# 90 -> 100
# ...
私の現在の解決策は入力数の範囲をチェックする辞書ですが、それはハードコードされており、1行の解決策を好みます。多分私はここで単純な数学的トリックまたは対応する派手な関数を逃していますか?
math.ceil
数値が次に高い10の累乗に割り当てられるようにするにはどうすればよいですか?
# 0.04 -> 0.1
# 0.7 -> 1
# 1.1 -> 10
# 90 -> 100
# ...
私の現在の解決策は入力数の範囲をチェックする辞書ですが、それはハードコードされており、1行の解決策を好みます。多分私はここで単純な数学的トリックまたは対応する派手な関数を逃していますか?
回答:
これを行うには、math.ceil
with math.log10
を使用できます。
>>> 10 ** math.ceil(math.log10(0.04))
0.1
>>> 10 ** math.ceil(math.log10(0.7))
1
>>> 10 ** math.ceil(math.log10(1.1))
10
>>> 10 ** math.ceil(math.log10(90))
100
log10(n)
は、x
を満たす解を与える10 ** x == n
のでx
、切り上げると、次に高い10のべき乗の指数が得られます。
音符値のそれ既に整数である「10の次に高いパワー」であろう。n
x
n
>>> 10 ** math.ceil(math.log10(0.1))
0.1
>>> 10 ** math.ceil(math.log10(1))
1
>>> 10 ** math.ceil(math.log10(10))
10
10 ** math.ceil(math.log10(1)) == 1
、「次の最高の累乗」ではありません
あなたの問題は十分に特定されておらず、一歩下がっていくつかの質問をする必要があります。
別の回答では、対数を取り、次に切り上げ(天井関数)、次にべき乗することが提案されました。
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
理論的には、他の方向に失敗する可能性もありますが、これを引き起こすのははるかに難しいようです。
したがって、floatとintの堅牢なソリューションでは、対数の値は近似値であると想定する必要があるため、いくつかの可能性をテストする必要があります。の線に沿った何か
def nextpow10(n):
p = round(math.log10(n))
r = 10 ** p
if r < n:
r = 10 ** (p+1)
return r;
私は、このコードが実用的な範囲のマグニチュードですべての引数に対して正しい結果を与えるはずだと思います。浮動小数点への変換に問題があるため、非常に少数または非常に多数の非整数型および非浮動小数点型では壊れます。Pythonは、オーバーフローを防止するためにlog10関数の整数引数を特殊なケースで処理しますが、十分に大きな整数を使用しても、丸めエラーが原因で誤った結果を強制する可能性があります。
2つの実装をテストするために、次のテストプログラムを使用しました。
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
これにより、単純な実装では多くの障害が見つかりますが、改善された実装では見つかりません。
round
代わりになぜ使用するのmath.ceil
ですか?これにより、r < n
trueである多くの不要なケースが発生し、追加の作業を実行する必要があります。
次の10の累乗のほうが望ましいと思われます。ここでは、純粋な数学を使用し、ログを使用せずに再帰を使用する方法を示します。
def ceiling10(x):
if (x > 10):
return ceiling10(x / 10) * 10
else:
if (x <= 1):
return ceiling10(10 * x) / 10
else:
return 10
for x in [1 / 1235, 0.5, 1, 3, 10, 125, 12345]:
print(x, ceiling10(x))
これをチェック!
>>> i = 0.04123; print i, 10 ** len( str( int( i ) ) ) if int( i ) > 1 else 10 if i > 1.0 else 1 if i > 0.1 else 10 ** ( 1 - min( [ ("%.100f" % i ).replace('.','').index( k ) for k in [ str( j ) for j in xrange( 1, 10 ) if str( j ) in "%.100f" % i ] ] ) )
0.04123 0.1
>>> i = 0.712; print i, 10 ** len( str( int( i ) ) ) if int( i ) > 1 else 10 if i > 1.0 else 1 if i > 0.1 else 10 ** ( 1 - min( [ ("%.100f" % i ).replace('.','').index( k ) for k in [ str( j ) for j in xrange( 1, 10 ) if str( j ) in "%.100f" % i ] ] ) )
0.712 1
>>> i = 1.1; print i, 10 ** len( str( int( i ) ) ) if int( i ) > 1 else 10 if i > 1.0 else 1 if i > 0.1 else 10 ** ( 1 - min( [ ("%.100f" % i ).replace('.','').index( k ) for k in [ str( j ) for j in xrange( 1, 10 ) if str( j ) in "%.100f" % i ] ] ) )
1.1 10
>>> i = 90; print i, 10 ** len( str( int( i ) ) ) if int( i ) > 1 else 10 if i > 1.0 else 1 if i > 0.1 else 10 ** ( 1 - min( [ ("%.100f" % i ).replace('.','').index( k ) for k in [ str( j ) for j in xrange( 1, 10 ) if str( j ) in "%.100f" % i ] ] ) )
90 100
このコードは、の10のべき乗の原理に基づいていlen( str( int( float_number ) ) )
ます。
4つのケースがあります。
int( i ) > 1
。Float
数値-に変換されint
、その後それstr()
から文字列に変換されると、正確に見ているstring
with が得られlength
ます。したがって、最初の部分は入力用ですi > 1.0
- 10
この長さの10 乗です。
i > 1.0
およびi > 0.1
<=>あり10
、1
それぞれです。i < 0.1
:ここでは、10は負のパワーになります。コンマの後に最初のゼロ以外の要素を取得するために、私はそのような構成を使用しました。("%.100f" % i ).replace('.','').index( k )
ここで、kは[1:10]
間隔にわたって実行されます。その後、結果リストを最小限にします。そして、1ずつ減少します。これは最初のゼロであり、カウントされます。また、interval index()
からゼロ以外の要素が少なくとも1つも見つからない場合、ここで標準のPython がクラッシュする可能性があります[1:10]
。そのため、結局、発生によってリストを「フィルタリング」する必要がありますif str( j ) in "%.100f" % i
。さらに、より深く正確にするために- %.100f
異なる場合があります。
10
するように見えますlog10
。これには、たとえばが必要になります。