为什么我在使用 math.fmod 和 mod 运算符时会得到不同的答案? (对于整数)

Why do I get different answers when I use math.fmod and just the mod operator? (for integers)

我写了下面的代码来求最大乘积子数组:

def ans(arr, n):
    M = 1000000007
    cur_max = cur_min = ans = arr[0] % M
    for i in range(1, n):
        tmp = cur_max
        cur_max = max(arr[i], cur_min * arr[i]% M, cur_max * arr[i] % M)
        cur_min = min(arr[i], cur_min * arr[i] % M, tmp * arr[i] % M)
        ans = max(ans, cur_max)
    return ans % M

当我使用它的时候 array = [6, -3, -10, 0, 2],我得到一个答案:999999989
然而,当我将其更改为

from math import *
def ans(arr, n):
    M = 1000000007
    cur_max = cur_min = ans = arr[0]
    for i in range(1, n):
        tmp = cur_max
        cur_max = max(arr[i], int(fmod(cur_min * arr[i], M)), int(fmod(cur_max * arr[i], M)))
        cur_min = min(arr[i], int(fmod(cur_min * arr[i], M)), int(fmod(tmp * arr[i], M)))
        ans = max(ans, cur_max)
    return ans

我得到答案:180
我所做的唯一更改是使用 fmod 函数,然后将其转换为整数,而不是使用 mod (%) 运算符。为什么我得到完全不同的答案?

% 运算符和 math.fmod 不执行相同的模运算。具体负数的处理方式不同:

math.fmod(x, y)

[..] The intent of the C standard is that fmod(x, y) be exactly (mathematically; to infinite precision) equal to x - n*y for some integer n such that the result has the same sign as x and magnitude less than abs(y). Python’s x % y returns a result with the sign of y instead, and may not be exactly computable for float arguments. [..]

Binary arithmetic operations

[..] The modulo operator always yields a result with the same sign as its second operand (or zero); [..] The function math.fmod() returns a result whose sign matches the sign of the first argument instead [..]. Which approach is more appropriate depends on the application.

>>> def test_mod(a, b): print('%-op:', a % b, 'fmod:', fmod(a, b))
>>> test_mod(10, 12)
%-op: 10 fmod: 10.0
>>> test_mod(-10, 12)
%-op: 2 fmod: -10.0
>>> test_mod(10, -12)
%-op: -2 fmod: 10.0

两个 ans 变体将为 positive 输入提供相同的结果:

>>> perc_ans([6, 3, 10, 0, 2], 5)
180
>>> math_ans([6, 3, 10, 0, 2], 5)
180
>>> perc_ans([6, -3, -10, 0, 2], 5)
999999989
>>> math_ans([6, -3, -10, 0, 2], 5)
180