0

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?

  • from [docs](https://docs.python.org/3.8/library/math.html#math.fmod): Note that the Python expression x % y may not return the same result. – deadshot Aug 07 '20 at 10:00
  • @deadshot the only ambiguity they mention here is for float data type but here we have all integers. – Just another person Aug 07 '20 at 10:03
  • 1
    A minimal example may help. (e.g. which numbers gives a different results. IIRC there are other possible changes: different convention when we have minus signs. it is hidden somewhere in documentation, and without a clear answer – Giacomo Catenazzi Aug 07 '20 at 10:10
  • The first initialises ``cur_max = cur_min = ans = arr[0] % M``, the second just ``cur_max = cur_min = ans = arr[0]``. Is this intentional? – MisterMiyagi Aug 07 '20 at 10:11
  • `-6 % M` gives different results – Giacomo Catenazzi Aug 07 '20 at 10:12

1 Answers1

2

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
MisterMiyagi
  • 44,374
  • 10
  • 104
  • 119