2014-01-24 2 views
1

Эта функция (написанная на C для удобства, но это не важно для вопроса) определяет размер массива. Я уверен, что он может быть преобразован в цепочку 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; 
} 

Если есть общий, idiotproof метод для преобразования такого рода петли арифметики, что было бы идеальным ответ , В противном случае решение для этого экземпляра будет в порядке.

ответ

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); 

, которые я исчерпывающе испытания всегда производят те же результаты, что и оригинал, и который ясно показывает, как сделать этот вид вещи в общем случае.

2

Во-первых, для простоты:

to = from + len - 1 

Я думаю, что это может быть разбита на 3 уравнений, для каждого "раздела". То есть:

  • A: 0 к 0xD800 - 1
  • B: 0xD800 в 0xDFFF
  • C: 0xDFFF + 1 до бесконечности

Раздел и C являются "стоит" 2, и B стоит 1. Если я неверно истолковал ваш код - есть ли только 2 раздела s?

Так умножить каждое значение сечения по длине диапазона, который попадает в нее:

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.

Я понятия не имею, было ли это более эффективным для компьютера. Тем не менее, это определенно менее эффективно для моего мозга.

+0

На самом деле есть * четыре области: от 0 до 0xD7FF, от D800 до DFFF, от E000 до FFFF и от 10000 до 1, 0, 1 и 2 соответственно. Мне нравится идея * здесь, но дополнительный регион делает ее более грязной, чем я полностью доволен. Это часть автоматизированного теста, и тест слишком медленный, поэтому я пытался его оптимизировать, но меня можно было убедить в том, что его легче понять, и это более важно ... – zwol

Смежные вопросы