2015-09-24 3 views
6

Я должен хранить одно двойное значение, кэшированное. После его использования он должен быть недействительным. Две альтернативыC/C++ NaN или boolean?

Одним из них является добавление булевого флага, true, когда кешированное значение является хорошим, когда оно используется, установите его в false, а когда флаг будет ложным, пересчитайте и пополните.

Второй интереснее - я мог бы сохранить его как двойное значение и использовать NaN как недействительный/необходимость в флагом recalc.

double get() const { 
    if (!isnan(_value)) { 
     double t = _value; 
     _value = std::numeric_limits<double>::quiet_NaN; 
     return t; 
    } 
} 

Любые возражения против него? Любые мысли об эффективности?

+4

Это вопрос C или C++ вопрос? Ответы совершенно разные для двух языков. –

+5

Ключевой вопрос: есть ли NaN разумное значение для установки кеша? Это всегда ключевая проблема с использованием значений флагов - если значение всегда может быть установлено на флаг во время нормальной работы, у вас будет реальная ошибка, связанная с ошибкой. –

+0

Имея флаг состояния, вы можете выйти за пределы «действительных» и «недопустимых» значений, таких как «внутреннее значение по умолчанию», «системное значение по умолчанию», «пользовательская настройка по умолчанию», «значение переопределения оператора» и т. Д. и т. д. – wallyk

ответ

6

используйте логическое значение, иначе вы столкнетесь с некоторыми интересными проблемами/ошибками по дороге, когда ваш вычисленный двойной фактически окажется NaN (из-за расчета). Если вы полагаетесь на NaN в качестве сигнала для «Я использовал это значение», тогда вы не сможете отличить в случае «действительного» неиспользованного NaN.

Не говоря уже о том, что такая перегрузка семантики вызовет будущего читателя вашего кода (пусть и самого себя через несколько месяцев), чтобы почесать его голову, пытаясь расшифровать это умное использование. ;-)

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

Что касается эффективность идет - я бы порекомендовал вам сначала измерить и только потом беспокоиться об оптимизации. Готов поспорить, что после запуска тестов вы обнаружите, что разница в скорости значительно ниже шума производительности, вызванного колебаниями температуры процессора.

+0

Да, это проблема. Если код пополнения производят NaN, все может стать интересным ... –

+0

Очень важная забота и та, с которой вы действительно не хотите заниматься производством ;-) – YePhIcK

0

Я думаю, что стоит отметить, что наном может быть более эффективное решение, главным преимуществом которого является то, что вы используете меньше памяти, чем с флагом (чьи накладные расходы, вероятно, будут более 1 байт за двойной, из-за выравнивание). Это означает, что он также будет быстрее, если вам нужно будет прочитать много памяти.

Еще одна вещь, на которую следует обратить внимание, заключается в том, что IEEE nans может иметь разные значения. Их экспоненты должны быть всеми, но мантисса может быть чем угодно, кроме всех нулей. Это означает, что вы можете использовать «специальный» nan, чтобы отличать от тех, которые были получены в результате вычисления, или даже использовать разные типы nans, если вам нужен флаг с более чем двумя состояниями.

+0

Проблема с этим подходом заключается в том, что единственная доступная стандартная функция для проверки 'isnan()' и друзья. Если есть действительно разные шаблоны NaN, я должен писать 'is_that_NaN()', 'is_it_another_NaN()' и т. Д. Но спасибо за ответ –

+0

@SeverinPappadeux, это правда, но это очень короткая функция для записи. memcmp (& my_double, & my_special_nan, sizeof (double))! = 0 будет делать трюк. – toth

3

я сомневаюсь, что будет разница с эффективностью, но код с булевым флагом будет более удобным для чтения:

double get() const { 
    if (!_cached) 
     _value = recalculate(); 
    _cached = !_cached; 
    return _value; 
} 
Смежные вопросы