2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




На страницу 1, 2, 3, 4  След.
 
 Отрицательный ноль и его идентификация
Сообщение18.09.2019, 16:21 
Известно, что форматы чисел с плавающей точкой предусматривают наличие отрицательного нуля. Свойства этого числа таковы, что
Код:
(-0==0)=true;
1/(-0)=-inf;

В общем, практически, отрицательный ноль мало чем отличается от положительного. Из за этого, возникает проблема с его идентификацией.
Истинный результат проверки
Код:
if (x==-x)

свидетельствует о том, что x=0 или x=-0, и не позволяет отличить 0 от -0.
В языке С была функция signbit(), позволяющая это сделать, но компилятор VC2010 пишет, что идентификатор не найден (math.h включена).
В связи с этим возникает вопрос, что signbit() теперь уже не поддерживается? Из материалов, почерпнутых из сети, можно сделать смутные выводы о том, что это зависит от конкретного компилятора.
Если она не поддерживается, есть ли какие то альтернативные пути идентификации отрицательного нуля?

 
 
 
 Re: Отрицательный ноль и его идентификация
Сообщение18.09.2019, 16:45 
Аватара пользователя
Судя по списку в https://docs.microsoft.com/en-us/previo ... dvs.100%29 , в VC++2010 ее действительно не было. В более новых версиях должна быть, она вошла в стандарт C++11. Простейший способ различить нули - взять 1/x, это будет бесконечость соответствующего знака, ее уже можно сравнить с нулем.

 
 
 
 Re: Отрицательный ноль и его идентификация
Сообщение18.09.2019, 16:57 
Насколько мне известно, единственный способ нормально писать на C в Visual Studio - это писать на общем подмножестве C и C++ и использовать компилятор C++. Вменяемого компилятора C у MS нет.

 
 
 
 Re: Отрицательный ноль и его идентификация
Сообщение18.09.2019, 17:00 
warlock66613 в сообщении #1415694 писал(а):
использовать компилятор C++

так оно и делается

-- 18.09.2019, 18:09 --

Xaositect в сообщении #1415690 писал(а):
Простейший способ различить нули - взять 1/x

да, но тогда потребуется проверка двойного условия
Код:
if (1/x<0 && x==0)

ну и операция 1/x как то смущает, нет ли чего нибудь более адекватного?
например, проверка NaN осуществляется просто, есть isnan(), или можно так:
Код:
if (x!=x)

 
 
 
 Re: Отрицательный ноль и его идентификация
Сообщение18.09.2019, 17:26 
Xaositect в сообщении #1415690 писал(а):
Простейший способ различить нули - взять 1/x, это будет бесконечость соответствующего знака, ее уже можно сравнить с нулем.
У меня тут некоторое сомнение: бесконечность ведь выдаётся если замаскировано исключение деления на ноль или обработчик исключения выдаст именно бесконечность. Но ведь он может выдать и что-то другое, да и вообще закрыть программу. А кроме того, время отработки этого исключения может быть достаточно велико (на порядки дольше самого деления). В общем похоже метод недостаточно универсальный ... Что по этому поводу стандарты говорят?

Надёжный работающий способ - ориентироваться на битовое представление форматов и проверять старший бит числа. Для IEEE 754 работает, и быстро. Но плохо совместимо/переносимо.

 
 
 
 Re: Отрицательный ноль и его идентификация
Сообщение18.09.2019, 17:35 
Andrey_Kireew в сообщении #1415695 писал(а):
нет ли чего нибудь более адекватного?
Использовать компилятор новее. Это будет адекватнее с точки зрения полноты соответствия со стандартом C99 (или ещё лучше с C11).

(Оффтоп)

Andrey_Kireew в сообщении #1415684 писал(а):
Известно, что форматы чисел с плавающей точкой предусматривают наличие отрицательного нуля.
Вообще говоря, не все. Соответствующие стандарту IEEE 754 — да.


-- Ср сен 18, 2019 19:36:29 --

