This operation should return 2
, but it returns 1
instead because of the floating point representation:
a <- .3
b <- .1
floor((a-b)*10)
I basically want the first digit after the point, of the actual base-10 result, not the floating-point computer's result. In this case a
and b
only have one decimal digit, but in most situations there will be more. Examples:
0.3-0.1=0.2
so I want the 2
0.5-0.001=0.499
so I want the 4
0.925-0.113=0.812
so I want the 8
0.57-0.11=0.46
so I want the 4
0.12-0.11=0.01
so I want the 0
that is, not rounding but truncating. I thought of using this:
floor(floor((a-b)*100)/10)
but I'm not sure if that is the best I can do.
update: indeed, it doesn't work (see comments below):
floor(floor((.9-.8)*100)/10) # gives 0 instead of 1
floor(round((.5-.001)*100)/10) # gives 5 instead of 1
update 2: think this does work (at least in all cases listed so far):
substring(as.character(a-b),first=3,last=3)
Suggestions?
This is not possible, because the information is no longer there: doubles cannot exactly represent decimal numbers.
If you are fine with an approximate solution, you can add a small number, and truncate the result. For instance, if you know that your numbers have at most 14 digits, the following would work:
first_digit <- function(x, epsilon=5e-15)
floor( (x+epsilon) * 10 )
first_digit( .3 - .1 ) # 2
first_digit( .5 - .001 ) # 4
first_digit( .925 - .113 ) # 8
first_digit( .57 - .11 ) # 4
first_digit( .12 - .11 ) # 0
If you wanted the first significant digit (that means "first non-zero digit"), you could use:
first_significant_digit <- function(x, epsilon=5e-14)
floor( (x+epsilon) * 10^-floor(log10(x+epsilon)) )
first_significant_digit(0.12-0.11) # 1