[R] Funky calculations

Avi Gross @v|gro@@ @end|ng |rom ver|zon@net
Tue Feb 1 17:52:56 CET 2022


Yes, Nathan, you are missing something.

You are missing a computer language that does infinite precision arithmetic.

0.1 cannot be stored in binary exactly just as numbers like pi and e cannot be stored exactly as they keep needing more digits. The last digit of the allowed number of digits in floating point may have to be chosen as either a 0 or 1 even though the value is sort of in between. 

Think of what happens if you add in decimal

1/3 + 1/3 + 1/3

You could add

.333
.333
.333

And your handwritten calculation would be .999

And no matter how many more 3's you add, you never get beyond .999999999999999999999999999999999

And obviously the right answer is 1.0000000000000000000000000000

The order the numbers are added can matter. You interspersed a combination of floating point and integers so conversions are happening too. 

R has the ability to test for very near equality like this:

> all.equal(1, (0.4 + 0.2 + 0 + 0.3 + 0 + 0.1))
[1] TRUE

There are some built-in and sort of hidden variables stored in .Machine that provide some tolerances for the data storage on that machine. 

> str(.Machine)
List of 28
 $ double.eps               : num 2.22e-16
 $ double.neg.eps           : num 1.11e-16
 $ double.xmin              : num 2.23e-308
 $ double.xmax              : num 1.8e+308
 $ double.base              : int 2
 $ double.digits            : int 53
 $ double.rounding          : int 5
 $ double.guard             : int 0
 $ double.ulp.digits        : int -52
 $ double.neg.ulp.digits    : int -53
 $ double.exponent          : int 11
 $ double.min.exp           : int -1022
 $ double.max.exp           : int 1024
 $ integer.max              : int 2147483647
 $ sizeof.long              : int 4
 $ sizeof.longlong          : int 8
 $ sizeof.longdouble        : int 16
 $ sizeof.pointer           : int 8
 $ longdouble.eps           : num 1.08e-19
 $ longdouble.neg.eps       : num 5.42e-20
 $ longdouble.digits        : int 64
 $ longdouble.rounding      : int 5
 $ longdouble.guard         : int 0
 $ longdouble.ulp.digits    : int -63
 $ longdouble.neg.ulp.digits: int -64
 $ longdouble.exponent      : int 15
 $ longdouble.min.exp       : int -16382
 $ longdouble.max.exp       : int 16384

Functions like all.equal() can use these to determine a way to compare while ignoring the last.

So yes, R shares this glitch with other programming languages and it is not really safe to compare floating point numbers at times. Here is just a suggestion on say rounding your sum to twelve digits to see how it compares to 1.0:

> round((0.4 + 0.2 + 0 + 0.3 + 0 + 0.1),12) > 1.0
[1] FALSE





-----Original Message-----
From: Nathan Boeger <nboeger using gmail.com>
To: r-help using r-project.org
Sent: Tue, Feb 1, 2022 8:45 am
Subject: [R] Funky calculations

Hello,

I found something strange and maybe I am going nuts but this does not make
sense:

>  (0.4 + 0.2 + 0 + 0.3 + 0 + 0.1) > 1
[1] TRUE

I tried it on my mac M1 (R v4.1.2) and my Linux box (R v4.0.4). If I use
other values, it does not work (see below). It seems only that combination,
granted I did not try them all.

>  (0.4 + 0.2 + 0 + 0.2 + 0 + 0.2) > 1
[1] FALSE

Am I missing something?

Cheers

-nb

    [[alternative HTML version deleted]]

______________________________________________
R-help using r-project.org mailing list -- To UNSUBSCRIBE and more, see
https://stat.ethz.ch/mailman/listinfo/r-help
PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
and provide commented, minimal, self-contained, reproducible code.



More information about the R-help mailing list