13
\$\begingroup\$

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
\$\endgroup\$
0

10 Answers 10

9
\$\begingroup\$

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.

\$\endgroup\$
4
  • \$\begingroup\$ 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? \$\endgroup\$
    – Jonah
    Jan 5 at 2:04
  • 4
    \$\begingroup\$ One answer I found is to avoid systematic bias in data sets that have many 0.5 values. \$\endgroup\$
    – Jonah
    Jan 5 at 2:38
  • 1
    \$\begingroup\$ @Jonah mathematica.stackexchange.com/q/2116/6652 \$\endgroup\$
    – alephalpha
    Jan 5 at 3:57
  • \$\begingroup\$ @alephalpha Thank you! That makes a lot of sense. \$\endgroup\$
    – Jonah
    Jan 5 at 4:05
5
\$\begingroup\$

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!

\$\endgroup\$
0
4
\$\begingroup\$

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\$.

\$\endgroup\$
4
\$\begingroup\$

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.

\$\endgroup\$
3
\$\begingroup\$

Rust, 55 51 bytes

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

Attempt This Online!

Copied from @matteo_c's C answer

\$\endgroup\$
2
\$\begingroup\$

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.

\$\endgroup\$
1
\$\begingroup\$

Charcoal, 31 bytes

NθNηNζ≧×X²⁻ηζθ≧⁺∧⁻﹪θ²⊘¹⊘¹θI⟦⌊θζ

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

NθNηNζ

Input x, n and m.

≧×X²⁻ηζθ

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.

I⟦⌊θζ

Output x and m.

\$\endgroup\$
0
\$\begingroup\$

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.

Try it online or verify all test cases.

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)
\$\endgroup\$
0
\$\begingroup\$

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

\$\endgroup\$
0
\$\begingroup\$

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
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.