compairing doubles

classic Classic list List threaded Threaded
14 messages Options
Reply | Threaded
Open this post in threaded view
|

compairing doubles

Felix Ernst
Dear all,

I a bit unsure, whether this qualifies as a bug, but it is definitly a strange behaviour. That why I wanted to discuss it.

With the following function, I want to test for evenly space numbers, starting from anywhere.

.is_continous_evenly_spaced <- function(n){
  if(length(n) < 2) return(FALSE)
  n <- n[order(n)]
  n <- n - min(n)
  step <- n[2] - n[1]
  test <- seq(from = min(n), to = max(n), by = step)
  if(length(n) == length(test) &&
     all(n == test)){
    return(TRUE)
  }
  return(FALSE)
}

> .is_continous_evenly_spaced(c(1,2,3,4))
[1] TRUE
> .is_continous_evenly_spaced(c(1,3,4,5))
[1] FALSE
> .is_continous_evenly_spaced(c(1,1.1,1.2,1.3))
[1] FALSE

I expect the result for 1 and 2, but not for 3. Upon Investigation it turns out, that n == test is TRUE for every pair, but not for the pair of 0.2.

The types reported are always double, however n[2] == 0.1 reports FALSE as well.

The whole problem is solved by switching from all(n == test) to all(as.character(n) == as.character(test)). However that is weird, isn�t it?

Does this work as intended? Thanks for any help, advise and suggestions in advance.

Best regards,
Felix


        [[alternative HTML version deleted]]


______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: compairing doubles

Iñaki Ucar
El vie., 31 ago. 2018 a las 15:10, Felix Ernst
(<[hidden email]>) escribió:

>
> Dear all,
>
> I a bit unsure, whether this qualifies as a bug, but it is definitly a strange behaviour. That why I wanted to discuss it.
>
> With the following function, I want to test for evenly space numbers, starting from anywhere.
>
> .is_continous_evenly_spaced <- function(n){
>   if(length(n) < 2) return(FALSE)
>   n <- n[order(n)]
>   n <- n - min(n)
>   step <- n[2] - n[1]
>   test <- seq(from = min(n), to = max(n), by = step)
>   if(length(n) == length(test) &&
>      all(n == test)){
>     return(TRUE)
>   }
>   return(FALSE)
> }
>
> > .is_continous_evenly_spaced(c(1,2,3,4))
> [1] TRUE
> > .is_continous_evenly_spaced(c(1,3,4,5))
> [1] FALSE
> > .is_continous_evenly_spaced(c(1,1.1,1.2,1.3))
> [1] FALSE
>
> I expect the result for 1 and 2, but not for 3. Upon Investigation it turns out, that n == test is TRUE for every pair, but not for the pair of 0.2.
>
> The types reported are always double, however n[2] == 0.1 reports FALSE as well.
>
> The whole problem is solved by switching from all(n == test) to all(as.character(n) == as.character(test)). However that is weird, isn’t it?
>
> Does this work as intended? Thanks for any help, advise and suggestions in advance.

I guess this has something to do with how the sequence is built and
the inherent error of floating point arithmetic. In fact, if you
return test minus n, you'll get:

[1] 0.000000e+00 0.000000e+00 2.220446e-16 0.000000e+00

and the error gets bigger when you continue the sequence; e.g., this
is for c(1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7):

[1] 0.000000e+00 0.000000e+00 2.220446e-16 2.220446e-16 4.440892e-16
[6] 4.440892e-16 4.440892e-16 0.000000e+00

So, independently of this is considered a bug or not, instead of

length(n) == length(test) && all(n == test)

I would use the following condition:

isTRUE(all.equal(n, test))

Iñaki

>
> Best regards,
> Felix
>
>
>         [[alternative HTML version deleted]]
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel



--
Iñaki Ucar

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: compairing doubles

Emil
Agreed that's it's rounding error, and all.equal would be the way to go.
I wouldn't call it a bug, it's simply part of working with floating point numbers, any language has the same issue.

And while we're at it, I think the function can be a lot shorter:
.is_continous_evenly_spaced <- function(n){
  length(n)>1 && isTRUE(all.equal(n[order(n)], seq(from=min(n), to=max(n), length.out = length(n))))
}

