Проверка, является ли двойным (или плавание) NaN в C++

Да, есть обработчик событий ondrag() , который срабатывает во время перетаскивания элемента. Если вы хотите вызвать функцию в самом начале действия перетаскивания, есть также обработчик событий ondragstart() .

Если вы хотите захватить, когда элемент перетаскивается поверх элемента (но не отброшен), есть ondragenter() , который срабатывает один раз, как элемент перетаскивается в элемент, а также ondragover() , который срабатывает многократно, когда элемент перетаскивается поверх элемента. 1112]

358
задан Peter Mortensen 3 September 2014 в 08:55
поделиться

7 ответов

Согласно стандарту IEEE, значения NaN имеют нечетное свойство, что сравнения, вовлекающие их, всегда ложь. Таким образом, для плавания f, f != f будет верен только , если f будет NaN.

Примечание, что, как некоторые комментарии ниже указали, не, все компиляторы уважают это при оптимизации кода.

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

342
ответ дан jalf 23 November 2019 в 00:19
поделиться

Можно использовать эти isnan() функция, но необходимо включать математическую библиотеку C.

#include <cmath>

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

inline bool isnan(double x) {
    return x != x;
}
18
ответ дан raimue 23 November 2019 в 00:19
поделиться

Можно использовать numeric_limits<float>::quiet_NaN( ) определенный в limits стандартная библиотека для тестирования с. Существует отдельная константа, определенная для double.

#include <iostream>
#include <math.h>
#include <limits>

using namespace std;

int main( )
{
   cout << "The quiet NaN for type float is:  "
        << numeric_limits<float>::quiet_NaN( )
        << endl;

   float f_nan = numeric_limits<float>::quiet_NaN();

   if( isnan(f_nan) )
   {
       cout << "Float was Not a Number: " << f_nan << endl;
   }

   return 0;
}

я не знаю, работает ли это над всеми платформами, когда я только протестировал с g ++ на Linux.

25
ответ дан Bill the Lizard 23 November 2019 в 00:19
поделиться

Существует станд.:: isnan, если Вы компилятор поддерживаете c99 расширения, но я не уверен, делает ли mingw.

Вот небольшая функция, которая должна работать, если Ваш компилятор не имеет стандартной функции:

bool custom_isnan(double var)
{
    volatile double d = var;
    return d != d;
}
39
ответ дан CTT 23 November 2019 в 00:19
поделиться

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

#include <boost/math/special_functions/fpclassify.hpp>

, Вы получаете следующие функции:

template <class T> bool isfinite(T z);
template <class T> bool isinf(T t);
template <class T> bool isnan(T t);
template <class T> bool isnormal(T t);

, Если у Вас есть время затем, взглянули на целый Математический инструментарий от Повышения, он имеет много полезных инструментов и растет быстро.

Также при контакте с плаванием и неплавающими точками это могла бы быть хорошая идея посмотреть Числовые Преобразования .

82
ответ дан Anonymous 23 November 2019 в 00:19
поделиться

На x86-64 у Вас могут быть чрезвычайно быстрые методы для проверки NaN и бесконечность, которые работают независимо от -ffast-math параметр компилятора. (f != f, std::isnan, std::isinf всегда урожай false с -ffast-math).

<час>

Тестирование на NaN, бесконечность и конечные числа может легко быть сделано путем проверки на максимальную экспоненту. бесконечность является максимальной экспонентой с нулевой мантиссой, NaN является максимальной экспонентой и ненулевой мантиссой. Экспонента хранится в следующих битах после самого верхнего знакового бита, так, чтобы мы могли просто сдвиг влево, чтобы избавиться от знакового бита и сделать экспоненту самыми верхними битами, никакое маскирование (operator&) не необходимо:

static inline uint64_t load_ieee754_rep(double a) {
    uint64_t r;
    static_assert(sizeof r == sizeof a, "Unexpected sizes.");
    std::memcpy(&r, &a, sizeof a); // Generates movq instruction.
    return r;
}

