Skip to content

When 1+2 != 3 (PR#9895)

7 messages · marco.vicentini at gmail.com, Petr Savicky, Duncan Murdoch +3 more

#
Full_Name: Marco Vicentini, University of Verona
Version: 2.4.1 & 2.5.1
OS: OsX & WinXP
Submission from: (NULL) (157.27.253.46)


When I proceed to test the following equation 1 + 2 == 3, I obviously obtain the
value TRUE. But when I tryed to do the same using real number (i.e. 0.1 + 0.2 ==
0.3)  I obtained an unusual FALSE.
In the online help there are some tricks for this problem. It suggests to use
identical(...) which again answer FALSE. Only using isTRUE(all.equal(0.3, 0.1 +
0.2)) I can obtain the true value TRUE.

But the problem does not concern only the operator ==. Many other functions,
among over:  sort, order, unique, duplicate, identical are not able to deal with
this problem. This is very dangerous because no advice are provide by the online
help, and anybody can use these functions no think to unusual results.

I think that the problem is due to how double number are store by the C
compiler.

If it may be usefull, I have written to small function (Unique and isEqual)
which can deal with this problem of the double numbers.

I also add some other conditions for the same problem.

	0.3 == 0.15 + 0.15
    0.3 == 0.1 + 0.2
1 - 0.7 == 0.3
    0.1 == 1 - 0.9

    0.2 == 1 - 0.2 - 0.2 - 0.2 - 0.2
   -0.2 == 1 - 0.2 - 0.2 - 0.2 - 0.2 - 0.2 - 0.2

identical (0.3, 0.1 + 0.2)
all.equal (0.3, 0.1 + 0.2)

identical (-0.2 , 1 - 0.2 - 0.2 - 0.2 - 0.2 - 0.2 - 0.2)
all.equal (-0.2 , 1 - 0.2 - 0.2 - 0.2 - 0.2 - 0.2 - 0.2)

isTRUE( all.equal (-0.2 , 1 - 0.2 - 0.2 - 0.2 - 0.2 - 0.2 - 0.2) )


   -0.2 == 1 - 0.2 - 0.2 - 0.2 - 0.2 - 0.2 - 0.2

a= -0.2 
b=         1 - 0.2 - 0.2 - 0.2 - 0.2 - 0.2 - 0.2

x<-c(a,b)
sprintf("%.15f",x)
sprintf("%.50f",x)



Unique <- function(x, digits = 8, fast = TRUE) {

	if (fast) {
		unique (round(x * 10^digits)) / 10^digits	
	} else {
		x = sort(x)
		for (i in 1:(length(x)-1))
			if (isTRUE(all.equal(x[i],x[i+1]))) x[i] = NaN
		x [ which (!is.nan(x)) ]
	}}

isEqual <- function (object, x, tol = 1e-9) {
	if (!is.vector(object)) stop("Object must be a vector")
	if (is.character(object)) stop("Object can not be a character")
	if (!is.real(x)) stop("x must be a real number")
	if (any(is.na(c(object,x)))) stop("NA is not supported")
	if (length(x) != 1) stop("length x must equal to 1")

	ifelse (abs(object - x) < tol, TRUE,FALSE) 
#	.Call("isEqual",as.real(object),as.real(x),as.real(tol), PACKAGE="mvUtils")
}
#
On Mon, Sep 03, 2007 at 08:59:22AM +0200, marco.vicentini at gmail.com wrote:
A rational number has a finite binary expansion iff its denominator is a power
of 2. Numbers 0.1 and 0.2 are 1/10 and 1/5, so they have 5 in their denominator.
Their binary expansion is
 0.1  = .0001100110011001100110011001100110...
 0.2  = .0011001100110011001100110011001100...
A double variable stores the numbers rounded to 53 significant binary digits.
Hence, they are not exactly 0.1 and 0.2, as may be seen in
  formatC(0.1,digits=30) # [1] "0.100000000000000005551115123126"
  formatC(0.2,digits=30) # [1] "0.200000000000000011102230246252"

In order to compare numbers with some tolerance, the function all.equal
may be used, which you also mention below. See its help page, which
specifies the tolerance to be  .Machine$double.eps ^ 0.5.
Not C compiler, but the hardware.

Petr Savicky.
#
On 03/09/2007 2:59 AM, marco.vicentini at gmail.com wrote:
The FAQ 7.31 gives general help on this.  Repeating it in every instance 
where it affects computations wouldn't make sense.

Please don't report unavoidable problems as bugs.

Duncan Murdoch
#
On 9/2/07, marco.vicentini at gmail.com <marco.vicentini at gmail.com> wrote:
Quiz: What about utility functions equalsE() and equalsPi()?
...together with examples illustrating when they return TRUE and when
they return FALSE.

Cheers

/Henrik
#
On 03-Sep-07 15:12:06, Henrik Bengtsson wrote:
Well, if you guys want a Quiz: ... My favourite example
of something which will probably never work on R (or any
machine which implements fixed-length binary real arithmetic).

An interated function scheme on [0,1] is defined by

  if 0 <= x <= 0.5 then next x = 2*x

  if 0.5 < x <= 1  then next x = 2*(1 - x)

in R:

  nextX <- function(x){ifelse(x<=0.5, 2*x, 2*(1-x))}

and try, e.g.,

 x<-3/7; for(i in (1:60)){x<-nextX(x); print(c(i,x))}

x = 0 is an absorbing state.
x = 1 -> x = 0
x = 1/2 -> 1 -> 0
...
(these work in R)

If K is an odd integer, and 0 < r < K, then

x = r/K ->  ... leads into a periodic set.

E.g. (see above) 3/7 -> 6/7 -> 2/7 -> 4/7 -> 2/7

All other numbers x outside these sets generate non-periodic
sequences.

Apart from the case where initial x = 1/2^k, none of the
above is true in R (e.g. the example above).

So can you devise an "isEqual" function which will make this
work?

It's only Monday .. plenty of time!
Best wishes,
Ted.

--------------------------------------------------------------------
E-Mail: (Ted Harding) <Ted.Harding at manchester.ac.uk>
Fax-to-email: +44 (0)870 094 0861
Date: 03-Sep-07                                       Time: 17:32:38
------------------------------ XFMail ------------------------------

--------------------------------------------------------------------
E-Mail: (Ted Harding) <ted.harding at nessie.mcc.ac.uk>
Fax-to-email: +44 (0)870 094 0861
Date: 03-Sep-07                                       Time: 18:50:23
------------------------------ XFMail ------------------------------
#
Not sure if this counts but using the Ryacas package
expression(3/7)
10 0: expression(3/7)
+ yacas("Set(x, If(x <= 1/2, 2*x, 2*(1-x)))")
+ cat(i, "i: "); print(x)
+ }
1 i: expression(6/7)
2 i: expression(2/7)
3 i: expression(4/7)
4 i: expression(6/7)
5 i: expression(2/7)
6 i: expression(4/7)
7 i: expression(6/7)
8 i: expression(2/7)
9 i: expression(4/7)
10 i: expression(6/7)
On 9/3/07, Ted Harding <ted.harding at nessie.mcc.ac.uk> wrote:
#
On 03-Sep-07 19:25:58, Gabor Grothendieck wrote:
Gabor, I'm afraid it doesn't count! (Though I didn't
exclude it explicitly). I'm not interested in the behaviour
of the sequence with denominator = 7 particularly.
The system is in fact an example of simulating chaotic
systems on a computer.

For instance, one of the classic illustrations is

  next x = 2*x*(1-x)

for any real x. The question is, how does a finite-length
binary representation behave?

Petr Savicky [privately] sent me a similar example:
Starting with r/K:

nextr <- function(r){ifelse(r<=K/2, 2*r, 2*(K-r))}

  "For K = 7 and r = 3, this yields r = 3,  6,  2,  4,  6, ...
   Dividing this by K=7, one gets the correct period with
   approximately correct numbers."

Best wishes,
Ted.

--------------------------------------------------------------------
E-Mail: (Ted Harding) <Ted.Harding at manchester.ac.uk>
Fax-to-email: +44 (0)870 094 0861
Date: 03-Sep-07                                       Time: 21:02:27
------------------------------ XFMail ------------------------------