将此循环简化为等式

时间:2014-01-24 19:00:00

标签: algorithm language-agnostic strength-reduction

此函数(为方便起见,用C语言编写,但这对问题并不重要)决定了数组的大小。我敢肯定它可以转换为if-else链甚至是方程式,但我不够聪明,不知道如何。 (我试着写下明显的if-else链,但在案件中陷入困境。)

// 0 <= from <= 0x10FFFF
// 1 <= len <= 0x10FFFF
unsigned int size_for_block(unsigned int from, unsigned int len)
{
  unsigned int size = 0;
  for (unsigned int i = 0; i < len; i++) {
    unsigned int point = from + i;
    if (0xD800 <= point && point <= 0xDFFF)
      ;
    else if (point <= 0xFFFF)
      size += 1;
    else
      size += 2;
  }
  return size;
}

如果有一种将这种循环转换为算术的通用,防盲技术,那将是一个理想的答案。如果做不到这一点,这个实例的解决方案就没问题。

2 个答案:

答案 0 :(得分:2)

首先,为简单起见:

to = from + len - 1

我认为对于每个“部分”,它可以分为3个等式。那就是:

  • 答:00xD800 - 1
  • B:0xD8000xDFFF
  • C:0xDFFF + 1到无穷大

部分 A C 是“值得”2, B 值得1.除非我误解了您的代码 - 是否存在只有2个部分?

因此,将每个部分值乘以其范围内的范围的长度:

答: if (from < 0xD800) size += 2 * min((0xD800 - 1) - from + 1, len)

假设min是一个返回其参数较小的函数:范围是from到该部分的末尾,或len,以较短者为准” 。范围是(结束 - 开始+ 1)。

B: if (to > 0xD800) size += 1 * min(0xDFFF - 0xD800 + 1, to - D800 + 1)

这里的逻辑类似:“完整部分,或部分的开头to,以较短者为准”

C: if (to > 0xDFFF + 1) size += 2 * (to - (0xDFFF + 1) + 1)

这更简单,因为没有终点:只从头开始计算to

我不知道这对计算机来说是否更有效率。不过,这对我的大脑来说效率肯定不高。

答案 1 :(得分:0)

结合nmclean的回答和this question的概念,我现在有了这个:

function overlap(min1, max1, min2, max2) {
  return Math.max(0, Math.min(max1, max2) - Math.max(min1, min2));
}
size = (overlap(from, from+len, 0x000000, 0x00D800) +
        overlap(from, from+len, 0x00E000, 0x010000) +
        overlap(from, from+len, 0x010000, 0x110000)*2);

我经过详尽的测试,总能产生与原版相同的结果,并且清楚地显示了在一般情况下如何做这类事情。