Cheers, Emil

    El vie., 31 ago. 2018 a las 15:10, Felix Ernst
    (<[hidden email]>) escribió:
    >
    > Dear all,
    >
    > I a bit unsure, whether this qualifies as a bug, but it is definitly a strange behaviour. That why I wanted to discuss it.
    >
    > With the following function, I want to test for evenly space numbers, starting from anywhere.
    >
    > .is_continous_evenly_spaced <- function(n){
    >   if(length(n) < 2) return(FALSE)
    >   n <- n[order(n)]
    >   n <- n - min(n)
    >   step <- n[2] - n[1]
    >   test <- seq(from = min(n), to = max(n), by = step)
    >   if(length(n) == length(test) &&
    >      all(n == test)){
    >     return(TRUE)
    >   }
    >   return(FALSE)
    > }
    >
    > > .is_continous_evenly_spaced(c(1,2,3,4))
    > [1] TRUE
    > > .is_continous_evenly_spaced(c(1,3,4,5))
    > [1] FALSE
    > > .is_continous_evenly_spaced(c(1,1.1,1.2,1.3))
    > [1] FALSE
    >
    > I expect the result for 1 and 2, but not for 3. Upon Investigation it turns out, that n == test is TRUE for every pair, but not for the pair of 0.2.
    >
    > The types reported are always double, however n[2] == 0.1 reports FALSE as well.
    >
    > The whole problem is solved by switching from all(n == test) to all(as.character(n) == as.character(test)). However that is weird, isn’t it?
    >
    > Does this work as intended? Thanks for any help, advise and suggestions in advance.
   
    I guess this has something to do with how the sequence is built and
    the inherent error of floating point arithmetic. In fact, if you
    return test minus n, you'll get:
   
    [1] 0.000000e+00 0.000000e+00 2.220446e-16 0.000000e+00
   
    and the error gets bigger when you continue the sequence; e.g., this
    is for c(1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7):
   
    [1] 0.000000e+00 0.000000e+00 2.220446e-16 2.220446e-16 4.440892e-16
    [6] 4.440892e-16 4.440892e-16 0.000000e+00
   
    So, independently of this is considered a bug or not, instead of
   
    length(n) == length(test) && all(n == test)
   
    I would use the following condition:
   
    isTRUE(all.equal(n, test))
   
    Iñaki
   
    >
    > Best regards,
    > Felix
    >
    >
    >         [[alternative HTML version deleted]]
    >
    > ______________________________________________
    > [hidden email] mailing list
    > https://stat.ethz.ch/mailman/listinfo/r-devel
   
   
   
    --
    Iñaki Ucar
   
    ______________________________________________
    [hidden email] mailing list
    https://stat.ethz.ch/mailman/listinfo/r-devel
   

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: compairing doubles

Iñaki Ucar
In reply to this post by Iñaki Ucar
FYI, more fun with floats:

> 0.1+0.1==0.2
[1] TRUE
> 0.1+0.1+0.1+0.1==0.4
[1] TRUE
> 0.1+0.1+0.1==0.3
[1] FALSE
> 0.1+0.1+0.1==0.1*3
[1] TRUE
> 0.3==0.1*3
[1] FALSE

¯\_(ツ)_/¯

But this is not R's fault. See: https://0.30000000000000004.com

Iñaki

El vie., 31 ago. 2018 a las 15:36, Iñaki Ucar
(<[hidden email]>) escribió:

>
> El vie., 31 ago. 2018 a las 15:10, Felix Ernst
> (<[hidden email]>) escribió:
> >
> > Dear all,
> >
> > I a bit unsure, whether this qualifies as a bug, but it is definitly a strange behaviour. That why I wanted to discuss it.
> >
> > With the following function, I want to test for evenly space numbers, starting from anywhere.
> >
> > .is_continous_evenly_spaced <- function(n){
> >   if(length(n) < 2) return(FALSE)
> >   n <- n[order(n)]
> >   n <- n - min(n)
> >   step <- n[2] - n[1]
> >   test <- seq(from = min(n), to = max(n), by = step)
> >   if(length(n) == length(test) &&
> >      all(n == test)){
> >     return(TRUE)
> >   }
> >   return(FALSE)
> > }
> >
> > > .is_continous_evenly_spaced(c(1,2,3,4))
> > [1] TRUE
> > > .is_continous_evenly_spaced(c(1,3,4,5))
> > [1] FALSE
> > > .is_continous_evenly_spaced(c(1,1.1,1.2,1.3))
> > [1] FALSE
> >
> > I expect the result for 1 and 2, but not for 3. Upon Investigation it turns out, that n == test is TRUE for every pair, but not for the pair of 0.2.
> >
> > The types reported are always double, however n[2] == 0.1 reports FALSE as well.
> >
> > The whole problem is solved by switching from all(n == test) to all(as.character(n) == as.character(test)). However that is weird, isn’t it?
> >
> > Does this work as intended? Thanks for any help, advise and suggestions in advance.
>
> I guess this has something to do with how the sequence is built and
> the inherent error of floating point arithmetic. In fact, if you
> return test minus n, you'll get:
>
> [1] 0.000000e+00 0.000000e+00 2.220446e-16 0.000000e+00
>
> and the error gets bigger when you continue the sequence; e.g., this
> is for c(1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7):
>
> [1] 0.000000e+00 0.000000e+00 2.220446e-16 2.220446e-16 4.440892e-16
> [6] 4.440892e-16 4.440892e-16 0.000000e+00
>
> So, independently of this is considered a bug or not, instead of
>
> length(n) == length(test) && all(n == test)
>
> I would use the following condition:
>
> isTRUE(all.equal(n, test))
>
> Iñaki
>
> >
> > Best regards,
> > Felix
> >
> >
> >         [[alternative HTML version deleted]]
> >
> > ______________________________________________
> > [hidden email] mailing list
> > https://stat.ethz.ch/mailman/listinfo/r-devel
>
>
>
> --
> Iñaki Ucar



--
Iñaki Ucar

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: compairing doubles

Mark van der Loo
In reply to this post by Emil
how about

is_evenly_spaced <- function(x,...) all.equal(diff(sort(x)),...)

(use ellipsis to set tolerance if necessary)


Op vr 31 aug. 2018 om 15:46 schreef Emil Bode <[hidden email]>:

