Баг или фича

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Баг или фича

Сообщение Osmiy » 11.04.2025 07:08:32

В консольной программе этот код вылетает с ошибкой
Код: Выделить всё
program Project1;

uses Math;

var
  R: Double =0;
begin
  if R=NaN then;
  ReadLn;
end. 


Это так и должно быть или это баг?

Lazarus 3.8 (rev lazarus_3_8) FPC 3.2.2 x86_64-win64-win32/win64
Osmiy
новенький
 
Сообщения: 44
Зарегистрирован: 07.05.2016 21:18:39

Re: Баг или фича

Сообщение Alexander » 11.04.2025 08:40:24

Это не простой вопрос, ведь формально тогда сравниваются нечисло и число. Да и зачем-то функция https://lazarus-ccr.sourceforge.io/docs ... isnan.html есть. В документации о сравнении с числами ничего не сказано.

FPC 3.3.1, Linux, gdb:

Код: Выделить всё
Reading symbols from ./Project1...
(gdb) r
Starting program: /tmp/Project1
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGFPE, Arithmetic exception.
0x00005555555800ab in $main () at Project1.pas:8
8         if R=NaN then;
(gdb) bt
#0  0x00005555555800ab in $main () at Project1.pas:8


При такой проверке ошибки не происходит:

Код: Выделить всё
program Project1;
uses Math;
begin
if (0/0)=NaN then WriteLn('*');
end.
Аватара пользователя
Alexander
энтузиаст
 
Сообщения: 821
Зарегистрирован: 18.12.2005 19:10:00
Откуда: оттуда

Re: Баг или фича

Сообщение Osmiy » 11.04.2025 10:04:33

Alexander писал(а):функция https://lazarus-ccr.sourceforge.io/docs ... isnan.html есть.
Спасибо, то что надо.

Alexander писал(а):Это не простой вопрос, ведь формально тогда сравниваются нечисло и число.
Просто мой вычислительный код спокойно работал в LCL приложении, а когда я его в консоли стал использовать, все эти проверки посыпались. Не хорошо это.
Osmiy
новенький
 
Сообщения: 44
Зарегистрирован: 07.05.2016 21:18:39

Re: Баг или фича

Сообщение iskander » 11.04.2025 10:07:49

Osmiy писал(а):Это так и должно быть или это баг?

NaN - одно из особых состояний числа с плавающей точкой(нечисло), при попытке сравнения обычного числа с NaN возникает исключительная ситуация FPU.
Для проверки на NaN можно использовать хелпер из модуля SysUtils
Код: Выделить всё
  if d.IsNaN then
    ...

Если замаскировать исключение средствами модуля Math
Код: Выделить всё
  SetExceptionMask(GetExceptionMask + [exInvalidOp]);
  if d = NaN then
    ...   

то возникать оно не будет, но результатом такого сравнения всегда будет False.
iskander
энтузиаст
 
Сообщения: 611
Зарегистрирован: 08.01.2012 18:43:34

Re: Баг или фича

Сообщение Alex2013 » 11.04.2025 17:32:18

Мдя "тихие нечисла" вещь в себе . (Честно говоря никогда не думал, что есть возможность добраться до них из кода на паскале )
Зы
В чем смысл сравнения ? Это же состояние FPU по идее его вообще нельзя записать в переменную. :roll:
То есть после какой-то операции оно может вылезти "как фаг" но пустая примерная которая просто лежит в памяти ни как содержать нечисло не может . Именно в этом смысл этого кода if (0/0)=NaN then WriteLn('*'); что-то сделано и это можно проверить но записать нечисло в переменную по идее нельзя (впрочем я опыта использования NaN не имею так что могу ошибаться )
Зы Зы

IsNan (А)
https://lazarus-ccr.sourceforge.io/docs ... isnan.html
По идее верно так
Код: Выделить всё
program Project1;

uses Math;

var
  R: Double =0;
begin
  if IsNan( R ) then  WriteLn('*');
  ReadLn;
end.
Alex2013
долгожитель
 
Сообщения: 3124
Зарегистрирован: 03.04.2013 11:59:44

Re: Баг или фича

Сообщение xchgeaxeax » 11.04.2025 19:03:35

Alex2013 писал(а):Мдя "тихие нечисла" вещь в себе . (Честно говоря никогда не думал, что есть возможность добраться до них из кода на паскале )
Зы
В чем смысл сравнения ? Это же состояние FPU по идее его вообще нельзя записать в переменную.
То есть после какой-то операции оно может вылезти "как фаг" но пустая примерная которая просто лежит в памяти ни как содержать нечисло не может . Именно в этом смысл этого кода if (0/0)=NaN then WriteLn('*'); что-то сделано и это можно проверить но записать нечисло в переменную по идее нельзя (впрочем я опыта использования NaN не имею так что могу ошибаться )
Зы Зы

Вы правы, что NaN это состояние сопроцессора. Но формат Extended (10-ти байтовое) для x87 вполне может хранить NaN. Тогда как Double или Single такого не могут.
xchgeaxeax
постоялец
 
Сообщения: 176
Зарегистрирован: 11.05.2023 03:51:40

Re: Баг или фича

Сообщение iskander » 11.04.2025 19:11:49

xchgeaxeax писал(а):Вы правы, что NaN это состояние сопроцессора. Но формат Extended (10-ти байтовое) для x87 вполне может хранить NaN. Тогда как Double или Single такого не могут.

Но это не точно? :)
Код: Выделить всё
uses
  SysUtils, Math;
var
  d: Double;
  s: Single;
begin
  SetExceptionMask(GetExceptionMask + [exInvalidOp]);
  d := Double.NaN;
  s := Single.NaN;
  SetExceptionMask(GetExceptionMask - [exInvalidOp]);
  if d.IsNan then
    WriteLn('Ich bin Double NaN!');
  if s.IsNan then
    WriteLn('Ich bin Single NaN!');
end.
iskander
энтузиаст
 
Сообщения: 611
Зарегистрирован: 08.01.2012 18:43:34

Re: Баг или фича

Сообщение Sergei I. Gorelkin » 12.04.2025 07:28:41

Любое число с плавающей запятой, у которого все биты порядка равны 1, а биты мантиссы не равны 0 (за исключением скрытого бита), считается NaN.
Операции с NaN вызывают исключение, а если исключения замаскированы, то результатом будет тоже NaN.
Операции сравнения с NaN при замаскированных исключениях всегда имеют результат false, кроме сравнения на неравенство, которое дает true. В отношении сравнений FPC ведет себя аналогично GCC, но отличается от старых Delphi (насчет новых не в курсе).

Выражения вида if (0/0)=NaN ..., скорее всего, вычисляются во время компиляции и не вызывают исключений при выполнении.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1406
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград


Вернуться в Free Pascal Compiler

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

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

Рейтинг@Mail.ru