3

Per the docs, "on a typical R platform the smallest positive double is about 5e-324." Given a double vector with values above, near, and below this limit:

library(tibble)

small_vec <- c(4e-300, 4e-324, 4e-350)
small_df <- data.frame(x = small_vec)
small_tibble <- tibble(x = small_vec)

Printing small_vec and small_df give about what I'd expect:

small_vec
#> [1] 4.000000e-300 4.940656e-324  0.000000e+00

small_df
#>               x
#> 1 4.000000e-300
#> 2 4.940656e-324
#> 3  0.000000e+00

The second value isn't quite right, which I vaguely understand is due to floating point weirdness. The third number underflows to 0. Fine. But printing as a tibble,

small_tibble
#> # A tibble: 3 × 1
#>           x
#>       <dbl>
#> 1   4 e-300
#> 2 Inf.e-324
#> 3   0

Created on 2022-10-19 with reprex v2.0.2

I'm thrown by Inf.e-324 -- both the idea of Inf with an exponent, and the decimal point. What does this signify? Or is it possibly a bug in the tibble package?

zephryl
  • 14,633
  • 3
  • 11
  • 30

2 Answers2

3

(A little long for a comment.)

Sure seems like a bug, but I think it's not in tibble per se, but in the pillar package underneath. library(pillar); pillar_shaft(small_vec) shows the same pathology. Digging down: looking at pillar:::format.pillar_shaft_decimal(), it uses the $sci component of this object. That component looks fishy:

> pillar_shaft(small_vec)$sci

[harmless-looking stuff]

$lhs
[1] "4"   "Inf" "0"  

$lhs_zero
[1] FALSE FALSE  TRUE

$rhs
[1]   0 NaN   0

[harmless-looking stuff]

So we probably have to see what pillar_shaft is doing during the conversion.

Specifically in

pillar:::pillar_shaft_number_attr(small_vec, NULL, NULL)

which goes to pillar_shaft_number which seems to lead to

pillar:::split_decimal(small_vec, sigfig = 3, digits = NULL)

but, weirdly enough, that one looks OK, so I must have lost the plot somewhere.

Ben Bolker
  • 211,554
  • 25
  • 370
  • 453
1

There is a bug report filled in github. In the meantime, this (not exhaustively tested) hack could work:

library(tibble)

print(tibble(x = c(4e-300, 4e-324, 4e324, 10, -10, 4e-350)))
#> # A tibble: 6 × 1
#>           x
#>       <dbl>
#> 1   4 e-300
#> 2 Inf.e-324
#> 3 Inf      
#> 4   1 e+  1
#> 5  -1 e+  1
#> 6   0

assignInNamespace("safe_divide_10_to", 
                  function(x,y) 10^(log10(x) - y), "pillar")

print(tibble(x = c(4e-300, 4e-324, 4e324, 10, -10, 4e-350)))
#> # A tibble: 6 × 1
#>             x
#>         <dbl>
#> 1   4   e-300
#> 2   4.94e-324
#> 3 Inf        
#> 4   1   e+  1
#> 5  -1   e+  1
#> 6   0
Ric
  • 5,362
  • 1
  • 10
  • 23