Ещё можно свою функцию написать, посмотрев на реализацию signbit откуда-нибудь. (И если в ней например используется два сравнения, то так тому и быть.)

-- Ср сен 18, 2019 19:38:06 --

Точнее, возможно, макрос. В C99/C11 это, говорят, макрос.

 
 
 
 Re: Отрицательный ноль и его идентификация
Сообщение18.09.2019, 17:49 
Угу, макрос, только зависит от реализации. Вот один из примеров math.h:
Используется синтаксис C
/* 7.12.3.6 The signbit macro */
extern __inline__ int __signbit (double x) {
  unsigned short stw;
  __asm__ ( "fxam; fstsw %%ax;": "=a" (stw) : "t" (x));
  return stw & 0x0200;
}
Как видно используются стандартные ассемблерные команды x86 для анализа числа. Зато никаких исключений и работает быстро. И кроме -0.0 правильно проверяет и -NaN.
Для isnan() тоже используется та же fxam с другими масками.

 
 
 
 Re: Отрицательный ноль и его идентификация
Сообщение18.09.2019, 17:50 
Dmitriy40 в сообщении #1415699 писал(а):
исключение деления на ноль
Какое исключение деления на ноль в FPU?
arseniiv в сообщении #1415701 писал(а):
Ещё можно свою функцию написать, посмотрев на реализацию signbit откуда-нибудь
Ну, вот, например, в GCC это ассемблерная функция.

 
 
 
 Re: Отрицательный ноль и его идентификация
Сообщение18.09.2019, 17:58 
Аватара пользователя
Никакие операторы C/C++ для таких вещей использовать нельзя. В языке(ах) C/C++ модель чисел с плавающей точкой - более простая, чем в IEEE 754, великом и благословенном. Чтобы правильно понимать данное битовое значение в понятиях IEEE 754, следует пользоваться специальными сделанными для этого функциями (макросами), желательно стандартными.

При высоком уровне гичества - можно самому тестить битовые маски. (И это, в принципе, будет даже переносимо, потому что IEEE 754 развивается под флагом обратной совместимости.)

 
 
 
 Re: Отрицательный ноль и его идентификация
Сообщение18.09.2019, 18:16 

(Исключения в FPU)