> Agreed that's it's rounding error, and all.equal would be the way to go.
> I wouldn't call it a bug, it's simply part of working with floating point
> numbers, any language has the same issue.
>
> And while we're at it, I think the function can be a lot shorter:
> .is_continous_evenly_spaced <- function(n){
>   length(n)>1 && isTRUE(all.equal(n[order(n)], seq(from=min(n), to=max(n),
> length.out = length(n))))
> }
>
> Cheers, Emil
>
>     El vie., 31 ago. 2018 a las 15:10, Felix Ernst
>     (<[hidden email]>) escribió:
>     >
>     > Dear all,
>     >
>     > I a bit unsure, whether this qualifies as a bug, but it is definitly
> a strange behaviour. That why I wanted to discuss it.
>     >
>     > With the following function, I want to test for evenly space
> numbers, starting from anywhere.
>     >
>     > .is_continous_evenly_spaced <- function(n){
>     >   if(length(n) < 2) return(FALSE)
>     >   n <- n[order(n)]
>     >   n <- n - min(n)
>     >   step <- n[2] - n[1]
>     >   test <- seq(from = min(n), to = max(n), by = step)
>     >   if(length(n) == length(test) &&
>     >      all(n == test)){
>     >     return(TRUE)
>     >   }
>     >   return(FALSE)
>     > }
>     >
>     > > .is_continous_evenly_spaced(c(1,2,3,4))
>     > [1] TRUE
>     > > .is_continous_evenly_spaced(c(1,3,4,5))
>     > [1] FALSE
>     > > .is_continous_evenly_spaced(c(1,1.1,1.2,1.3))
>     > [1] FALSE
>     >
>     > I expect the result for 1 and 2, but not for 3. Upon Investigation
> it turns out, that n == test is TRUE for every pair, but not for the pair
> of 0.2.
>     >
>     > The types reported are always double, however n[2] == 0.1 reports
> FALSE as well.
>     >
>     > The whole problem is solved by switching from all(n == test) to
> all(as.character(n) == as.character(test)). However that is weird, isn’t it?
>     >
>     > Does this work as intended? Thanks for any help, advise and
> suggestions in advance.
>
>     I guess this has something to do with how the sequence is built and
>     the inherent error of floating point arithmetic. In fact, if you
>     return test minus n, you'll get:
>
>     [1] 0.000000e+00 0.000000e+00 2.220446e-16 0.000000e+00
>
>     and the error gets bigger when you continue the sequence; e.g., this
>     is for c(1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7):
>
>     [1] 0.000000e+00 0.000000e+00 2.220446e-16 2.220446e-16 4.440892e-16
>     [6] 4.440892e-16 4.440892e-16 0.000000e+00
>
>     So, independently of this is considered a bug or not, instead of
>
>     length(n) == length(test) && all(n == test)
>
>     I would use the following condition:
>
>     isTRUE(all.equal(n, test))
>
>     Iñaki
>
>     >
>     > Best regards,
>     > Felix
>     >
>     >
>     >         [[alternative HTML version deleted]]
>     >
>     > ______________________________________________
>     > [hidden email] mailing list
>     > https://stat.ethz.ch/mailman/listinfo/r-devel
>
>
>
>     --
>     Iñaki Ucar
>
>     ______________________________________________
>     [hidden email] mailing list
>     https://stat.ethz.ch/mailman/listinfo/r-devel
>
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>

        [[alternative HTML version deleted]]

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: compairing doubles

R devel mailing list
In reply to this post by Iñaki Ucar


> On Aug 31, 2018, at 9:36 AM, Iñaki Ucar <[hidden email]> wrote:
>
> El vie., 31 ago. 2018 a las 15:10, Felix Ernst
> (<[hidden email]>) escribió:
>>
>> Dear all,
>>
>> I a bit unsure, whether this qualifies as a bug, but it is definitly a strange behaviour. That why I wanted to discuss it.
>>
>> With the following function, I want to test for evenly space numbers, starting from anywhere.
>>
>> .is_continous_evenly_spaced <- function(n){
>>  if(length(n) < 2) return(FALSE)
>>  n <- n[order(n)]
>>  n <- n - min(n)
>>  step <- n[2] - n[1]
>>  test <- seq(from = min(n), to = max(n), by = step)
>>  if(length(n) == length(test) &&
>>     all(n == test)){
>>    return(TRUE)
>>  }
>>  return(FALSE)
>> }
>>
>>> .is_continous_evenly_spaced(c(1,2,3,4))
>> [1] TRUE
>>> .is_continous_evenly_spaced(c(1,3,4,5))
>> [1] FALSE
>>> .is_continous_evenly_spaced(c(1,1.1,1.2,1.3))
>> [1] FALSE
>>
>> I expect the result for 1 and 2, but not for 3. Upon Investigation it turns out, that n == test is TRUE for every pair, but not for the pair of 0.2.
>>
>> The types reported are always double, however n[2] == 0.1 reports FALSE as well.
>>
>> The whole problem is solved by switching from all(n == test) to all(as.character(n) == as.character(test)). However that is weird, isn’t it?
>>
>> Does this work as intended? Thanks for any help, advise and suggestions in advance.
>
> I guess this has something to do with how the sequence is built and
> the inherent error of floating point arithmetic. In fact, if you
> return test minus n, you'll get:
>
> [1] 0.000000e+00 0.000000e+00 2.220446e-16 0.000000e+00
>
> and the error gets bigger when you continue the sequence; e.g., this
> is for c(1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7):
>
> [1] 0.000000e+00 0.000000e+00 2.220446e-16 2.220446e-16 4.440892e-16
> [6] 4.440892e-16 4.440892e-16 0.000000e+00
>
> So, independently of this is considered a bug or not, instead of
>
> length(n) == length(test) && all(n == test)
>
> I would use the following condition:
>
> isTRUE(all.equal(n, test))
>
> Iñaki
>
>>
>> Best regards,
>> Felix


