# Round to nicer numbers

The standard way to round numbers is to choose the nearest whole value, if the initial value is exactly halfway between two values, i.e. there is a tie, then you choose the larger one.

However where I work we round in a different way. Everything is measured in powers of two. So wholes, halves, quarters, eights, sixteenths etc. This means our measurements are always a binary fraction. We also round to binary fractions. However when the value is exactly halfway between, instead of rounding up we round to the "nicer" number.

For example if I measure 5/8 but I need to round it to the nearest fourth, both 2/4 and 3/4 are equally close to 5/8, but 2/4 = 1/2 which is a nicer number so we round to 1/2. If I measured 7/8 and needed to round to the nearest fourth I would round up to 8/8 = 1.

To put it concretely if we express every number as $$\x\times2^n\$$ where $$\x\$$ is odd, then we round towards the number with the larger $$\n\$$.

Going back to the example: I measure 5/8 and I need to round it to the nearest fourth. The values I can choose are $$\2/4=1\times2^{-1}\$$ and $$\3/4=3\times 2^{-2}\$$, since -1 is larger than -2 we round towards that.

When both the options are fully reduced fractions you can think of this as rounding towards the fraction with the smaller denominator. However this intuition becomes a little bit strained when the options are whole numbers.

## Challenge

In this challenge you will receive 3 numbers. An odd positive integer $$\x\$$, an integer $$\n\$$ and an integer $$\m\$$. You must round $$\x\times2^n\$$ to the nearest integer multiple of $$\2^m\$$ using the process described, and output the result as a binary fraction. This can be either a native binary fraction or the $$\x\times2^n\$$ format used for the input. The input will always be fully reduced so that the numerator, $$\x\$$, is odd, however you are not required to do so for your output.

This is so the goal is to minimize the size of your source code as measured in bytes.

## Test cases

$$\x\$$ $$\n\$$ $$\m\$$ $$\x\$$ $$\n\$$
5 -3 -2 1 -1
3 -1 -3 3 -1
9 -3 0 1 0
1 3 4 0 5
1 4 4 1 4
3 3 4 1 5

# Wolfram Language (Mathematica), 18 bytes

Round[2^#2#,2^#3]&


Try it online!

Returns a binary fraction. By default, the built-in Round rounds to even.

• Reading the docs on Round: "Round rounds numbers of the form x.5 toward the nearest even integer" got me wondering: Why does it work this way? It seems perfect for this challenge, but the much more common rule is to round up. I assume there is a deeper mathemetical reason for this? Also, what if you do just want to round up in Wolfram? Jan 5 at 2:04
• One answer I found is to avoid systematic bias in data sets that have many 0.5 values. Jan 5 at 2:38
• Jan 5 at 3:57
• @alephalpha Thank you! That makes a lot of sense. Jan 5 at 4:05

# C (GCC), 53 51 bytes

-2 bytes thanks to @ceilingcat

f(x,n,m)int*n,*x;{for(;*n<m;++*n)*x+=*x&(*x/=2)%2;}


Attempt This Online!

# J, 39 32 bytes

((]*%<.@+1r2*2|<.@%)2&^)~(*2&^)/


Try it online!

-7 thanks to the round toward even idea from att's Wolfram answer

Divide $$\x2^n/2^m\$$, manually round toward even, then multiply back $$\2^m\$$.

# R, 29 bytes

\(x,n,m)c(round(x*2^n/2^m),m)


Attempt This Online!

Based on @att's answer and similar round behaviour in R.

Outputs non-reduced answers in (x,n) format.

# Rust, 55 51 bytes

|x,n,m|((n..m).fold(x,|x,_|x/2+(x&1&x/2)),m.max(n))


Attempt This Online!

# Retina 0.8.2, 214 bytes

\d+
$* ,(1+),(?!1\1).* ,$1
,(-1+),\1.*
,$1 ,(-1+)(1+),\1 ,0$2,$1 ,-(1+),(1*) ,0$1$2,$2
,(1*),\1(1+)
,0$2,$1$2 +01 100 \G1(?=.*0) 0 (?=0+,1+(0+))\1 1 ^(?=1*0*,1+(0+)\1)(11)*.\1 1$&
(1*)0*,(1+0+,)?(-?)(1*)
$.1,$3$.4  Try it online! Link includes test cases. Output is not normalised and input is not required to be normalised either. Explanation: \d+$*


Convert to unary.

,(1+),(?!1\1).*
,$1 ,(-1+),\1.* ,$1


If n is greater than m then just delete m. Most of the rest of the code will then do nothing.

,(-1+)(1+),\1
,0$2,$1
,-(1+),(1*)
,0$1$2,$2 ,(1*),\1(1+) ,0$2,$1$2


Subtract n from m, adjusting for their signs.

+01
100


Calculate 2 to that power.

\G1(?=.*0)
0
(?=0+,1+(0+))\1
1


Divmod x by that.

^(?=1*0*,1+(0+)\1)(11)*.\1
1$&  If the remainder is at least half (for odd results) or more than half (for even results) then add another 1 to the result. (1*)0*,(1+0+,)?(-?)(1*)$.1,$3$.4


Convert to decimal.

# Charcoal, 31 bytes

ＮθＮηＮζ≧×Ｘ²⁻ηζθ≧⁺∧⁻﹪θ²⊘¹⊘¹θＩ⟦⌊θζ


Try it online! Link is to verbose version of code. Output is not normalised and input is not required to be normalised either. Explanation:

ＮθＮηＮζ


Input x, n and m.

≧×Ｘ²⁻ηζθ


Scale x by 2ⁿ⁻ᵐ.

≧⁺∧⁻﹪θ²⊘¹⊘¹θ


Prepare to floor x, but if its remainder modulo 2 is not 0.5, add 0.5 so that it gets rounded instead.

Ｉ⟦⌊θζ


Output x and m.

# 05AB1E (legacy), 7 bytes

o*Io/ò‚


Port of @pajonk's R answer, which is based on @att's Wolfram Language answer.

Inputs in the order $$\n,x,m\$$; outputs as pair $$\[n,x]\$$. Just like the ported R answer, it does no additional reduction to its simplest form.

Explanation:

Uses the legacy version of 05AB1E (built in Python), where ò does banker's rounding. In the new version of 05AB1E (built in Elixir), ò seems to be a regular rounding builtin, using the 'away from zero' convention for rounding halves.

o        # Take 2 to the power of the first (implicit) input n
*       # Multiply it to the second (implicit) input x
Io     # Push 2 to the power of the third input m as well
/    # Divide the earlier x*2**n by this 2**m
ò   # Banker's round it to the nearest integer
‚  # Pair it with the (implicit) third input m
# (after which this pair is output implicitly as result)


# JavaScript (Node.js), 32 bytes

(x,n,m)=>x*2**(n-m)*N/N;N=3e-324


Try it online!

Take x,n,m, return new x and set new n to input m

# Thunno, $$\ 12 \log_{256}(96) \approx \$$ 9.88 bytes

2@*z22@/ZvZP


Attempt This Online!

Port of Kevin Cruijssen's 05AB1E (legacy) answer, which is a port of pajonk's R answer, which is based on att's Mathematica answer.

Thunno is also built in Python so the rounding will work as intended.

2@*z22@/ZvZP  # Implicit input
2@            # Raise 2 to the power of the first input, n
*           # Multiply with the second input, x
z22@       # Push 2 to the power of the third input, m
/      # Divide x*2**n by 2**m
Zv    # Round to the nearest integer
ZP  # Pair with the third input, m
# Implicit output