# Rounding a range

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)

• Might be a good idea to have a test case with L > 1. May 6 at 3:28
• 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?
– Neil
May 6 at 9:23
• @chunes Done... May 6 at 13:35
• @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. May 6 at 13:40

# 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.

• 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. May 6 at 3:47
• @chunes Well, it's an integer valued float in that case because of floor division (//2). May 6 at 4:53
• Ah, it really looked to me like the integer division is outside the assignment expression to m. May 6 at 5:54

# 05AB1E, 16 14 bytes

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


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

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)


# 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.

# 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!

# Charcoal, 26 bytes

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

Ｎθ≔Ｅ⁺Ｎ⟦±θ⊕θ⟧⌊ιηＩ÷⟦↨η±¹Ση⟧²


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:

ＮθＮη≔⌊⁻ηθζ≧⁺⊕θηＩ÷⟦⁻ηθ⁺ηζ⟧²


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:

ＮθＮη≔⌊⁻ηθζ≔÷⁻⊕⁺ηθζ²εＩ⟦ε⁺εζ


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.

# 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!