Hi,

This is essentially FAQ 7.31:

  https://cran.r-project.org/doc/FAQ/R-FAQ.html#Why-doesn_0027t-R-think-these-numbers-are-equal_003f <https://cran.r-project.org/doc/FAQ/R-FAQ.html#Why-doesn_0027t-R-think-these-numbers-are-equal_003f>

Review that and the references therein to gain some insights into binary representations of floating point numbers.

Rather than the more complicated code you have above, try the following:

evenlyspaced <- function(x) {
  gaps <- diff(sort(x))
  all(gaps[-1] == gaps[1])
}

Note the use of ?diff:

> diff(c(1, 2, 3, 4))
[1] 1 1 1

> diff(c(1, 3, 4, 5))
[1] 2 1 1

> diff(c(1, 1.1, 1.2, 1.3))
[1] 0.1 0.1 0.1

However, in reality, due to the floating point representation issues noted above:

> print(diff(c(1, 1.1, 1.2, 1.3)), 20)
[1] 0.100000000000000088818 0.099999999999999866773
[3] 0.100000000000000088818

So the differences between the numbers are not exactly 0.1.

Using the function above, you get:

> evenlyspaced(c(1, 2, 3, 4))
[1] TRUE

> evenlyspaced(c(1, 3, 4, 5))
[1] FALSE

> evenlyspaced(c(1, 1.1, 1.2, 1.3))
[1] FALSE

As has been noted, if you want the gap comparison to be based upon some margin of error, use ?all.equal rather than the explicit equals comparison that I have in the function above. Something along the lines of:

evenlyspaced <- function(x) {
  gaps <- diff(sort(x))
  all(sapply(gaps[-1], function(x) all.equal(x, gaps[1])))
}

On which case, you now get:

evenlyspaced(c(1, 1.1, 1.2, 1.3))
[1] TRUE


Regards,

Marc Schwartz


        [[alternative HTML version deleted]]

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: compairing doubles

Mark van der Loo
In reply to this post by Mark van der Loo
Sorry for the second e-mail: this is worth watching:
https://www.youtube.com/watch?v=3Bu7QUxzIbA&t=1s
It's Martin Maechler's talk at useR!2018. This kind of stuff should be
mandatory material for any aspiring programmer/data scientist/statistician.

-Mark




Op vr 31 aug. 2018 om 16:00 schreef Mark van der Loo <
[hidden email]>:

> how about
>
> is_evenly_spaced <- function(x,...) all.equal(diff(sort(x)),...)
>
> (use ellipsis to set tolerance if necessary)
>
>
> Op vr 31 aug. 2018 om 15:46 schreef Emil Bode <[hidden email]>:
>
>> Agreed that's it's rounding error, and all.equal would be the way to go.
>> I wouldn't call it a bug, it's simply part of working with floating point
>> numbers, any language has the same issue.
>>
>> And while we're at it, I think the function can be a lot shorter:
>> .is_continous_evenly_spaced <- function(n){
>>   length(n)>1 && isTRUE(all.equal(n[order(n)], seq(from=min(n),
>> to=max(n), length.out = length(n))))
>> }
>>
>> Cheers, Emil
>>
>>     El vie., 31 ago. 2018 a las 15:10, Felix Ernst
>>     (<[hidden email]>) escribió:
>>     >
>>     > Dear all,
>>     >
>>     > I a bit unsure, whether this qualifies as a bug, but it is
>> definitly a strange behaviour. That why I wanted to discuss it.
>>     >
>>     > With the following function, I want to test for evenly space
>> numbers, starting from anywhere.
>>     >
>>     > .is_continous_evenly_spaced <- function(n){
>>     >   if(length(n) < 2) return(FALSE)
>>     >   n <- n[order(n)]
>>     >   n <- n - min(n)
>>     >   step <- n[2] - n[1]
>>     >   test <- seq(from = min(n), to = max(n), by = step)
>>     >   if(length(n) == length(test) &&
>>     >      all(n == test)){
>>     >     return(TRUE)
>>     >   }
>>     >   return(FALSE)
>>     > }
>>     >
>>     > > .is_continous_evenly_spaced(c(1,2,3,4))
>>     > [1] TRUE
>>     > > .is_continous_evenly_spaced(c(1,3,4,5))
>>     > [1] FALSE
>>     > > .is_continous_evenly_spaced(c(1,1.1,1.2,1.3))
>>     > [1] FALSE
>>     >
>>     > I expect the result for 1 and 2, but not for 3. Upon Investigation
>> it turns out, that n == test is TRUE for every pair, but not for the pair
>> of 0.2.
>>     >
>>     > The types reported are always double, however n[2] == 0.1 reports
>> FALSE as well.
>>     >
>>     > The whole problem is solved by switching from all(n == test) to
>> all(as.character(n) == as.character(test)). However that is weird, isn’t it?
>>     >
>>     > Does this work as intended? Thanks for any help, advise and
>> suggestions in advance.
>>
>>     I guess this has something to do with how the sequence is built and
>>     the inherent error of floating point arithmetic. In fact, if you
>>     return test minus n, you'll get:
>>
>>     [1] 0.000000e+00 0.000000e+00 2.220446e-16 0.000000e+00
>>
>>     and the error gets bigger when you continue the sequence; e.g., this
>>     is for c(1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7):
>>
>>     [1] 0.000000e+00 0.000000e+00 2.220446e-16 2.220446e-16 4.440892e-16
>>     [6] 4.440892e-16 4.440892e-16 0.000000e+00
>>
>>     So, independently of this is considered a bug or not, instead of
>>
>>     length(n) == length(test) && all(n == test)
>>
>>     I would use the following condition:
>>
>>     isTRUE(all.equal(n, test))
>>
>>     Iñaki
>>
>>     >
>>     > Best regards,
>>     > Felix
>>     >
>>     >
>>     >         [[alternative HTML version deleted]]
>>     >
>>     > ______________________________________________
>>     > [hidden email] mailing list
>>     > https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>>
>>
>>     --
>>     Iñaki Ucar
>>
>>     ______________________________________________
>>     [hidden email] mailing list
>>     https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>>
>> ______________________________________________
>> [hidden email] mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>

        [[alternative HTML version deleted]]

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: compairing doubles

