2014-01-25 2 views
3

У меня есть цифровой код, разработанный на AMD64 Linux (с использованием LLVM 3.2).Положительный и отрицательный nans

Я недавно портировал его на OSX 10.9 с помощью XCode. Он работает нормально, но он не выполняет много модульных тестов: кажется, что некоторые вычисления, которые на Linux возвращают NaN (или -NaN), теперь возвращаются на OSX, -NaN (или NaN).

Могу ли я с уверенностью предположить, что положительные и отрицательные NaN эквивалентны и корректируют мои модульные тесты, чтобы принять их как успех, или это признак чего-то более серьезного не так?

+0

Что-то серьезное может уже пойти не так, если у ваших NaN есть знаки. Это не нормально. – user2357112

+0

http://stackoverflow.com/a/8817304/267482 – bobah

+0

Huh. Я думал, что бит знака всегда игнорируется; похоже, что есть системы, которые отображают его. Тогда, наверное, хорошо. – user2357112

ответ

3

Это зависит от полностью от того, что тестирует ваш юнит-тест.

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

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

x = doCalc() 
if x is any sort of Nan: 
    doSomethingWithNan() 

, то ваш тест должен обработать все NaN значения как равнозначные. Однако, если вы используете его таким образом:

x = doCalc() 
if x is +Nan: 
    doSomethingForPositive() 
else: 
    if x is -Nan: 
     doSomethingForNegative() 

тогда вы захотите относиться к ним как к разным.

Аналогично, если ваша реализация создает полезную полезную нагрузку в дробных битах (см. Ниже), а ваш реальный код использует, что также должно быть проверено модульными тестами.


Поскольку NaN просто все 1-бит в показателе и нечто иное, чем все нулевые биты во фракции, бит знака может быть положительным или отрицательным, а дробные биты могут быть самые разнообразные значений. Тем не менее, это по-прежнему значение или результат, который был вне представления типа данных, поэтому, если вы ожидали именно этого, вероятно, мало что может означать, что содержит знак или полезная нагрузка.

С точки зрения проверки текстового вывода NaN значений, the Wikipedia page on NaN указывает на то, что различные реализации могут дать вам весьма различные выходы, среди них:

nan 
NaN 
NaN% 
NAN 
NaNQ 
NaNS 
qNaN 
sNaN 
1.#SNAN 
1.#QNAN 
-1.#IND 

и даже варианты показывая изменяющегося знака и полезной нагрузки, которые имеют не влияет на его NaN-Несс:

-NaN 
NaN12345 
-sNaN12300 
-NaN(s1234) 

Так что, если вы хотите быть массивно портативный в тестовом модуле, вы заметите, что все выходные данные повторно В префиксах есть один вариант строки nan. Таким образом, поиск без учета регистра по значению для строки nan или ind подберет их всех. Это может не сработать в всех окружениях, но имеет очень большой охват.

Для чего это стоит, стандарт C имеет это, чтобы сказать о выводе значений с плавающей запятой с %f (%F использует заглавные буквы):

double аргумент, представляющий NaN превращается в один из стилей [-]nan или [-]nan(n-char-sequence) - какой стиль, а также значение любого n-char-sequence, определяется реализацией.

Поэтому достаточно просто проверить, было ли в нем nan.

+0

Это не совсем отвечает на мой вопрос, хотя --- Мне нужно знать, является ли бит знака в NaN достаточно важным для моих модульных тестов, на которые нужно обратить внимание. Я очень удивлен тем, что OSX и Linux дают разные результаты здесь: это тот же процессор и тот же самый компилятор, и я думал, что спецификация float IEEE не дает никакой комнаты для разборки, чтобы производить разные результаты здесь. Это то, о чем я должен заботиться? –

+0

@ Давид, как я уже говорил, это зависит от ваших тестов. Если вы специально не тестируете выход NaN, вы почти наверняка можете спокойно предположить, что все NaN идентичны, так как любой найденный код почти наверняка относится к ним одинаково. Если вы тестируете функцию, вызывающие которой будут вести себя по-разному на основе знака, тогда вы должны относиться к ним _differently._ Но это было бы очень необычно. Я уточню. – paxdiablo

+0

Нет никакого значащего понятия, в котором значение может быть + NaN или -NaN, так как NaN не имеет знака; «обработка значений как разных» является ошибкой в ​​программе, если намерение выполняется по арифметике IEEE-754. –

8

В арифметике IEEE-754 нет понятия «отрицательный NaN». В кодировке NaN все еще есть знаковый бит, и существует понятие операции «знакового бита», которая использует или влияет на этот бит (copysign, abs, несколько других), но он не имеет никакого значения, когда интерпретируется кодировка NaN как ценность. Многие типографии печати печатают бит как отрицательный знак, но формально бессмысленны, и поэтому в стандарте нет большого количества правил для управления его значением (кроме w.r.t. вышеупомянутых функций).

Вот соответствующий раздел IEEE-754 (2008):

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

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

Отредактировано для того, чтобы быть немного сильнее: это почти всегда ошибка, придающая значение знаку «бит бит» базы данных NaN.

+0

Однако тот факт, что есть и результаты, которые являются «NaN» в первой системе, и «-NaN» на втором, а результаты «-NaN» на первом и «NaN» на втором указывают на то, что что-то другое возникающие в предыдущих операциях с плавающей запятой, а не только окончательный 'printf'. Может существовать численный результат, который имеет различный знак в двух системах до генерирования NaN. Тот факт, что тестовая программа не выявила ошибок в числовых результатах (результаты, отличные от NaN), может быть из-за недостаточности тестов. Поэтому, возможно, стоит исследовать, почему знаки различаются. –

+1

Более вероятным объяснением является то, что существует библиотечная функция, которая сохраняет «знак» NaN на одной платформе, но не на другом (что хорошо, потому что «знак» не имеет смысла). Это очень распространено; одна платформа имеет 'if (isnan (x)) return x', другой имеет' if (isnan (x)) return NAN' или аналогичный. Единственными условиями, при которых я бы сказал, что дальнейшее расследование является подходящим, было бы, если тестируемая подпрограмма не содержит ничего, кроме основных арифметических операций (без вызовов библиотеки) и выполняется на идентичном оборудовании. –

+0

@StephenCanon: даже при использовании идентичного оборудования возможно, что код выполняет «a + b» в одном случае и «b + a» в другом; добавление, как ожидается, всегда будет коммутативным, за исключением того, что при добавлении положительного и отрицательного нуля или оба операнда являются NaN (если только один является NaN, результатом должно быть то, что NaN дословно, но если оба являются NaN, стандарт умалчивает о том, должен ли результат быть первым, вторым, «максимальным», «побитовым ИЛИ» или чем-то еще). – supercat

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