3

Here round() behaves as expected:

round(3.5)
[1] 4

However this was surprising to me:

round(2.5)
[1] 2

Question

In times when we want everything ending in .5 to be rounded up, what's best practice in R to achieve that?

Note

Ideally the solution should also cater for rounding beyond the first decimal place e.g. the following should return 0.2:

round(0.15, 1)
[1] 0.1
stevec
  • 41,291
  • 27
  • 223
  • 311
  • Just to clarify: do you understand *why* `round` behaves the way it does, and why its way of rounding is generally superior? – Konrad Rudolph Mar 12 '21 at 13:09
  • 1
    @KonradRudolph I don't. – user2974951 Mar 12 '21 at 13:10
  • @KonradRudolph I do but only after learning of the difference in norms. I believe it's simply a norm in some places to round 0.5 to the nearest *even* number (irrespective of whether that may be higher or lower than the input), whereas in other places it's the norm to always round 0.5 up without exception. – stevec Mar 12 '21 at 13:11
  • @user2974951 I hadn't either until 25 minutes ago :) – stevec Mar 12 '21 at 13:13
  • 3
    @user2974951 Have a look at the [Wikipedia section](https://en.wikipedia.org/wiki/Rounding#Round_half_to_even). In a nutshell, other rounding methods introduce a systematic bias. By contrast, round-half-towards-even doesn’t: a distribution of random numbers has the same mean before and after rounding with this method. – Konrad Rudolph Mar 12 '21 at 13:15
  • 1
    @KonradRudolph I'm beginning to question everything my 3rd grade math teacher taught me! – stevec Mar 12 '21 at 13:17
  • 2
    @stevec Tell me about it! I almost had an existential crisis when I learned this. – Konrad Rudolph Mar 12 '21 at 13:19
  • 1
    This must be a duplicate, right? – Ben Bolker Jun 22 '21 at 03:44
  • 1
    @BenBolker I rewrote the title for visibility, mostly because I googled just now and couldn’t find it and a *lot* of other similar but different questions come up on google. I guess TL;DR the answer has probably been provided many times before, but probably to different variations on the question. FYI I requested a native implemtation in base R: https://github.com/HenrikBengtsson/Wishlist-for-R/issues/121 – stevec Jun 22 '21 at 03:50
  • `janitor::round_half_up()` https://cran.r-project.org/web/packages/janitor/vignettes/janitor.html#directionally-consistent-rounding-behavior-with-round_half_up – Patrick Jul 15 '22 at 11:34

1 Answers1

1

After googling for 'commercial rounding in r', this answer comes up, which can be adapted to have a default value of 0 decimal places like so:

round2 = function(x, decimal_places = 0) {
  posneg = sign(x)
  z = abs(x)*10^decimal_places
  z = z + 0.5 + sqrt(.Machine$double.eps)
  z = trunc(z)
  z = z/10^decimal_places
  z*posneg
}

Examples:

round2(3.5)
[1] 4

round2(2.5)
[1] 3

round2(0.15, decimal_places = 1)
[1] 0.2
stevec
  • 41,291
  • 27
  • 223
  • 311