Iñaki Ucar
In reply to this post by Mark van der Loo
El vie., 31 ago. 2018 a las 16:00, Mark van der Loo
(<[hidden email]>) escribió:
>
> how about
>
> is_evenly_spaced <- function(x,...) all.equal(diff(sort(x)),...)

This doesn't work, because

1. all.equal does *not* return FALSE. Use of isTRUE or identical(.,
TRUE) is required if you want a boolean.
2. all.equal compares two objects, not elements in a vector.

Iñaki

>
> (use ellipsis to set tolerance if necessary)
>
>
> Op vr 31 aug. 2018 om 15:46 schreef Emil Bode <[hidden email]>:
>>
>> Agreed that's it's rounding error, and all.equal would be the way to go.
>> I wouldn't call it a bug, it's simply part of working with floating point numbers, any language has the same issue.
>>
>> And while we're at it, I think the function can be a lot shorter:
>> .is_continous_evenly_spaced <- function(n){
>>   length(n)>1 && isTRUE(all.equal(n[order(n)], seq(from=min(n), to=max(n), length.out = length(n))))
>> }
>>
>> Cheers, Emil
>>
>>     El vie., 31 ago. 2018 a las 15:10, Felix Ernst
>>     (<[hidden email]>) escribió:
>>     >
>>     > Dear all,
>>     >
>>     > I a bit unsure, whether this qualifies as a bug, but it is definitly a strange behaviour. That why I wanted to discuss it.
>>     >
>>     > With the following function, I want to test for evenly space numbers, starting from anywhere.
>>     >
>>     > .is_continous_evenly_spaced <- function(n){
>>     >   if(length(n) < 2) return(FALSE)
>>     >   n <- n[order(n)]
>>     >   n <- n - min(n)
>>     >   step <- n[2] - n[1]
>>     >   test <- seq(from = min(n), to = max(n), by = step)
>>     >   if(length(n) == length(test) &&
>>     >      all(n == test)){
>>     >     return(TRUE)
>>     >   }
>>     >   return(FALSE)
>>     > }
>>     >
>>     > > .is_continous_evenly_spaced(c(1,2,3,4))
>>     > [1] TRUE
>>     > > .is_continous_evenly_spaced(c(1,3,4,5))
>>     > [1] FALSE
>>     > > .is_continous_evenly_spaced(c(1,1.1,1.2,1.3))
>>     > [1] FALSE
>>     >
>>     > I expect the result for 1 and 2, but not for 3. Upon Investigation it turns out, that n == test is TRUE for every pair, but not for the pair of 0.2.
>>     >
>>     > The types reported are always double, however n[2] == 0.1 reports FALSE as well.
>>     >
>>     > The whole problem is solved by switching from all(n == test) to all(as.character(n) == as.character(test)). However that is weird, isn’t it?
>>     >
>>     > Does this work as intended? Thanks for any help, advise and suggestions in advance.
>>
>>     I guess this has something to do with how the sequence is built and
>>     the inherent error of floating point arithmetic. In fact, if you
>>     return test minus n, you'll get:
>>
>>     [1] 0.000000e+00 0.000000e+00 2.220446e-16 0.000000e+00
>>
>>     and the error gets bigger when you continue the sequence; e.g., this
>>     is for c(1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7):
>>
>>     [1] 0.000000e+00 0.000000e+00 2.220446e-16 2.220446e-16 4.440892e-16
>>     [6] 4.440892e-16 4.440892e-16 0.000000e+00
>>
>>     So, independently of this is considered a bug or not, instead of
>>
>>     length(n) == length(test) && all(n == test)
>>
>>     I would use the following condition:
>>
>>     isTRUE(all.equal(n, test))
>>
>>     Iñaki
>>
>>     >
>>     > Best regards,
>>     > Felix
>>     >
>>     >
>>     >         [[alternative HTML version deleted]]
>>     >
>>     > ______________________________________________
>>     > [hidden email] mailing list
>>     > https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>>
>>
>>     --
>>     Iñaki Ucar
>>
>>     ______________________________________________
>>     [hidden email] mailing list
>>     https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>>
>> ______________________________________________
>> [hidden email] mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-devel



