[英]Python round to next highest power of 10
How would I manage to perform math.ceil
such that a number is assigned to the next highest power of 10?我将如何设法执行
math.ceil
以便将数字分配给 10 的下一个最高幂?
# 0.04 -> 0.1
# 0.7 -> 1
# 1.1 -> 10
# 90 -> 100
# ...
My current solution is a dictionary that checks the range of the input number, but it's hardcoded and I would prefer a one-liner solution.我当前的解决方案是检查输入数字范围的字典,但它是硬编码的,我更喜欢单行解决方案。 Maybe I am missing a simple mathematical trick or a corresponding numpy function here?
也许我在这里缺少一个简单的数学技巧或相应的 numpy function ?
You can use math.ceil
with math.log10
to do this:您可以使用
math.ceil
和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)
gives you the solution x
that satisfies 10 ** x == n
, so if you round up x
it gives you the exponent for the next highest power of 10. log10(n)
为您提供满足10 ** x == n
的解决方案x
,因此如果您将x
向上取整,它会为您提供下一个最高 10 次幂的指数。
Note that for a value n
where x
is already an integer, the "next highest power of 10" will be n
:请注意,对于
x
已经是 integer 的值n
, “10 的下一个最高幂”将为n
:
>>> 10 ** math.ceil(math.log10(0.1))
0.1
>>> 10 ** math.ceil(math.log10(1))
1
>>> 10 ** math.ceil(math.log10(10))
10
Your problem is under-specified, you need to step back and ask some questions.您的问题未明确说明,您需要退后一步并提出一些问题。
In another answer it was proposed to take the logarithm, then round up (ceiling function), then exponentiate.在另一个答案中,建议取对数,然后四舍五入(天花板函数),然后取幂。
def nextpow10(n):
return 10 ** math.ceil(math.log10(n))
Unfortunately this suffers from rounding errors.不幸的是,这会受到舍入误差的影响。 First of all n is converted from whatever data type it happens to have into a double precision floating point number, potentially introducing rounding errors, then the logarithm is calculated potentially introducing more rounding errors both in its internal calculations and in its result.
首先,n 从它碰巧拥有的任何数据类型转换为双精度浮点数,可能会引入舍入误差,然后计算对数可能会在其内部计算和结果中引入更多舍入误差。
As such it did not take me long to find an example where it gave an incorrect result.因此,我很快就找到了一个给出错误结果的例子。
>>> 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
It is also theoretically possible for it to fail in the other direction, though this seems to be much harder to provoke.从理论上讲,它也有可能在另一个方向上失败,尽管这似乎更难激怒。
So for a robust solution for floats and ints we need to assume that the value of our logarithm is only approximate, and we must therefore test a couple of possibilities.因此,对于浮点数和整数的稳健解决方案,我们需要假设我们的对数值只是近似值,因此我们必须测试几种可能性。 Something along the lines of
类似的东西
def nextpow10(n):
p = round(math.log10(n))
r = 10 ** p
if r < n:
r = 10 ** (p+1)
return r;
I believe this code should give correct results for all arguments in a sensible real-world range of magnitudes.我相信这段代码应该为所有 arguments 在合理的真实世界范围内给出正确的结果。 It will break for very small or very large numbers of non integer and non-floating point types because of issues converting them to floating point.
由于将它们转换为浮点的问题,它会破坏非常少量或非常大量的非 integer 和非浮点类型。 Python special cases integer arguments to the log10 function in an attempt to prevent overflow, but still with a sufficiently massive integer it may be possible to force incorrect results due to rounding errors.
Python special cases integer arguments to the log10 function in an attempt to prevent overflow, but still with a sufficiently massive integer it may be possible to force incorrect results due to rounding errors.
To test the two implementations I used the following test program.为了测试这两个实现,我使用了以下测试程序。
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
This finds lots of failures in the naive implementation, but none in the improved implementation.这在幼稚的实现中发现了很多失败,但在改进的实现中却没有。
It seems you want rather the lowest next power of 10... Here is a way using pure maths and no log, but recursion.看来您想要的是 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))
Check this out!看一下这个!
>>> 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
This code based on principle of ten's power in len(str(int(float_number)))
.此代码基于
len(str(int(float_number)))
中的十次方原理。
There are 4 cases:有4种情况:
int(i) > 1
. int(i) > 1
。
Float
number - converted to int
, thereafter string str()
from it, will give us a string
with length
which is we are looking exactly. Float
- 转换为int
,然后字符串str()
将给我们一个length
为我们正在查看的string
。 So, first part, for input i > 1.0
- it is ten 10
in power of this length.所以,第一部分,对于输入
i > 1.0
- 它是这个长度的 10 的10
次方。
i > 1.0
and i > 0.1
<=> it is 10
and 1
respectively. i > 1.0
和i > 0.1
<=> 分别是10
和1
。i < 0.1
: Here, ten shall be in negative power.i < 0.1
时:这里,10 应该是负幂。 To get first non zero element after comma, I've used such construction ("%.100f" % i).replace('.', '').index(k)
, where k run over [1:10]
interval.("%.100f" % i).replace('.', '').index(k)
,其中 k 超过[1:10]
间隔. Thereafter, take minimum of result list.index()
may crash, if it will not find at least one of non-zero element from [1:10]
interval, that is why in the end I must "filter" listing by occurrence: if str(j) in "%.100f" % i
.index()
可能会崩溃,如果它不会从[1:10]
间隔中找到至少一个非零元素,这就是为什么最后我必须按出现“过滤”列表: if str(j) in "%.100f" % i
中。 Additionally, to get deeper precise - %.100f
may be taken differ.%.100f
可能会有所不同。I think the simplest way is:我认为最简单的方法是:
import math
number = int(input('Enter a number: '))
next_pow_ten = round(10 ** math.ceil(math.log10(number)))
print(str(10) + ' power ' + str(round(math.log10(number))) + ' = '\
+ str(next_pow_ten))
I hope this help you.我希望这对你有帮助。
a specific shortcut works for big-integers that are already coming in as string-format:一个特定的快捷方式适用于已经以字符串格式出现的大整数:
instead of having to first convert it to integer, or running it through the log()/ceiling()
function, or perform any sort of modulo math, the next largest power-of-10 is simply:不必先将其转换为 integer,或通过
log()/ceiling()
function 运行它,或执行任何类型的模数运算,下一个最大的 10 次幂很简单:
10 ** length(big_int_str_var)
—- below: 1st one generates a string formatted power-of-10, the 2nd one is numeric --- 下面:第一个生成一个字符串格式的 10 次幂,第二个是数字
echo 23958699683561808518065081866850688652086158016508618152865101851111111111111 | tee >( gpaste | gcat -n >&2; ) | gcat - | python3 -c '\ import sys; [ print("1"+"0"*len(_.strip("\n"))) for _ in sys.stdin ]' or '... [ print( 10 ** len(_.strip("\n"))) for _ in sys.stdin ]'
1 23958699683561808518065081866850688652086158016508618152865101851111111111111
1 100000000000000000000000000000000000000000000000000000000000000000000000000000
y = math.ceil(x)
z = y + (10 - (y % 10))
Something like this maybe?可能是这样的? It's just off the top of my head but it worked when I tried a few numbers in terminal.
这只是我的想法,但是当我在终端中尝试了几个数字时它就起作用了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.