warlock66613 в сообщении #1415709 писал(а):
Dmitriy40 в сообщении #1415699 писал(а):
исключение деления на ноль
Какое исключение деления на ноль в FPU?
Ну например такое (привожу по документу 325462-sdm-vol-1-2abcd-3abcd.pdf с названием "Intel® 64 and IA-32 Architectures Software Developer’s Manual":
Цитата:
4.9.1.3 Divide-By-Zero Exception (#Z)
The processor reports the floating-point divide-by-zero exception whenever an instruction attempts to divide a finite non-zero operand by 0. The masked response for the divide-by-zero exception is to set the ZE flag and return an infinity signed with the exclusive OR of the sign of the operands. If the divide-by-zero exception is not masked, the ZE flag is set, a software exception handler is invoked, and the operands remain unaltered.
See the following sections for information regarding the divide-by-zero exception when detected while executing x87 FPU or SSE/SSE2 instructions:
• x87 FPU; Section 8.5.3, “Divide-By-Zero Exception (#Z)”
• SIMD floating-point exceptions; Section 11.5.2.3, “Divide-By-Zero Exception (#Z)”
Обратите внимание на выделенное мною жирным.
Цитата:
8.5.3 Divide-By-Zero Exception (#Z)
The x87 FPU reports a floating-point divide-by-zero exception whenever an instruction attempts to divide a finite non-zero operand by 0. The flag (ZE) for this exception is bit 2 of the x87 FPU status word, and the mask bit (ZM) is bit 2 of the x87 FPU control word. The FDIV, FDIVP, FDIVR, FDIVRP, FIDIV, and FIDIVR instructions and the other instructions that perform division internally (FYL2X and FXTRACT) can report the divide-by-zero exception.
When a divide-by-zero exception occurs and the exception is masked, the x87 FPU sets the ZE flag and returns the values shown in Table 8-10. If the divide-by-zero exception is not masked, the ZE flag is set, a software exception handler is invoked (see Section 8.7, “Handling x87 FPU Exceptions in Software”), and the top-of-stack pointer (TOP) and source operands remain unchanged.
Цитата:
11.5.2.3 Divide-By-Zero Exception (#Z)
The processor reports a divide-by-zero exception when a DIVPS, DIVSS, DIVPD or DIVSD instruction attempts to divide a finite non-zero operand by 0. The flag (ZE) and mask (ZM) bits for the divide-by-zero exception are bits 2 and 9, respectively, in the MXCSR register.
See Section 4.9.1.3, “Divide-By-Zero Exception (#Z),” for more information about the divide-by-zero exception.
See Section 11.5.4, “Handling SIMD Floating-Point Exceptions in Software,” for information on handling unmasked exceptions.
The divide-by-zero exception is not affected by the flush-to-zero mode at a single-instruction boundary. While DAZ does not affect the rules for signaling IEEE exceptions, operations on denormal inputs might have different results when DAZ=1. As a consequence, DAZ can have an effect on the floating-point exceptions - including the divide-by-zero exception - when observed for a given operation involving denormal inputs.
Что говорит по этому поводу стандарт и что за код выдают компиляторы - я не в курсе, может там эти исключение замаскированы навсегда ...

 
 
 
 Re: Отрицательный ноль и его идентификация
Сообщение18.09.2019, 18:41 
Dmitriy40 в сообщении #1415707 писал(а):
Угу, макрос, только зависит от реализации. Вот один из примеров math.h

Если уж так случилось, и в VC 2010 этот макрос неосмотрительно не реализован, то можно ли как то его прописать вручную, прямо в программе?
В надежде на чудо, я вставил этот код в глобальную область своей программы, но увы - чуда опять не произошло ...

В каракулях компилятора (а по русски, равно как на любом другом человеческом языке, он со мной общаться отказывается), я разобрал, что он ругается на ";", выглядит это так:
Цитата:
error C2144: бЁ­в ЄбЁзҐбЄ п
®иЁЎЄ : ЇҐаҐ¤ "int" вॡгҐвбп ";"

 
 
 
 Re: Отрицательный ноль и его идентификация
Сообщение18.09.2019, 18:46 
С помощью https://www.artlebedev.ru/decoder/ это сообщение превращается в
Цитата:
error C2144: си­т ксическ я
ошибк : перед "int" требуется ";"

 
 
 
 Re: Отрицательный ноль и его идентификация
Сообщение18.09.2019, 18:57 
warlock66613 в сообщении #1415738 писал(а):
С помощью https://www.artlebedev.ru/decoder/
это сообщение превращается в

спасибо, теперь буду знать

Т.е. этот макрос мне просто так приспособить не получится?

 
 
 
 Re: Отрицательный ноль и его идентификация
Сообщение18.09.2019, 19:02 
Аватара пользователя
Dmitriy40 в сообщении #1415699 писал(а):
В общем похоже метод недостаточно универсальный ... Что по этому поводу стандарты говорят?
Ну это да, в библиотеку такое не положишь. Но чисто для себя, если точно знаешь, что не будешь ловить бесконечности, можно.

Andrey_Kireew в сообщении #1415743 писал(а):
Т.е. этот макрос мне просто так приспособить не получится?
Уберите __inline__ или замените на просто inline. Правда, все равно может не заработать, не уверен, какой синтаксис ассемблерных вставок в VC++.

 
 
 
 Re: Отрицательный ноль и его идентификация
Сообщение18.09.2019, 19:12 
Xaositect в сообщении #1415746 писал(а):
не уверен, какой синтаксис ассемблерных вставок в VC++

да, он потом начал ругаться на строку со вставкой

 
 
 [ Сообщений: 56 ]  На страницу 1, 2, 3, 4  След.


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group