--
Iñaki Ucar

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: compairing doubles

Mark van der Loo
Ah, my bad, you're right of course.

sum(abs(diff(diff( sort(x))))) < eps

for some reasonable eps then, would do as a oneliner, or

all(abs(diff(diff(sort(x)))) < eps)

or

max(abs(diff(diff(sort(x))))) < eps


-Mark

Op vr 31 aug. 2018 om 16:14 schreef Iñaki Ucar <[hidden email]>:

> El vie., 31 ago. 2018 a las 16:00, Mark van der Loo
> (<[hidden email]>) escribió:
> >
> > how about
> >
> > is_evenly_spaced <- function(x,...) all.equal(diff(sort(x)),...)
>
> This doesn't work, because
>
> 1. all.equal does *not* return FALSE. Use of isTRUE or identical(.,
> TRUE) is required if you want a boolean.
> 2. all.equal compares two objects, not elements in a vector.
>
> Iñaki
>
> >
> > (use ellipsis to set tolerance if necessary)
> >
> >
> > Op vr 31 aug. 2018 om 15:46 schreef Emil Bode <[hidden email]>:
> >>
> >> Agreed that's it's rounding error, and all.equal would be the way to go.
> >> I wouldn't call it a bug, it's simply part of working with floating
> point numbers, any language has the same issue.
> >>
> >> And while we're at it, I think the function can be a lot shorter:
> >> .is_continous_evenly_spaced <- function(n){
> >>   length(n)>1 && isTRUE(all.equal(n[order(n)], seq(from=min(n),
> to=max(n), length.out = length(n))))
> >> }
> >>
> >> Cheers, Emil
> >>
> >>     El vie., 31 ago. 2018 a las 15:10, Felix Ernst
> >>     (<[hidden email]>) escribió:
> >>     >
> >>     > Dear all,
> >>     >
> >>     > I a bit unsure, whether this qualifies as a bug, but it is
> definitly a strange behaviour. That why I wanted to discuss it.
> >>     >
> >>     > With the following function, I want to test for evenly space
> numbers, starting from anywhere.
> >>     >
> >>     > .is_continous_evenly_spaced <- function(n){
> >>     >   if(length(n) < 2) return(FALSE)
> >>     >   n <- n[order(n)]
> >>     >   n <- n - min(n)
> >>     >   step <- n[2] - n[1]
> >>     >   test <- seq(from = min(n), to = max(n), by = step)
> >>     >   if(length(n) == length(test) &&
> >>     >      all(n == test)){
> >>     >     return(TRUE)
> >>     >   }
> >>     >   return(FALSE)
> >>     > }
> >>     >
> >>     > > .is_continous_evenly_spaced(c(1,2,3,4))
> >>     > [1] TRUE
> >>     > > .is_continous_evenly_spaced(c(1,3,4,5))
> >>     > [1] FALSE
> >>     > > .is_continous_evenly_spaced(c(1,1.1,1.2,1.3))
> >>     > [1] FALSE
> >>     >
> >>     > I expect the result for 1 and 2, but not for 3. Upon
> Investigation it turns out, that n == test is TRUE for every pair, but not
> for the pair of 0.2.
> >>     >
> >>     > The types reported are always double, however n[2] == 0.1 reports
> FALSE as well.
> >>     >
> >>     > The whole problem is solved by switching from all(n == test) to
> all(as.character(n) == as.character(test)). However that is weird, isn’t it?
> >>     >
> >>     > Does this work as intended? Thanks for any help, advise and
> suggestions in advance.
> >>
> >>     I guess this has something to do with how the sequence is built and
> >>     the inherent error of floating point arithmetic. In fact, if you
> >>     return test minus n, you'll get:
> >>
> >>     [1] 0.000000e+00 0.000000e+00 2.220446e-16 0.000000e+00
> >>
> >>     and the error gets bigger when you continue the sequence; e.g., this
> >>     is for c(1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7):
> >>
> >>     [1] 0.000000e+00 0.000000e+00 2.220446e-16 2.220446e-16 4.440892e-16
> >>     [6] 4.440892e-16 4.440892e-16 0.000000e+00
> >>
> >>     So, independently of this is considered a bug or not, instead of
> >>
> >>     length(n) == length(test) && all(n == test)
> >>
> >>     I would use the following condition:
> >>
> >>     isTRUE(all.equal(n, test))
> >>
> >>     Iñaki
> >>
> >>     >
> >>     > Best regards,
> >>     > Felix
> >>     >
> >>     >
> >>     >         [[alternative HTML version deleted]]
> >>     >
> >>     > ______________________________________________
> >>     > [hidden email] mailing list
> >>     > https://stat.ethz.ch/mailman/listinfo/r-devel
> >>
> >>
> >>
> >>     --
> >>     Iñaki Ucar
> >>
> >>     ______________________________________________
> >>     [hidden email] mailing list
> >>     https://stat.ethz.ch/mailman/listinfo/r-devel
> >>
> >>
> >> ______________________________________________
> >> [hidden email] mailing list
> >> https://stat.ethz.ch/mailman/listinfo/r-devel
>
>
>
> --
> Iñaki Ucar
>

        [[alternative HTML version deleted]]

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: compairing doubles

