此函数(为方便起见,用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;
}
如果有一种将这种循环转换为算术的通用,防盲技术,那将是一个理想的答案。如果做不到这一点,这个实例的解决方案就没问题。
答案 0 :(得分:2)
首先,为简单起见:
to = from + len - 1
我认为对于每个“部分”,它可以分为3个等式。那就是:
0
至0xD800 - 1
0xD800
至0xDFFF
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);
我经过详尽的测试,总能产生与原版相同的结果,并且清楚地显示了在一般情况下如何做这类事情。