2014 dxdy logo

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

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




Начать новую тему Ответить на тему На страницу 1, 2, 3, 4  След.
 
 Отрицательный ноль и его идентификация
Сообщение18.09.2019, 16:21 


07/10/15

2400
Известно, что форматы чисел с плавающей точкой предусматривают наличие отрицательного нуля. Свойства этого числа таковы, что
Код:
(-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 
Заслуженный участник
Аватара пользователя


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

 Профиль  
                  
 
 Re: Отрицательный ноль и его идентификация
Сообщение18.09.2019, 16:57 
Заслуженный участник


02/08/11
6892
Насколько мне известно, единственный способ нормально писать на C в Visual Studio - это писать на общем подмножестве C и C++ и использовать компилятор C++. Вменяемого компилятора C у MS нет.

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


07/10/15

2400
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 
Заслуженный участник


20/08/14
11177
Россия, Москва
Xaositect в сообщении #1415690 писал(а):
Простейший способ различить нули - взять 1/x, это будет бесконечость соответствующего знака, ее уже можно сравнить с нулем.
У меня тут некоторое сомнение: бесконечность ведь выдаётся если замаскировано исключение деления на ноль или обработчик исключения выдаст именно бесконечность. Но ведь он может выдать и что-то другое, да и вообще закрыть программу. А кроме того, время отработки этого исключения может быть достаточно велико (на порядки дольше самого деления). В общем похоже метод недостаточно универсальный ... Что по этому поводу стандарты говорят?

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

 Профиль  
                  
 
 Re: Отрицательный ноль и его идентификация
Сообщение18.09.2019, 17:35 
Заслуженный участник


27/04/09
28128
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 
Заслуженный участник


20/08/14
11177
Россия, Москва
Угу, макрос, только зависит от реализации. Вот один из примеров 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 
Заслуженный участник


02/08/11
6892
Dmitriy40 в сообщении #1415699 писал(а):
исключение деления на ноль
Какое исключение деления на ноль в FPU?
arseniiv в сообщении #1415701 писал(а):
Ещё можно свою функцию написать, посмотрев на реализацию signbit откуда-нибудь
Ну, вот, например, в GCC это ассемблерная функция.

 Профиль  
                  
 
 Re: Отрицательный ноль и его идентификация
Сообщение18.09.2019, 17:58 
Заслуженный участник
Аватара пользователя


30/01/06
72407
Никакие операторы C/C++ для таких вещей использовать нельзя. В языке(ах) C/C++ модель чисел с плавающей точкой - более простая, чем в IEEE 754, великом и благословенном. Чтобы правильно понимать данное битовое значение в понятиях IEEE 754, следует пользоваться специальными сделанными для этого функциями (макросами), желательно стандартными.

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

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


20/08/14
11177
Россия, Москва

(Исключения в 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 


07/10/15

2400
Dmitriy40 в сообщении #1415707 писал(а):
Угу, макрос, только зависит от реализации. Вот один из примеров math.h

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

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

 Профиль  
                  
 
 Re: Отрицательный ноль и его идентификация
Сообщение18.09.2019, 18:46 
Заслуженный участник


02/08/11
6892
С помощью https://www.artlebedev.ru/decoder/ это сообщение превращается в
Цитата:
error C2144: си­т ксическ я
ошибк : перед "int" требуется ";"

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


07/10/15

2400
warlock66613 в сообщении #1415738 писал(а):
С помощью https://www.artlebedev.ru/decoder/
это сообщение превращается в

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

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

 Профиль  
                  
 
 Re: Отрицательный ноль и его идентификация
Сообщение18.09.2019, 19:02 
Заслуженный участник
Аватара пользователя


06/10/08
6422
Dmitriy40 в сообщении #1415699 писал(а):
В общем похоже метод недостаточно универсальный ... Что по этому поводу стандарты говорят?
Ну это да, в библиотеку такое не положишь. Но чисто для себя, если точно знаешь, что не будешь ловить бесконечности, можно.

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

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


07/10/15

2400
Xaositect в сообщении #1415746 писал(а):
не уверен, какой синтаксис ассемблерных вставок в VC++

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

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 56 ]  На страницу 1, 2, 3, 4  След.

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group