[Rd] Undefined behavior of head() and tail() with n = 0

Florent Angly florent.angly at gmail.com
Fri Jan 27 10:24:39 CET 2017


Martin, I agree with you that +0 and -0 should generally be treated as
equal, and R does a fine job in this respect. The Wikipedia article on
signed zero (https://en.wikipedia.org/wiki/Signed_zero) echoes this
view but also highlights that +0 and -0 can be treated differently in
particular situations, including their interpretation as mathematical
limits (as in the 1/-0 case). Indeed, the main question here is
whether head() and tail() represent a special case that would benefit
from differentiating between +0 and -0.

We can break down the discussion into two problems:
A/ the discrepancy between the implementation of R head() and tail()
and the documentation of these functions (where the use of zero is not
documented and thus not permissible),
B/ the discrepancy between the implementation of R head() and tail()
and their GNU equivalent (which allow zeros and differentiate between
-0 and +0, i.e. head takes "0" and "-0", tail takes "0" and "+0").

There are several possible solutions to address these discrepancies:

1/ Leave the code as-is but document its behavior with respect to zero
(zeros allowed, with negative zeros treated like positive zeros).
Advantages: This is the path of least resistance, and discrepancy A is fixed.
Disadvantages: Discrepancy B remains (but is documented).

2/ Leave the documentation as-is but reflect this in code by not
allowing zeros at all.
Advantages: Discrepancy A is fixed.
Disadvantages: Discrepancy B remains in some form (but is documented).
Need to deprecate the usage of +0 (which was not clearly documented
but may have been assumed by users).

3/ Update the code and documentation to differentiate between +0 and -0.
Advantages: In my eyes, this is the ideal solution since discrepancy A
and (most of) B are resolved.
Disadvantages: It is unclear how to implement this solution and the
implications it may have on backward compatibility:
   a/ Allow -0 (as double). But is it supported on all platforms used
by R (see ?Arithmetic)? William has raised the issue that negative
zero cannot be represented as an integer. Should head() and tail()
then strictly check double input (while forbidding integers)?
   b/ The input could always be as character. This would allow to
mirror even more closely GNU tail (where the prefix "+" is used to
invert the meaning of n). This probably involves a fair amount of work
and careful handling of deprecation.



On 26 January 2017 at 16:51, William Dunlap <wdunlap at tibco.com> wrote:
> In addition, signed zeroes only exist for floating point numbers - the
> bit patterns for as.integer(0) and as.integer(-0) are identical.
> Bill Dunlap
> TIBCO Software
> wdunlap tibco.com
>
>
> On Thu, Jan 26, 2017 at 1:53 AM, Martin Maechler
> <maechler at stat.math.ethz.ch> wrote:
>>>>>>> Florent Angly <florent.angly at gmail.com>
>>>>>>>     on Wed, 25 Jan 2017 16:31:45 +0100 writes:
>>
>>     > Hi all,
>>     > The documentation for head() and tail() describes the behavior of
>>     > these generic functions when n is strictly positive (n > 0) and
>>     > strictly negative (n < 0). How these functions work when given a zero
>>     > value is not defined.
>>
>>     > Both GNU command-line utilities head and tail behave differently with +0 and -0:
>>     > http://man7.org/linux/man-pages/man1/head.1.html
>>     > http://man7.org/linux/man-pages/man1/tail.1.html
>>
>>     > Since R supports signed zeros (1/+0 != 1/-0)
>>
>> whoa, whoa, .. slow down --  The above is misleading!
>>
>> Rather read in  ?Arithmetic (*the* reference to consult for such issues),
>> where the 2nd part of the following section
>>
>>  || Implementation limits:
>>  ||
>>  ||      [..............]
>>  ||
>>  ||      Another potential issue is signed zeroes: on IEC 60659 platforms
>>  ||      there are two zeroes with internal representations differing by
>>  ||      sign.  Where possible R treats them as the same, but for example
>>  ||      direct output from C code often does not do so and may output
>>  ||      ‘-0.0’ (and on Windows whether it does so or not depends on the
>>  ||      version of Windows).  One place in R where the difference might be
>>  ||      seen is in division by zero: ‘1/x’ is ‘Inf’ or ‘-Inf’ depending on
>>  ||      the sign of zero ‘x’.  Another place is ‘identical(0, -0, num.eq =
>>  ||      FALSE)’.
>>
>> says the *contrary* ( __Where possible R treats them as the same__ ):
>> We do _not_ want to distinguish -0 and +0,
>> but there are cases where it is inavoidable
>>
>> And there are good reasons (mathematics !!) for this.
>>
>> I'm pretty sure that it would be quite a mistake to start
>> differentiating it here...  but of course we can continue
>> discussing here if you like.
>>
>> Martin Maechler
>> ETH Zurich and R Core
>>
>>
>>     > and the R head() and tail() functions are modeled after
>>     > their GNU counterparts, I would expect the R functions to
>>     > distinguish between +0 and -0
>>
>>     >> tail(1:5, n=0)
>>     > integer(0)
>>     >> tail(1:5, n=1)
>>     > [1] 5
>>     >> tail(1:5, n=2)
>>     > [1] 4 5
>>
>>     >> tail(1:5, n=-2)
>>     > [1] 3 4 5
>>     >> tail(1:5, n=-1)
>>     > [1] 2 3 4 5
>>     >> tail(1:5, n=-0)
>>     > integer(0)  # expected 1:5
>>
>>     >> head(1:5, n=0)
>>     > integer(0)
>>     >> head(1:5, n=1)
>>     > [1] 1
>>     >> head(1:5, n=2)
>>     > [1] 1 2
>>
>>     >> head(1:5, n=-2)
>>     > [1] 1 2 3
>>     >> head(1:5, n=-1)
>>     > [1] 1 2 3 4
>>     >> head(1:5, n=-0)
>>     > integer(0)  # expected 1:5
>>
>>     > For both head() and tail(), I expected 1:5 as output but got
>>     > integer(0). I obtained similar results using a data.frame and a
>>     > function as x argument.
>>
>>     > An easy fix would be to explicitly state in the documentation what n =
>>     > 0 does, and that there is no practical difference between -0 and +0.
>>     > However, in my eyes, the better approach would be implement support
>>     > for -0 and document it. What do you think?
>>
>>     > Best,
>>
>>     > Florent
>>
>>
>>     > PS/ My sessionInfo() gives:
>>     > R version 3.3.2 (2016-10-31)
>>     > Platform: x86_64-w64-mingw32/x64 (64-bit)
>>     > Running under: Windows 7 x64 (build 7601) Service Pack 1
>>
>>     > locale:
>>     > [1] LC_COLLATE=German_Switzerland.1252
>>     > LC_CTYPE=German_Switzerland.1252
>>     > LC_MONETARY=German_Switzerland.1252 LC_NUMERIC=C
>>     > LC_TIME=German_Switzerland.1252
>>
>>     > attached base packages:
>>     > [1] stats     graphics  grDevices utils     datasets  methods   base
>>
>>     > ______________________________________________
>>     > R-devel at r-project.org mailing list
>>     > https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>> ______________________________________________
>> R-devel at r-project.org mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-devel



More information about the R-devel mailing list