11

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

Patrick Chin
  • 119
  • 4
  • Welcome to Mathematica.SE! I suggest the following:
    1. As you receive help, try to give it too, by answering questions in your area of expertise.
    2. Read the [faq]!
    3. When you see good questions and answers, vote them up by clicking the gray triangles, because the credibility of the system is based on the reputation gained by users sharing their knowledge.

    Also, please remember to accept the answer, if any, that solves your problem, by clicking the checkmark sign!

    –  Nov 23 '14 at 17:03
  • 9
    AFAIK this is a common attribute of floating point arithmetic, and is expected behavior. Note that Mod[6/5, 1/5] gives 0. – DumpsterDoofus Nov 23 '14 at 17:04
  • 2
    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`

    – Daniel Lichtblau Nov 23 '14 at 17:06
  • Thanks, I Guess I'll have to find a workaround with integers – Patrick Chin Nov 23 '14 at 17:06
  • @PatrickChin Try Rationalize. – Kuba Nov 23 '14 at 17:07
  • @DumpsterDoofus Documentation states: The arguments of Mod can be any numeric quantities, not necessarily integers. So I don't think it is expected. – Kuba Nov 23 '14 at 17:09
  • 3
    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. – Daniel Lichtblau Nov 23 '14 at 17:21
  • 3
    @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. – DumpsterDoofus Nov 23 '14 at 17:24
  • @DumpsterDoofus I agree, but documentation should warn about that since MMA is advertised as suited also for people without programming/IT/numeric background. – Kuba Nov 23 '14 at 17:31
  • 1
    @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? – DumpsterDoofus Nov 23 '14 at 17:38
  • @Kuba I answered before seeing your comment. – faysou Oct 21 '15 at 07:59

3 Answers3

11

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
J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
ilian
  • 25,474
  • 4
  • 117
  • 186
6

This seems to work

Mod[Rationalize@1.2, Rationalize@0.2] == 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)

faysou
  • 10,999
  • 3
  • 50
  • 125
3

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.

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371