# Efficient Round edition with different rounding direction

As pointed out in this post, Mathematica has a special version of Round that

Round rounds numbers of the form x.5 toward the nearest even integer.

A comment by David G suggest that why not have differnt options Direction → {"HalfDown","HalfUp","HalfEven","HalfOdd","Stochastic"}

These days I need a version of Round to HalfUp. I write a quite ugly and slow function as below

myRound[x_, d_] := Module[{},
c1 = (1./d)*10;
c2 = 1./d;
theDigit = Last@IntegerDigits@IntegerPart[x*c1];
If[theDigit >= 5,
InternalStringToDouble@ToString@N[(IntegerPart[x*c2] + 1)/c2],
InternalStringToDouble@ToString@N[(IntegerPart[x*c2])/c2]]]


speed test

In:=
myRound[#, 0.01] & /@ RandomReal[1., 1000000]; // AbsoluteTiming

Out= {30.7072, Null}

In:=
Round[#, 0.01] & /@ RandomReal[1., 1000000]; // AbsoluteTiming

Out= {0.285921, Null}


So I am wondering if someone on this site already have developed an efficient toolkit for round matters?

• Floor[x+0.5]? Mar 17, 2019 at 11:58
• @Szabolcs But Floor gives integer. Round can round at any digit Mar 17, 2019 at 12:02
• Are your aware of RoundingRule? Mar 17, 2019 at 12:25
• Could extend the method proposed by @Szabolcs: myRound[x_, d_] := d*Floor[x/d + 1/2] Mar 17, 2019 at 13:58
• That's a result of using decimal values e.g. .01 that do not have exact binary equivalents. Could instead do myRound[8.121,1/100] and numericize afterward. Mar 17, 2019 at 18:36

I offer the following solution

r2[x_, a_] := x - Mod[x, a, -(a/2)]


We can verify that it has the desired result, using PiecewiseExpand

PiecewiseExpand[r2[x, a], -2 a < x < 2 a && a > 0]


Performance is only a little slower than the built-in Round

list = RandomReal[{0, 1}, 1000000];

AbsoluteTiming[Round[list, 0.1];]
(* {0.0079, Null} *)

AbsoluteTiming[r2[list, 0.1];]
(* {0.009414, Null} *)

• Wow, great solution. But there is a issue with hidden fractions as pointed out by mathematica.stackexchange.com/q/65298/4742 . But if we use InternalStringToDouble@ToString, the performance will drop down. Mar 17, 2019 at 13:22
• @matheorem Technically, 1.265 in binary floating point corresponds to the fraction 5697053528623677/4503599627370496 which less than 1265/1000. The issue is due to rounding decimal to binary. Thus it is a problem of inputting the number you meant, not a problem with r2[]. Mar 17, 2019 at 15:14
• @matheorem The problem with imprecise calculation is that unwanted errors creep in, such as what you're complaining about. :) How about this?: r2[x_, a_] := x (1 + Sign[x] $MachineEpsilon) - Mod[x (1 + Sign[x]$MachineEpsilon), a, -(a/2)]` Mar 17, 2019 at 15:40
• @matheorem, I think you need to consider why you know the input is exactly 1.265 rather than a little more or a little less, and why the rounding is important to you. If you know the 3rd decimal place is exact, I suggest you multiply all your numbers by 1000, and work with integers. Mar 17, 2019 at 18:38
• @matheorem That's what happens (automatically) when you use real (floating-point) numbers on all common CPUs. Mar 18, 2019 at 2:52