Serguei Sokol
Le 31/08/2018 à 16:25, Mark van der Loo a écrit :

> Ah, my bad, you're right of course.
>
> sum(abs(diff(diff( sort(x))))) < eps
>
> for some reasonable eps then, would do as a oneliner, or
>
> all(abs(diff(diff(sort(x)))) < eps)
>
> or
>
> max(abs(diff(diff(sort(x))))) < eps
Or with only four function calls:
diff(range(diff(sort(x)))) < eps

Serguei.

>
>
> -Mark
>
> Op vr 31 aug. 2018 om 16:14 schreef Iñaki Ucar <[hidden email]>:
>
>> El vie., 31 ago. 2018 a las 16:00, Mark van der Loo
>> (<[hidden email]>) escribió:
>>> how about
>>>
>>> is_evenly_spaced <- function(x,...) all.equal(diff(sort(x)),...)
>> This doesn't work, because
>>
>> 1. all.equal does *not* return FALSE. Use of isTRUE or identical(.,
>> TRUE) is required if you want a boolean.
>> 2. all.equal compares two objects, not elements in a vector.
>>
>> Iñaki
>>
>>> (use ellipsis to set tolerance if necessary)
>>>
>>>
>>> Op vr 31 aug. 2018 om 15:46 schreef Emil Bode <[hidden email]>:
>>>> Agreed that's it's rounding error, and all.equal would be the way to go.
>>>> I wouldn't call it a bug, it's simply part of working with floating
>> point numbers, any language has the same issue.
>>>> And while we're at it, I think the function can be a lot shorter:
>>>> .is_continous_evenly_spaced <- function(n){
>>>>    length(n)>1 && isTRUE(all.equal(n[order(n)], seq(from=min(n),
>> to=max(n), length.out = length(n))))
>>>> }
>>>>
>>>> Cheers, Emil
>>>>
>>>>      El vie., 31 ago. 2018 a las 15:10, Felix Ernst
>>>>      (<[hidden email]>) escribió:
>>>>      >
>>>>      > Dear all,
>>>>      >
>>>>      > I a bit unsure, whether this qualifies as a bug, but it is
>> definitly a strange behaviour. That why I wanted to discuss it.
>>>>      >
>>>>      > With the following function, I want to test for evenly space
>> numbers, starting from anywhere.
>>>>      >
>>>>      > .is_continous_evenly_spaced <- function(n){
>>>>      >   if(length(n) < 2) return(FALSE)
>>>>      >   n <- n[order(n)]
>>>>      >   n <- n - min(n)
>>>>      >   step <- n[2] - n[1]
>>>>      >   test <- seq(from = min(n), to = max(n), by = step)
>>>>      >   if(length(n) == length(test) &&
>>>>      >      all(n == test)){
>>>>      >     return(TRUE)
>>>>      >   }
>>>>      >   return(FALSE)
>>>>      > }
>>>>      >
>>>>      > > .is_continous_evenly_spaced(c(1,2,3,4))
>>>>      > [1] TRUE
>>>>      > > .is_continous_evenly_spaced(c(1,3,4,5))
>>>>      > [1] FALSE
>>>>      > > .is_continous_evenly_spaced(c(1,1.1,1.2,1.3))
>>>>      > [1] FALSE
>>>>      >
>>>>      > I expect the result for 1 and 2, but not for 3. Upon
>> Investigation it turns out, that n == test is TRUE for every pair, but not
>> for the pair of 0.2.
>>>>      >
>>>>      > The types reported are always double, however n[2] == 0.1 reports
>> FALSE as well.
>>>>      >
>>>>      > The whole problem is solved by switching from all(n == test) to
>> all(as.character(n) == as.character(test)). However that is weird, isn’t it?
>>>>      >
>>>>      > Does this work as intended? Thanks for any help, advise and
>> suggestions in advance.
>>>>      I guess this has something to do with how the sequence is built and
>>>>      the inherent error of floating point arithmetic. In fact, if you
>>>>      return test minus n, you'll get:
>>>>
>>>>      [1] 0.000000e+00 0.000000e+00 2.220446e-16 0.000000e+00
>>>>
>>>>      and the error gets bigger when you continue the sequence; e.g., this
>>>>      is for c(1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7):
>>>>
>>>>      [1] 0.000000e+00 0.000000e+00 2.220446e-16 2.220446e-16 4.440892e-16
>>>>      [6] 4.440892e-16 4.440892e-16 0.000000e+00
>>>>
>>>>      So, independently of this is considered a bug or not, instead of
>>>>
>>>>      length(n) == length(test) && all(n == test)
>>>>
>>>>      I would use the following condition:
>>>>
>>>>      isTRUE(all.equal(n, test))
>>>>
>>>>      Iñaki
>>>>
>>>>      >
>>>>      > Best regards,
>>>>      > Felix
>>>>      >
>>>>      >
>>>>      >         [[alternative HTML version deleted]]
>>>>      >
>>>>      > ______________________________________________
>>>>      > [hidden email] mailing list
>>>>      > https://stat.ethz.ch/mailman/listinfo/r-devel
>>>>
>>>>
>>>>
>>>>      --
>>>>      Iñaki Ucar
>>>>
>>>>      ______________________________________________
>>>>      [hidden email] mailing list
>>>>      https://stat.ethz.ch/mailman/listinfo/r-devel
>>>>
>>>>
>>>> ______________________________________________
>>>> [hidden email] mailing list
>>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>>
>> --
>> Iñaki Ucar
>>
> [[alternative HTML version deleted]]
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>


