14
\$\begingroup\$

You have a line with two endpoints a and b (0 ≤ a < b) on a 1D space. When a or b has a fractional value, you want to round it to an integer.

One way to do this is to round a and b each to its nearest integer, but this has a problem that the length of the rounded range (L) can vary while b - a stays the same. For example,

b - a = 1.4
(a, b) = (1, 2.4) -> (1, 2), L = 1
         (1.2, 2.6) -> (1, 3), L = 2

We want to find a way to round (a, b) so that L always has the same value ⌊b - a⌋ while the rounded pair (ra, rb) is closest to (a, b).

With (a, b) = (1.2, 2.6), we can consider two candidates of (ra, rb) with L = ⌊2.6 - 1.2⌋ = 1. One is (1, 2) and the other is (2, 3). (1, 2)'s overlapping range with (a, b) = (1.2, 2.6) is (1.2, 2), while (2, 3) overlaps at (2, 2.6). (1, 2) has a larger overlapping range ((1.2, 2) vs (2, 2.6)), so in this case we choose (1, 2).

Sometimes there are two options with the same overlapping length. For example, (0.5, 1.5) -> (0, 1), (1, 2). In such cases, either could be, but one should be, chosen.

Examples

0 ≤ a < b
b - a ≥ 1
(a, b) -> (ra, rb)

(1, 2) -> (1, 2)
(1, 3.9) -> (1, 3)
(1.1, 4) -> (2, 4)
(1.2, 4.6) -> (1, 4)
(1.3, 4.7) -> (1, 4) or (2, 5)
(1.4, 4.8) -> (2, 5)
(0.5, 10.5) -> (0, 10) or (1, 11)
\$\endgroup\$
4
  • 5
    \$\begingroup\$ Might be a good idea to have a test case with L > 1. \$\endgroup\$
    – chunes
    Commented May 6, 2022 at 3:28
  • \$\begingroup\$ IMHO it's strange that the rounded range's length is actually the truncation of the original range's length. Surely it should have been rounded too? \$\endgroup\$
    – Neil
    Commented May 6, 2022 at 9:23
  • \$\begingroup\$ @chunes Done... \$\endgroup\$
    – xiver77
    Commented May 6, 2022 at 13:35
  • 1
    \$\begingroup\$ @Neil If the length of the rounded range is also rounded, the half-points in the rounded range may not be included in the original range. Consider rounding (0.7, 2.3), if you also round the resulting length the result will include 2 half-points while the original has 1 (1.5). Keeping the number of half-points the same could be useful when applying this to some computer graphic operation. \$\endgroup\$
    – xiver77
    Commented May 6, 2022 at 13:40

6 Answers 6

7
\$\begingroup\$

Python, 44 bytes

lambda a,b:(m:=(a+b+1-(l:=int(b-a)))//2,m+l)

Attempt This Online!

Old Python, 50 bytes

lambda a,b:(m:=(a+b+~(l:=int(b-a))%2)//2-l//2,m+l)

Attempt This Online!

Old Python, 56 bytes

lambda a,b:((m:=(a+b+~(l:=int(b-a))%2)//2)-l//2,m--l//2)

Attempt This Online!

How?

The basic idea is: If the required length l is even round the midpoint and move l/2 in both directions. If l is odd round the midpoint to the nearest half integer instead.

\$\endgroup\$
3
  • \$\begingroup\$ I don't understand this. How does m (and thus m+l) end up being an integer? It seems to me that it should be a non-integer if either a or b are non-integers. \$\endgroup\$
    – chunes
    Commented May 6, 2022 at 3:47
  • \$\begingroup\$ @chunes Well, it's an integer valued float in that case because of floor division (//2). \$\endgroup\$
    – loopy walt
    Commented May 6, 2022 at 4:53
  • \$\begingroup\$ Ah, it really looked to me like the integer division is outside the assignment expression to m. \$\endgroup\$
    – chunes
    Commented May 6, 2022 at 5:54
3
\$\begingroup\$

05AB1E, 16 14 bytes

O>I`αï©-2÷D®+‚

-2 bytes porting @loopyWalt's Python answer; make sure to upvote him as well!

Try it online or verify all test cases.

Explanation:

O              # Sum the (implicit) input-pair
 >             # Increase it by 1
  I            # Push the input-pair again
   `           # Pop and push both values separated to the stack
    α          # Take the absolute difference between both
     ï         # Cast it to an integer to floor it
      ©        # Sort this value in variable `®` (without popping)
       -       # Subtract it from the earlier sum+1
        2÷     # Integer-divide it by 2
          D    # Duplicate this
           ®+  # Add `®` to the copy
             ‚ # Pair the two values together
               # (after which it is output implicitly as result)
\$\endgroup\$
3
\$\begingroup\$

Factor + math.unicode, 44 bytes

[ 2dup - ⌊ -rot 1 + + over - 2 /i tuck + ]

Try it online!

Takes input as b a. Port of loopy walt's Python answer.

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

Desmos, 62 bytes


f(a,b)=(A,\floor(b-a)+A)+\{\ceil(b)-b<a-A,0\}(1,1)
A=floor(a)

Takes input as function parameters and returns a point (ra,rb)

Try it on Desmos!

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

Charcoal, 26 bytes

After messing around trying to find an arithmetic solution I came up with the following:

Nθ≔E⁺N⟦±θ⊕θ⟧⌊ιηI÷⟦↨η±¹Ση⟧²

Try it online! Link is to verbose version of code.

Rather than trying to be clever with vectorised arithmetic, I rewrote it to use variables instead. It still came out at 26 bytes:

NθNη≔⌊⁻ηθζ≧⁺⊕θηI÷⟦⁻ηθ⁺ηζ⟧²

Try it online! Link is to verbose version of code.

A direct port of @loopywalt's Python answer turns out to also be 26 bytes:

NθNη≔⌊⁻ηθζ≔÷⁻⊕⁺ηθζ²εI⟦ε⁺εζ

Try it online! Link is to verbose version of code. Note that because it does the integer division by 2 earlier it doesn't need to explicitly close the output list, saving a byte.

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

PARI/GP, 34 bytes

f(a,b)=[m=(a+b+1-l=(b-a)\1)\2,m+l]

Attempt This Online!

A port of loopy walt's Python answer.


PARI/GP, 48 bytes

f(a,b)=[a,b]\1+if(a%1>b%1,[1,0],[t=a%1+b%1>1,t])

Attempt This Online!

\$\endgroup\$

Your Answer

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

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