简体   繁体   English

没有 Decimal.quantize 的快速和精确的最近步浮点天花板/地板

[英]Fast and precise nearest step floating point ceiling/flooring without Decimal.quantize

The following function is supposed to ceil the given number to the nearest step:以下 function 应该将给定数字上限到最近的步骤:

def ceil_step(x, step):
    return math.ceil(x / step) * step

This works well... until it does not:这很好用......直到它没有:

print(ceil_step(1000.365, 0.01)) # 1000.37
print(ceil_step(1000.369, 0.01)) # 1000.37
print(ceil_step(1000.370, 0.01)) # 1000.37
print(ceil_step(1000.371, 0.01)) # 1000.38

print(ceil_step(10000.365, 0.01)) # 10000.37
print(ceil_step(10000.369, 0.01)) # 10000.37
print(ceil_step(10000.370, 0.01)) # 10000.380000000001
print(ceil_step(10000.371, 0.01)) # 10000.380000000001

A working implementation would be:一个可行的实现是:

def ceil_step(x, step):
    return Decimal(str(x)).quantize(Decimal(str(step)), rounding=ROUND_CEILING)

Unfortunately, I cannot use it because I am writing Numba-accelerated Python code.不幸的是,我无法使用它,因为我正在编写 Numba 加速的 Python 代码。 Therefore, my question: Is there a way to implement the ceil_step (and analogously floor_step ) function such that it only uses basic floating point operations or Numba-supported function calls and produces reliable results?因此,我的问题是:有没有办法实现ceil_step (以及类似floor_step ) function 以便它只使用基本的浮点运算或 Numba 支持的 function 调用并产生可靠的结果?

For now, I have settled with the following function:目前,我已经解决了以下 function:

def round_step(x, step, method=-1):
    eps = np.finfo(np.float64).eps
    digits = math.ceil(-np.log10(step))
    return round(math.ceil(x * (1 - eps) / step) * step, digits)

The multiplication with (1 - eps) makes sure (hopefully!) that math.ceil does not overshoot.(1 - eps)的乘法确保(希望如此!) math.ceil不会过冲。 The round is necessary to get rid of stuff like ...0000000001 .round对于摆脱...0000000001之类的东西是必要的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM