[R] odd behaviour of %%?

(Ted Harding) Ted.Harding at nessie.mcc.ac.uk
Wed Nov 22 12:33:09 CET 2006


On 22-Nov-06 Jonathan Williams wrote:
> Dear R Helpers,
> 
> I am trying to extract the modulus from divisions by a
> sequence of fractions.
> I noticed that %% seems to behave inconsistently (to my
> untutored eye), thus:
> 
>> 0.1%%0.1
> [1] 0
>> 0.2%%0.1
> [1] 0
>> 0.3%%0.1
> [1] 0.1
>> 0.4%%0.1
> [1] 0
>> 0.5%%0.1
> [1] 0.1
>> 0.6%%0.1
> [1] 0.1
>> 0.7%%0.1
> [1] 0.1
>> 0.8%%0.1
> [1] 0
>> 0.9%%0.1

This is yet another manifestation of the fact that R (like
most computer languages) stores numbers as binary representations
of fixed length. This is OK for inetegers up to a certain
maximum value, but relatively few factions (those which are
multiples of powers of 1/2) will be stored exactly.

In particular, 0.1 is not stored exactly.

When you do 0.2 %% 0.1, you will be getting the remainder of
twice the binary representation of 0.1, modulo 0.1, which will
be zero; and similarly for 0.4 and 0.8, since these are going
up by powers of 2 and the relationships between their binary
representations will match what you would expect.

However, the binary representation of 0.3 does not correspond
exactly to 3 times the binary representation of 0.1:

  0.3 - 3*0.1
  [1] -5.551115e-17

so 3*0.1 is represented by a binary fraction slightly greater
than the binary representation of 0.3, so 0.1 only "goes into"
0.3 twice, with a remainder slightly less than  0.1 which rounds
to 0.1 when displayed as a result:

  > 0.3 %% 0.1
  [1] 0.1
  > 0.1 - (0.3 %% 0.1)
  [1] 2.775558e-17

Similarly for 0.5, 0.6, 0.7 and 0.9.

> The modulus for 0.1, 0.2, 0.4 and 0.8 is zero, as I'd expect.
> But, the modulus for 0.3, 0.6, 0.7 and 0.9 is 0.1 - which I
> did not expect. I can see no obvious rule that predicts whether
> x%%0.1 will give an answer of 0 or 0.1. I could find no
> explanation of the way that %% works in the R manuals. So,
> I have 3 questions:-
> 
> 1) Why is the modulus of 0.3%%0.1 (and 0.5%%0.1 and 0.6%%0.1...)
> not zero?

See above.

> 2) Are there any algorithms in R that use the %% operator with
> fractional divisors in this way,

I don't know -- though others will!

> and do they know about its apparently inconsisten behaviour?

People who write algorithms should be aware of such effects of
binary representation, so a well-written algorithm will take
account of this danger.

> 3) If %% is not intended for use with fractional divisors,
> then would it be a good idea to trap attempts to use them?

The best protection against this kind of thing is circumspection
on the part of the programmer -- who, therefore should do his
own trapping.

An alternative aproach to the calculations you made could be

  > 0.3 - 0.1*(0.3/0.1)
  [1] 0

which is "algebraically" equivalent, and gives the right answer:

  > identical(0.3 - 0.1*(0.3/0.1),0)
  [1] TRUE

However, this is not always going to work either:

  > 1000001.1 - (1000001.1/0.1)*0.1
  [1] -1.164153e-10

so it's prudent to wrap it in a suitable round():

  > round(1000001.1 - (1000001.1/0.1)*0.1, digits=9)
  [1] 0

but you still have to be aware of what value to set the number
of digits to round to:

  > round(1000001.1 - (1000001.1/0.1)*0.1, digits=10)
  [1] -1e-10

Hoping this helps,
Ted.

--------------------------------------------------------------------
E-Mail: (Ted Harding) <Ted.Harding at nessie.mcc.ac.uk>
Fax-to-email: +44 (0)870 094 0861
Date: 22-Nov-06                                       Time: 11:33:05
------------------------------ XFMail ------------------------------



More information about the R-help mailing list