--
Serguei Sokol
Ingenieur de recherche INRA

Cellule mathématiques
LISBP, INSA/INRA UMR 792, INSA/CNRS UMR 5504
135 Avenue de Rangueil
31077 Toulouse Cedex 04

tel: +33 5 62 25 01 27
email: [hidden email]
http://www.lisbp.fr

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: compairing doubles

Iñaki Ucar
El vie., 31 ago. 2018 a las 17:08, Serguei Sokol
(<[hidden email]>) escribió:

>
> Le 31/08/2018 à 16:25, Mark van der Loo a écrit :
> > Ah, my bad, you're right of course.
> >
> > sum(abs(diff(diff( sort(x))))) < eps
> >
> > for some reasonable eps then, would do as a oneliner, or
> >
> > all(abs(diff(diff(sort(x)))) < eps)
> >
> > or
> >
> > max(abs(diff(diff(sort(x))))) < eps
> Or with only four function calls:
> diff(range(diff(sort(x)))) < eps

We may have a winner... :)

Iñaki

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: compairing doubles

Juan Telleria Ruiz de Aguirre
Maybe a new Operator could be defined for a fast and easy double
Comparison: `~~`

`~~` <- function (e1, e2)  all.equal(e1, e2)

And document it properly.

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: compairing doubles

Rui Barradas
Hello,

Watch out for operator precedence.



all.equal(0.3, 0.1*3)
#[1] TRUE


`%~~%` <- function (e1, e2)  all.equal(e1, e2)

0.3 %~~% 0.1*3
#Error in 0.3 %~~% 0.1 * 3 : argumento não-numérico para operador binário


0.3 %~~% (0.1*3)
#[1] TRUE


Now with isTRUE. The problem changes a bit.


isTRUE(all.equal(0.3, 0.1*3))
#[1] TRUE


`%~~%` <- function (e1, e2)  isTRUE(all.equal(e1, e2))

0.3 %~~% 0.1*3
#[1] 0

0.3 %~~% (0.1*3)
#[1] TRUE


Hope this helps,

Rui Barradas

Às 08:20 de 03/09/2018, Juan Telleria Ruiz de Aguirre escreveu:

> Maybe a new Operator could be defined for a fast and easy double
> Comparison: `~~`
>
> `~~` <- function (e1, e2)  all.equal(e1, e2)
>
> And document it properly.
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: compairing doubles

Martin Maechler
>>>>> Rui Barradas
>>>>>     on Mon, 3 Sep 2018 09:58:34 +0100 writes:

    > Hello, Watch out for operator precedence.

indeed!  (but not only)

> all.equal(0.3, 0.1*3)
> #[1] TRUE
>
>
> `%~~%` <- function (e1, e2)  all.equal(e1, e2)
>
> 0.3 %~~% 0.1*3
> #Error in 0.3 %~~% 0.1 * 3 : argumento não-numérico para operador binário
>
>
> 0.3 %~~% (0.1*3)
> #[1] TRUE
>
>
> Now with isTRUE. The problem changes a bit.
>
>
> isTRUE(all.equal(0.3, 0.1*3))
> #[1] TRUE
>
>
> `%~~%` <- function (e1, e2)  isTRUE(all.equal(e1, e2))
>
> 0.3 %~~% 0.1*3
> #[1] 0
>
> 0.3 %~~% (0.1*3)
> #[1] TRUE
>

> Hope this helps,
> Rui Barradas
>
> Às 08:20 de 03/09/2018, Juan Telleria Ruiz de Aguirre escreveu:
> > Maybe a new Operator could be defined for a fast and easy double
> > Comparison: `~~`
> >
> > `~~` <- function (e1, e2)  all.equal(e1, e2)
> >
> > And document it properly.
> >

I would still quite strongly recommend against such a
definition:

If you ask for  help(all.equal)
you do see that it is a generic with a   all.equal.numeric()
method which has several extra arguments
(new ones even in R-devel)  the most important one being the
numerical  'tolerance'  with a default of
sqrt(.Machine$double.eps)  { == 2^-26 == 1.490116e-08  on all current platforms}

Of course there is some arbitraryness in that choice
{{ but only *some*: the default is related to finding the minimum of
   smooth function which hence is locally quadratic at a "decent"
   minimum hence sqrt(.)
}}
but I find it important sometimes to increase the equality
strictness of that tolerance.

Hiding everything behind a new operator which does not allow to
take into account that there are quite a few versions of
near-equality --- only partly) mirrored by the existence of
extra arguments of all.equal() --- only encourages simplified
thinking about the underlying subtle issues  which already too
many people don't care to know about.

(( e.g. all those people only caring for speed, but not for
   accuracy and reliability ... ))

Martin Maechler
ETH Zurich and R Core

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel