[R] customize the step value

Duncan Murdoch murdoch@dunc@n @end|ng |rom gm@||@com
Fri Oct 29 18:03:08 CEST 2021


On 29/10/2021 11:04 a.m., Martin Maechler wrote:
>>>>>> Duncan Murdoch
>>>>>>      on Fri, 29 Oct 2021 09:07:31 -0400 writes:
> 
>      > On 29/10/2021 4:34 a.m., PIKAL Petr wrote:
>      >> Hi
>      >>
>      >> One has to be careful when using fractions in seq step.
>      >>
>      >> Although it works for 0.5
>      >>> (seq(0,10, .5) - round(seq(0,10,.5),2))==0
>      >> [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
>      >> TRUE
>      >> [16] TRUE TRUE TRUE TRUE TRUE TRUE
>      >>
>      >> in case of 0.3 (or others) it does not always result in expected values (see
>      >> FAQ 7.31 for explanation)
>      >>
>      >>> (seq(0,10, .3) - round(seq(0,10,.3),2))==0
>      >> [1]  TRUE  TRUE  TRUE FALSE  TRUE  TRUE FALSE  TRUE  TRUE FALSE  TRUE  TRUE
>      >> [13] FALSE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE FALSE
>      >> [25] FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE
> 
> 
>      > Petr is right, it's unsafe to use fractional values for the step.  0.5
>      > works because it has a power of 2 in the denominator and so does the
>      > start value, but it's easy to make mistakes when you rely on that (e.g.
>      > changing the step size from 0.5 to 0.3 would break things).
> 
>      > A better idea is to modify a sequence of integers.  For example, to get
>      > 1.5 to 3.5 by 0.5, you can do (3:7)*0.5, and for 0 to 3 by 0.3, use
>      > (0:10)*0.3.
> 
> 
> Well, but you will not get truly equidistant (to the last bit)
> sequences also by that and people who are not aware of
> FAQ 7.31  and its consequences do wrongly assume that

No, that would be impossible.

> 
> length(unique(diff(seqVec))) == 1
> 
> for any      seqVec <-  k * seq(....)   # k a "scalar" (of length 1)
> 
> but the reality of floating point arithmetic can be quite
> different than pure math :
> 
> In this case and on my platform the two ways to construct the
> sequence are even identical:
> 
>> identical((0:10)*0.3, seq(0, 3, by=.3))
> [1] TRUE
>> sv <- (0:10)*0.3
>> length(unique(diff(sv))) # you'd like |-->  1 (the number 0.3 !)
> [1] 5

But I suspect that's not guaranteed for every step size.

The really serious problem (which R tries hard to avoid, but again I 
doubt it's guaranteed) is to ask for

   seq(a, b, step = (b-a)/n)

for an integer n and get a sequence that stops one step early and 
doesn't include b.   For this case, I would always use the replacement

   a + (0:n)*(b - a)/n

I suspect this is also not guaranteed to return b, but it is guaranteed 
to return a value very close to it.

Duncan Murdoch



More information about the R-help mailing list