Уменьшите этот цикл до уравнения
Эта функция (написана на 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 ответа
Объединив ответ nmclean и концепцию из этого вопроса, я получил следующее:
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);
который я тщательно проверил, чтобы всегда давать те же результаты, что и оригинал, и который ясно показывает, как делать подобные вещи в общем случае.
Во-первых, для простоты:
to = from + len - 1
Я думаю, что это может быть разбито на 3 уравнения, для каждого "раздела". То есть:
- A:
0
в0xD800 - 1
- B:
0xD800
в0xDFFF
- C:
0xDFFF + 1
до бесконечности
Раздел A и C "стоят" 2, а B стоит 1. Если я неправильно истолковал ваш код - есть только 2 раздела?
Таким образом, умножьте каждое значение секции на длину диапазона, который попадает в него:
A: 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
,
Я понятия не имею, будет ли это более эффективным для компьютера. Хотя это определенно менее эффективно для моего мозга.