11
$\begingroup$

Why doesn't the following expression evaluate to zero?

In[1]:=Mod[1.2, 0.2]
Out[1]=0.2

Edit:

This is what I wanted to do:

xgrid = Table[{i,If[Mod[i, 0.2] == 0 , GrayLevel[0.5], GrayLevel[0.8]]}, {i, 0, 1.5, 0.05}]

I haven't programmed in a while so I forgot this happens. It was probably an error due to floating point arithmetic (0.2 cannot be fully represented by binary digits) so this was my solution:

xgrid = Table[{i*0.05, If[Mod[i, 4] == 0 , GrayLevel[0.5], GrayLevel[0.8]]}, {i, 0, 30, 1}]

This may also be the reason this solution for plotting minor and major grid lines didn't work for me

$\endgroup$
11
  • 9
    $\begingroup$ AFAIK this is a common attribute of floating point arithmetic, and is expected behavior. Note that Mod[6/5, 1/5] gives 0. $\endgroup$ Commented Nov 23, 2014 at 17:04
  • 2
    $\begingroup$ What @DumpsterDoofus said can be seen in this example by looking at the input form of the result. In[1]:= Mod[1.2, 0.2] // InputForm Out[1]//InputForm= 0.1999999999999999 $\endgroup$ Commented Nov 23, 2014 at 17:06
  • 3
    $\begingroup$ Expected or not, it is correct behavior, and for the reason given by @DumpsterDoofus. Machine floats are not in general exactly representable and roundoff error will give rise to this type of behavior, wherein e.g. 1.2-5*.2 is not exactly equal to 0.2, and 1.2-6*.2 is not exactly zero. $\endgroup$ Commented Nov 23, 2014 at 17:21
  • 3
    $\begingroup$ @Kuba: On the contrary, this sort of thing happens all the time. For example, note that in the high-performance scientific computing language Julia, there is a separate built-in function mod2pi for modulus under exact 2*pi. From the documentation, "mod2pi(x): This function computes a floating point representation of the modulus after division by numerically exact 2pi, and is therefore not exactly the same as mod(x,2pi), which would compute the modulus of x relative to division by the floating-point number 2pi." This is an unpleasant but unavoidable feature of floating-point arithmetic. $\endgroup$ Commented Nov 23, 2014 at 17:24
  • 1
    $\begingroup$ @Kuba: Yeah you're right, I feel like it should be listed in the Possible Issues section of the Mod documentation, but there are no warnings of the behavior listed there. Maybe the OP can suggest it to bug support as a feature request for the documentation? $\endgroup$ Commented Nov 23, 2014 at 17:38

3 Answers 3

11
$\begingroup$

Already answered in the comments by DumpsterDoofus and Daniel Lichtblau, to summarize:

Machine floating point numbers such as 0.2 are not always exactly representable in binary (no terminating expansion in base 2). Thus floating point arithmetic is susceptible to roundoff error and other accuracy problems. For example, the following are not exactly equal to 0.2 and 0. respectively:

1.2 - 5*0.2 // InputForm

(* 0.19999999999999996 *)

1.2 - 6*0.2 // InputForm

(* -2.220446049250313*^-16 *)

Such phenomena are not specific to Mathematica at all, e.g. Python's % and fmod operators give the exact same result as Mod:

$ python
Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
\>>> 1.2 % 0.2
0.1999999999999999
\>>> import math
\>>> math.fmod(1.2, 0.2)
0.1999999999999999
$\endgroup$
1
6
$\begingroup$

This seems to work

Mod[[email protected], [email protected]] == 0

I also tried with SetAccuracy, but it didn't always work.

"If Your Only Tool Is a Hammer Then Every Problem Looks Like a Nail"
What I mean is that I'm using here a function that is probably quite involved (Rationalize) for a problem that doesn't look complex (although it is complex when you have a look at http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html)

$\endgroup$
3
$\begingroup$

It appears that QuotientRemainder has logic to improve handling of this issue, though it's not perfect, and unfortunately your given example is one of the exceptions.

A simple example where it behaves "better" than Mod:

a = 1.2`;
b = 0.2`;

Mod[10 a, b]
QuotientRemainder[10 a, b]
0.2

{60, 0.}

Ideally we would want all integer multiples of a to have a remainder of either zero or b. Let's compare:

myMod = QuotientRemainder[#, #2][[All, 2]]&;  (* only for lists *)

Mod[Range[1*^6] a, b]    // Union // Length
myMod[Range[1*^6] a, b]  // Union // Length
795632

35

So while Mod produces nearly 80% "unique" values (according to Union) QuotientRemainder does so in only a few of the cases tested.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.