static inline uint32_t load_ieee754_rep(float a) {
    uint32_t r;
    static_assert(sizeof r == sizeof a, "Unexpected sizes.");
    std::memcpy(&r, &a, sizeof a); // Generates movd instruction.
    return r;
}

constexpr uint64_t inf_double_shl1 = UINT64_C(0xffe0000000000000);
constexpr uint32_t inf_float_shl1 = UINT32_C(0xff000000);

// The shift left removes the sign bit. The exponent moves into the topmost bits,
// so that plain unsigned comparison is enough.
static inline bool isnan2(double a)    { return load_ieee754_rep(a) << 1  > inf_double_shl1; }
static inline bool isinf2(double a)    { return load_ieee754_rep(a) << 1 == inf_double_shl1; }
static inline bool isfinite2(double a) { return load_ieee754_rep(a) << 1  < inf_double_shl1; }
static inline bool isnan2(float a)     { return load_ieee754_rep(a) << 1  > inf_float_shl1; }
static inline bool isinf2(float a)     { return load_ieee754_rep(a) << 1 == inf_float_shl1; }
static inline bool isfinite2(float a)  { return load_ieee754_rep(a) << 1  < inf_float_shl1; }

std версии [1 110] и isfinite загрузка 2 double/float константы от [1 113] сегмент и в худшем варианте развития событий они могут вызвать 2 неудачных обращения в кэш данных. Вышеупомянутые версии не загружают данных, inf_double_shl1 и inf_float_shl1, константы кодируются как непосредственные операнды в инструкции по сборке.

<час>

Быстрее isnan2 всего 2 инструкции по сборке:

bool isnan2(double a) {
    bool r;
    asm(".intel_syntax noprefix"
        "\n\t ucomisd %1, %1"
        "\n\t setp %b0"
        "\n\t .att_syntax prefix"
        : "=g" (r)
        : "x" (a)
        : "cc"
        );
    return r;
}

Использование то, что ucomisd флаг четности систем команд, если каким-либо аргументом является NaN. Это - то, как std::isnan работы, когда никакой -ffast-math опции указан.

0
ответ дан 23 November 2019 в 00:19
поделиться

В текущей стандартной библиотеке C++ отсутствует функция isnan(). Она была введена в C99 и определена как макро, а не как функция. Элементы стандартной библиотеки, определённые С99, не являются частью текущего стандарта ISO/IEC 14882:1998 и его обновления ISO/IEC 14882:2003.

В 2005 году был предложен Технический отчет 1. TR1 обеспечивает совместимость с C99 до C++. Несмотря на то, что он никогда не был официально принят, чтобы стать стандартом C++, многие (GCC 4.0+ или Visual C++ 9.0+ реализации C++ предоставляют возможности TR1, все или только некоторые из них (Visual C++ 9.0 не предоставляет математические функции C99).

Если TR1 доступен, то cmath включает элементы C99, такие как isnan(), isfinite() и т.д., но они определены как функции, а не как макросы, обычно в std::tr1:: пространстве имён, хотя многие реализации (i. например, GCC 4+ на Linux или в XCode на Mac OS X 10.5+) вводят их непосредственно в std::, так что std::isnan хорошо определено.

Более того, некоторые реализации C++ все еще делают макрос C99 isnan() доступным для C++ (включенный через cmath или math.h), что может вызвать больше путаницы, и разработчики могут предположить, что это стандартное поведение.

Заметка о Viusal C++, как упоминалось выше, не предоставляет std::isnan и std::tr1::isnan, но предоставляет функцию расширения, определяемую как _isnan(), которая была доступна с Visual C++ 6.0

On XCode, это еще более забавно. Как уже упоминалось, GCC 4+ определяет std::isnan. Для старых версий компилятора и библиотеки формы XCode, кажется (вот соответствующая дискуссия), не успел проверить себя) определены две функции, __inline_isnand() на Intel и __isnand() на Power PC.

218
ответ дан 23 November 2019 в 00:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: