powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Округление в Firebird 3.0
15 сообщений из 15, страница 1 из 1
Округление в Firebird 3.0
    #39726318
inoremap
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Есть программа на "Delphi" работающая с базой данных "Firebird SQL" при помощи компонентов "UIB". Программа может работать с "Firebird SQL" версий 1.5.3.4870 и 3.0.3.32900, во встроенном режиме и с сервером по TCP.

При работе во встроенном режиме с версией 3.0.3.32900 запрос
Код: sql
1.
select cast(cast(cast('16.575' as double precision) as numeric(10, 2)) as varchar(11)) "fSum" from rdb$database

возвращает результат "16.57", но при подключении по TCP с версией 3.0.3.32900, а также с версией 1.5.3.4870 в любом режиме результат выполнения запроса - "16.58".

В программе "isql.exe", запущенной во встроенном режиме с библиотеками "Firebird SQL" 3.0.3.32900, которые поставляются с программой на "Delphi", запрос также возвращает "16.58".

Если в программе на "Delphi", во встроенном режиме с версией 3.0.3.32900, перед выполнением запроса вызвать процедуру "SetRoundMode(rmUp)", то результат запроса будет таким же как и в остальных вариантах - "16.58".

Если не вызывать "SetRoundMode(rmUp)", то функция "Get8087CW" во всех вариантах подключения возвращает 0x1372.

Чем может быть вызвано отличие в результатах запроса, и есть ли способ получить результат "16.58" в всех вариантах без изменения способа округления?
...
Рейтинг: 0 / 0
Округление в Firebird 3.0
    #39726439
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
inoremap,

ну а чего ты хочешь. Если используешь Embedded, то Firebird работает в его адресном пространстве и подчиняется правилам которые установлены для твоего приложения
...
Рейтинг: 0 / 0
Округление в Firebird 3.0
    #39726444
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
inoremapперед выполнением запроса вызвать процедуру "SetRoundMode(rmUp)", то результат запроса будет таким же как и в остальных вариантах - "16.58".

Почему не rmNearest?
...
Рейтинг: 0 / 0
Округление в Firebird 3.0
    #39726454
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
inoremapесть ли способ получить результат "16.58" в всех вариантах без изменения способа округления?

Есть: никогда не доверяй серверу арифметику сложнее сложения и вычитания. Получай чистый
результат и округляй так как тебе нужно самостоятельно.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Округление в Firebird 3.0
    #39726475
inoremap
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Симонов Денисну а чего ты хочешь. Если используешь Embedded, то Firebird работает в его адресном пространстве и подчиняется правилам которые установлены для твоего приложения Встроенный 1.5 возвращает "16.58", и вряд ли "isql.exe" меняет способ округления. Попробую еще сделать UDF с "Get8087CW" для проверки.
Симонов ДенисПочему не rmNearest?Во всех вариантах кроме "rmUp" результат - "16.57".
...
Рейтинг: 0 / 0
Округление в Firebird 3.0
    #39726484
hvlad
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
fbclient при каждом входе в API запоминает текущую маску сопроцессора, ставит стандартную (в ней округление к ближайшему чётному и замаскированы прерывания) и при выходе из API восстанавливает маску.
Проблемы могут быть только если UDF поменяла маску и не восстановила её за собой.


inoremapВо всех вариантах кроме "rmUp" результат - "16.57".Верится с трудом
...
Рейтинг: 0 / 0
Округление в Firebird 3.0
    #39726554
inoremap
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hvladinoremapВо всех вариантах кроме "rmUp" результат - "16.57".Верится с трудомПроект с воспроизведением проблемы - https://yadi.sk/d/Nf_DdMP_2zPTmQ в архиве собранный "exe" файл и исходные тексты для Delphi 5.
...
Рейтинг: 0 / 0
Округление в Firebird 3.0
    #39726569
hvlad
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
inoremap,

у нас нет яндекса
...
Рейтинг: 0 / 0
Округление в Firebird 3.0
    #39726575
inoremap
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
Округление в Firebird 3.0
    #39726838
hvlad
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
inoremap,

добавь аналогичное округление в Delphi код и выведи его в лог.

Потом сделай вот так
Код: pascal
1.
2.
3.
4.
var
  d : Double;
begin
  d := 16.575;


И посмотри в отладчике на d - расскажи, что видишь
...
Рейтинг: 0 / 0
Округление в Firebird 3.0
    #39726840
hvlad
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hvladfbclient при каждом входе в API запоминает текущую маску сопроцессора, ставит стандартную (в ней округление к ближайшему чётному и замаскированы прерывания) и при выходе из API восстанавливает маску.Тут я немного ошибся, похоже.
В статусном регистре сопроцессора меняется только режим маскирования прерываний, режим округления (и прочее) - не меняется.
...
Рейтинг: 0 / 0
Округление в Firebird 3.0
    #39727095
