Reputation: 437
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
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 tox - n*y
for some integern
such that the result has the same sign asx
and magnitude less thanabs(y)
. Python’sx % y
returns a result with the sign ofy
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