Just another person
Just another person

Reputation: 437

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

I write the following code to find the maximum product subarray:

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

When I use it on array = [6, -3, -10, 0, 2], I get an answer: 999999989
Whereas, when I change it to

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

I get the answer: 180
The only change I made was to use the fmod function and then convert it into integers rather than using the mod (%) operator. Why do I get totally different answers?

Upvotes: 1

Views: 1627

Answers (1)

MisterMiyagi
MisterMiyagi

Reputation: 50126

The % operator and math.fmod do not perform the same modulo operation. In specific, the handling of negative numbers is different:

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

Both ans variants will give the same result for positive inputs:

>>> 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

Upvotes: 3

Related Questions