Гость
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Округление в Firebird 3.0 / 15 сообщений из 15, страница 1 из 1
01.11.2018, 09:46
    #39726318
inoremap
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Округление в Firebird 3.0
Есть программа на "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
01.11.2018, 12:02
    #39726439
Симонов Денис
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Округление в Firebird 3.0
inoremap,

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

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

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


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

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

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

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


И посмотри в отладчике на d - расскажи, что видишь
...
Рейтинг: 0 / 0
01.11.2018, 20:31
    #39726840
hvlad
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Округление в Firebird 3.0
hvladfbclient при каждом входе в API запоминает текущую маску сопроцессора, ставит стандартную (в ней округление к ближайшему чётному и замаскированы прерывания) и при выходе из API восстанавливает маску.Тут я немного ошибся, похоже.
В статусном регистре сопроцессора меняется только режим маскирования прерываний, режим округления (и прочее) - не меняется.
...
Рейтинг: 0 / 0
02.11.2018, 11:28
    #39727095
inoremap
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Округление в Firebird 3.0
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
02.11.2018, 11:45
    #39727115
Симонов Денис
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Округление в Firebird 3.0
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
02.11.2018, 12:18
    #39727153
hvlad
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Округление в Firebird 3.0
inoremapДля этого мне надо понимать как округляет "Firebird SQLОн не делает ничего специального.

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

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


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