inoremap
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hvladinoremap,
добавь аналогичное округление в Delphi код и выведи его в лог.

Для этого мне надо понимать как округляет "Firebird SQL" 8-(
hvladinoremap,
Потом сделай вот так
Код: pascal
1.
2.
3.
4.
var
  d : Double;
begin
  d := 16.575;


И посмотри в отладчике на d - расскажи, что видишь
Процедура тестирования:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
procedure TForm1.Button1Click(Sender: TObject);
const
  cRoundModeName: array[TFPURoundingMode] of string = ('Nearest', 'Down', 'Up', 'Truncate');
var
  m: TFPURoundingMode;
  d : Double;
begin
  d := 16.575;
  memLog.Lines.Add(Format('d=%1.18f', [d]));
  UIBDataBase1.LibraryName := ExtractFilePath(Application.ExeName) + 'fb30e/fbclient.dll';
  UIBDataBase1.DatabaseName := ExtractFilePath(Application.ExeName) + 'EMPLOYEE.FDB';
  UIBDataBase1.Connected := True;
  try
    for m := Low(TFPURoundingMode) to High(TFPURoundingMode) do
    begin
      SetRoundMode(m);
      UIBQuery1.Open(True);
      memLog.Lines.Add(Format('mode=%-8s fSum=%s RoundTo=%1.18f SimpleRoundTo=%1.18f',
        [cRoundModeName[m], UIBQuery1.Fields.ByNameAsString['fSum'], RoundTo(d, -2), SimpleRoundTo(d, -2)]));
    end;
  finally
    UIBDataBase1.Connected := False;
  end;
end;


Результат:
Код: plaintext
1.
2.
3.
4.
5.
d=16,574999999999999300
mode=Nearest  fSum=16.57 RoundTo=16,570000000000000300 SimpleRoundTo=16,570000000000000300
mode=Down     fSum=16.57 RoundTo=16,569999999999996700 SimpleRoundTo=16,579999999999994700
mode=Up       fSum=16.58 RoundTo=16,580000000000001900 SimpleRoundTo=16,570000000000003900
mode=Truncate fSum=16.57 RoundTo=16,569999999999996700 SimpleRoundTo=16,579999999999994700

Собранный исполняемый файл

https://drive.google.com/open?id=10wYa4XM5IVNG4hJFjWqVy_f1XbPQSW_2
...
Рейтинг: 0 / 0
Округление в Firebird 3.0
    #39727115
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
inoremapДля этого мне надо понимать как округляет "Firebird SQL" 8-(

ну так проведи эксперимент

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
SELECT
    CAST(CAST(CAST('16.575' AS DOUBLE PRECISION) AS NUMERIC(10,2)) AS VARCHAR(11)) AS f1,
    CAST(CAST(CAST('16.574' AS DOUBLE PRECISION) AS NUMERIC(10,2)) AS VARCHAR(11)) AS f2,
    CAST(CAST(CAST('16.576' AS DOUBLE PRECISION) AS NUMERIC(10,2)) AS VARCHAR(11)) AS f3,
    CAST(CAST(CAST('-16.575' AS DOUBLE PRECISION) AS NUMERIC(10,2)) AS VARCHAR(11)) AS f4,
    CAST(CAST(CAST('-16.574' AS DOUBLE PRECISION) AS NUMERIC(10,2)) AS VARCHAR(11)) AS f5,
    CAST(CAST(CAST('-16.576' AS DOUBLE PRECISION) AS NUMERIC(10,2)) AS VARCHAR(11)) AS f6
FROM
    RDB$DATABASE
...
Рейтинг: 0 / 0
Округление в Firebird 3.0
    #39727153
hvlad
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
inoremapДля этого мне надо понимать как округляет "Firebird SQLОн не делает ничего специального.

inoremap
Код: plaintext
d=16,574999999999999300
Этого уже достаточно, чтобы объяснить, почему округление к ближайшему чётному даёт 16.57, а не 16.58

Далее, как видишь, и Delphi (RoundTo), и Firebird округляют одинаково.
...
Рейтинг: 0 / 0
Округление в Firebird 3.0
    #39727213
inoremap
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дело оказалось не в режиме округления, а в точности - в "Deplhi" была установлена "Extended Precision", в серверном варианте "Firebird SQL 3.0" - "Double Precision", после установки точности в "Delphi" в "Double Precision" запрос стал возвращать одинаковый результат как при подключении к серверу, так и во встроенном режиме.
...
Рейтинг: 0 / 0
15 сообщений из 15, страница 1 из 1
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Округление в Firebird 3.0
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]