# Split a value x into n approximately equal values with the remainder # distributed so the sum of the result array is equal to x. # Add one to each result while remainder is non-zero. # @note Larger values are always toward the front. def split_1(value, interval): assert interval > 0 result = [] q, r = divmod(value, interval) for _ in range(interval): if r == 0: result.append(q) else: result.append(q + 1) r -= 1 return result # Recursive split. # @note One value tends to repeat followed by alternation. def split_2(value, interval): if interval <= 0: return [] x = round(value / interval) return [x] + split_2(value - x, interval - 1) def rounddiv(a, b): return (a + b//2) // b # round half toward +INF def split_2(value, interval): assert interval > 0 result = [] v = value i = interval for _ in range(interval): x = rounddiv(v, i) v = v - x i = i - 1 result.append(x) return result # Minimize error on r/t (Bresenham). # @note Fairly uniform distribution of remainder. def split_3(value, interval): assert interval > 0 result = [] q, r = divmod(value, interval) t = interval - r e = 0 for _ in range(interval): if e < t: result.append(q) e += r else: result.append(q + 1) e -= t return result # Main. from timeit import timeit def _test(n, f): def check(v, i): a = f(v, i) ok = len(a) == i ok = ok and sum(a) == v t = v // i ok = ok and all(x == t or x == t+1 for x in a) return ok for v in range(-2*n, 2*n+1): for i in range(1, n+1): assert check(v, i), f'bad match at {v},{i}' def _show(n, f): for i in range(n+1): a = f(i, n) print(a, sum(a) == i) def _time(n, f): def g(): for v in range(-n, n+1): for i in range(1, n+1): f(v, i) print('Elapsed: {:.6f}s'.format(timeit(g, number=1))) # .. n = 10 _test(n, split_1) _test(n, split_2) _test(n, split_3) n = 5 m = 100 _show(n, split_1) _time(m, split_1) _show(n, split_2) _time(m, split_2) _show(n, split_3) _time(m, split_3) n = 100 m = 15 print(split_1(n, m)) print(split_2(n, m)) print(split_3(n, m))
Standard input is empty
[0, 0, 0, 0, 0] True [1, 0, 0, 0, 0] True [1, 1, 0, 0, 0] True [1, 1, 1, 0, 0] True [1, 1, 1, 1, 0] True [1, 1, 1, 1, 1] True Elapsed: 0.050364s [0, 0, 0, 0, 0] True [0, 0, 0, 1, 0] True [0, 1, 0, 1, 0] True [1, 1, 0, 1, 0] True [1, 1, 1, 1, 0] True [1, 1, 1, 1, 1] True Elapsed: 0.198435s [0, 0, 0, 0, 0] True [0, 0, 0, 0, 1] True [0, 0, 1, 0, 1] True [0, 1, 0, 1, 1] True [0, 1, 1, 1, 1] True [1, 1, 1, 1, 1] True Elapsed: 0.099216s [7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6] [7, 7, 7, 7, 7, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6] [6, 7, 7, 6, 7, 7, 6, 7, 7, 6, 7, 7, 6, 7, 7]