模算法难以捉摸

Modulo algorithm proving elusive

我有一个色轮,可以将颜色映射到 24 小时制的每个小时。现在给定一天中的时间,我想将这些颜色映射到 12 小时制,以便使用当前时间之前 5 小时和之后 6 小时的颜色。但这有点棘手 b/c 结果的第 0 个索引总是必须是 24 色轮的第 0 种颜色或第 12 种颜色。

例如,给定 colors24 作为 24 种颜色的数组和 5 小时的时间,那么最终的 color12 数组将映射到 colors24 的索引为:

{0,1,2,3,4,5,6,7,8,9,10,11}

如果小时是 3,则:

{0,1,2,3,4,5,6,7,8,9,22,23}

如果小时是 9,则:

{12,13,14,15,4,5,6,7,8,9,10,11}

如果算法可以推广到任意两个数组而不管大小,只要第一个可以被第二个整除即可加分。

能不能直接把颜色从(C-Y/2+X+1)%X 到(C+Y/2)%X,然后排序?

(这与循环 (C+Z+X+1)%X 从 Z = -Y/2 到 Z = Y/2-1 相同):

for (i = 0, j = c+x+1, z = -y/2; z < y/2; z++) {
    color[i++] = (z+j)%x;
}

对于 C=3、X=24 和 Y=12,您得到:

 (C-12/2+24+1)%24 = 3-6+24+1 = 22, 23, 0, 1 .. 9

排序后你得到 0、1 ...9、22、23。

如果不进行排序,您总是会得到一个当前小时位于中间的序列(这可能对某些应用程序有好处),而您的 3 示例将它向左移动了两个位置。

你可以通过移动而不是排序来做到这一点,注意你只需要在 c 低于 Y/2 时移动(C​​=3 使你从 -2 开始,变成 22),在这种情况下你移动负数 y/2-c(这里是 2,或者 12+2 使用另一个模数),或者如果 c > (x-y/2),在这种情况下你会超出 x:如果 c = 20, c+6 是 26,回滚到 2:

15 16 17 18 19 20 21 22 23 0 1 2

并给出 2+1 = 3 的 s 因子,或者一般来说 (c+y/2)%x+1:

0 1 2 15 16 17 18 19 20 21 22 23


for (i = 0, j = c+x+1, z = -y/2; z < y/2; z++) {
    color[(s+i++)%y] = (z+j)%x;
}

但是,如果 x > 2*y,我认为你遇到了问题;在这种情况下,您会得到一些 c 值,其中 0 和 x/2 都不是 c 的 "in reach"。也就是说,"evenly divisible" 必须意味着 x 必须始终 等于 到 y*2。

这可以通过首先将数字放入临时数组,然后在其中找到 0 或 12 的位置,并从该位置打印结果,将索引视为循环(即对数组长度取模)来完成)

这是一个示例实现:

int num[12];
// Populate the values that we are going to need
for (int i = 0 ; i != 12 ; i++) {
    // 19 is 24-5
    num[i] = (h+i+19) % 24;
}
int p = 0;
// Find p, the position of 0 or 12
while (num[p] != 0 && num[p] != 12) {
    p++;
}
// Print num[] array with offset of p
for (int i = 0 ; i != 12 ; i++) {
    printf("%d ", num[(p+i) % 12]);
}

Demo.

注意:第一和第二循环可以合并。添加检查你刚刚设置的数字是否为零或12,并在找到匹配时设置p的值。

这是JavaScript中的解决方案:

function f(h) {
  var retval = [];
  for (var i = h - 5; i <= h + 6; ++i)
    retval.push((i+24) % 24);
  return retval.sort(function(a,b){return a-b;}); // This is just a regular sort
}

https://repl.it/CWQf

例如,

f(5) // [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ]
f(3) // [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 22, 23 ]
f(9) // [ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ]

如果hours是总小时数(24),length一次显示的颜色数(12),hour是当前小时,那么这是将索引放入颜色数组的通用算法:

result = [];
add = hour + hours - (length / 2) - (length % 2) + 1;
for (i = 0; i < length; i++) {
    result[(add + i) % length] = (add + i) % hours;
}

这是一个 Javascript 实现(通用,可用于 24/12 以外的其他范围):

function getColorIndexes(hour, hours, length) {
    var i, result, add;

    if (hours % length) throw "number of hours must be multiple of length";
    result = [];
    add = hour + hours - (length / 2) - (length % 2) + 1;
    for (i = 0; i < length; i++) {
        result[(add + i) % length] = (add + i) % hours;
    }
    return result;
}

console.log ('hour=3: ' + getColorIndexes(3, 24, 12));
console.log ('hour=5: ' + getColorIndexes(5, 24, 12));
console.log ('hour=9: ' + getColorIndexes(9, 24, 12));
console.log ('hour=23: ' + getColorIndexes(23, 24, 12));

如问题中所述,小时数 (24) 必须是 return 数组长度的倍数。