5

GNU C 库具有函数drem(别名remainder)。

如何仅使用Google App Engine Python 2.7 运行时支持的模块来模拟此功能?

来自GNU手册drem

这些函数很相似fmod,只是它们将内商 n 舍入到最接近的整数,而不是向零舍入到整数。例如,drem (6.5, 2.3) 返回 -0.4,即 6.5 减去 6.9。

来自GNU手册fmod

这些函数计算分子除以分母的余数。具体来说,返回值为分子 - n * 分母,其中 n 是分子除以分母的商,向零舍入为整数。因此,fmod (6.5, 2.3) 返回 1.9,即 6.5 减去 4.6。

阅读文档,以下 Python 代码应该可以工作:

def drem(x, y):
    n = round(x / y)
    return x - n * y

但是对于 Pythondrem(1.0, 2.0) == -1.0和 C drem(1.0, 2.0) == 1.0。注意 Python 返回负一,C 返回正一。这几乎可以肯定是舍入浮点数的内部差异。据我所知,这两个函数的执行方式相同,否则参数2 * x != y

如何使我的 Pythondrem函数与其 C 等效函数一样工作?

4

2 回答 2

5

解决这个问题的关键是要实现drem/remainder 函数规范要求内部舍入计算要四舍五入为偶数。

因此,我们不能使用 Python 2.x 中的内置round函数,因为它从 0 舍入。但是roundPython 3.x 中的函数已更改为舍入到一半。因此,以下 Python 3.x 代码将等效于 GNU C 库drem函数,但在 Python 2.x 中不起作用:

def drem(x, y):
    n = round(x / y)
    return x - n * y

为了在 Python 2.x 中实现同样的效果,我们可以使用 decimal 模块及其剩余函数:

import decimal

def drem(x, y):
    xd = decimal.Decimal(x)
    yd = decimal.Decimal(y)

    return float(xd.remainder_near(yd))
于 2013-07-06T12:28:32.570 回答
1

编辑:我刚刚阅读了您的第一条评论,发现您无法使用该ctypes模块。无论如何,我今天通过尝试找到您的问题的答案学到了很多东西。

考虑到将numpy.round()舍入十进制值之间的值恰好舍入到下一个偶数整数,使用 numpy 不是一个好的解决方案。

另外,drem内部调用了这个MONSTER 函数,这在 Python 中应该很难实现。

这篇文章的启发,我建议您drem直接从数学库中调用该函数。这些方面的东西应该可以解决问题:

from ctypes import CDLL
# Use the C math library directly from Python
# This works for Linux, but the version might differ for some systems
libm = CDLL('libm.so.6') 

# For Windows, try this instead: 
# from ctypes import cdll
# libm = cdll.libc

# Make sure the return value is handled as double instead of the default int
libm.drem.restype = c_double
# Make sure the arguments are double by putting them inside c_double()
# Call your function and have fun!
print libm.drem(c_double(1.0), c_double(2.0))
于 2013-07-05T16:47:02.300 回答