Форум » [x]Harbour » Неправильная работа функции Int() » Ответить

Неправильная работа функции Int()

ort: Всем привет! Все больше и больше тестирую свое ПО на Харборе. Работаю с большими числами и вот что выяснилось. Функция Int() работает с ошибками: Int(10^15) = 1000000000000000 Int(10^16) = 10000000000000002 :( Int(10^17) = 100000000000000016 :( Int(10^18) = 1000000000000000256 :( Int(10^19) = 10000000000000000000 Int(10^20) = 100000000000000000000 Кстати, на Клиппере все OK. Харбор 3.2 февральский. Это можно как-то исправить?

Ответов - 14

ort: Может быть, проблема в функции Round(): Round(10^15,0) = 1000000000000000 Round(10^16,0) = 10000000000000002 :( Round(10^17,0) = 100000000000000016 :( Round(10^18,0) = 1000000000000000256 :( Round(10^19,0) = 10000000000000000000 Round(10^20,0) = 100000000000000000000

Dima: http://clipper.borda.ru/?1-4-0-00001174-000-0-0-1486814959

ort: Dima, спасибо, но я не могу понять, почему результат разный n := 10000000000000000 // 17 цифр Int(n) = Round(n,0) = 10000000000000000 // OK n := 10^16 // те же 17 цифр Int(n) = Round(n,0) = 10000000000000002 // :(


ort: Если поставить десятичную точку, то вылезает та же двойка n := 10000000000000000.0 // 17 цифр Int(n) = Round(n,0) = 10000000000000002 // :(( n := 10^16 // те же 17 цифр Int(n) = Round(n,0) = 10000000000000002 // :((

ort: n := 10^16 // те же 17 цифр Int(n) = Round(n,0) = 10000000000000002 // А вот так работает: n := Val(Str(10^16,20,0)) // те же 17 цифр Int(n) = Round(n,0) = 10000000000000000 //

Pasha: ort пишет: Dima, спасибо, но я не могу понять, почему результат разный n := 10000000000000000 // 17 цифр Int(n) = Round(n,0) = 10000000000000000 // OK n := 10^16 // те же 17 цифр Int(n) = Round(n,0) = 10000000000000002 // :( В первом случае внутреннее представление n - это 64-битное целое, без потери точности. Во втором случае n представлено как double с потерей точности, так как значности 52-х битной мантиссы уже не хватает. Результат 2^n тоже будет double с потерей точности Странно не то, что харбор дает потерю точности, как раз так и должно быть. Странно то, что 16-битный клиппер работает без потери точности. В харборе функция int реализована через сишную функцию modf, завтра попробую глянуть, как это сделано в клиппере.

ort: Pasha пишет: В первом случае внутреннее представление n - это 64-битное целое, без потери точности. Во втором случае n представлено как double с потерей точности, так как значности 52-х битной мантиссы уже не хватает. Результат 2^n тоже будет double с потерей точности До меня тоже уже дошло! Паша, а почему во втором случае результат правильный? Round(10^18,0) = 1000000000000000256 :( Round(10^19,0) = 10000000000000000000

Pasha: ort пишет: Функция Int() работает с ошибками: Int(10^15) = 1000000000000000 Int(10^16) = 10000000000000002 :( Int(10^17) = 100000000000000016 :( Int(10^18) = 1000000000000000256 :( Int(10^19) = 10000000000000000000 Int(10^20) = 100000000000000000000 Кстати, на Клиппере все OK. Ну хоть на этот вопрос ответ нашелся. В функции int (и round) харбора зачем-то используется такой трюк: #if defined( HB_DBLFL_PREC_FACTOR ) && ! defined( HB_CLP_STRICT ) /* Similar hack as in round to make this functions compatible */ dNum *= HB_DBLFL_PREC_FACTOR; #endif HB_DBLFL_PREC_FACTOR это #define HB_DBLFL_PREC_FACTOR 1.0000000000000002; кто это сделал, когда и для какой совместимости - непонятно. Но как раз для 10**16 и выше это и дает погрешность. Если убрать умножение на 1.0000000000000002, то результат становится правильным, как и в клиппере. Может быть это умножение для чего-то и нужно, но не для нашего случая

ort: Паша, погрешность только для 10^16, 10^17, 10^18, а для 10^19 и больше ее нет.

ort: Паша, вот что я нашел в файле C:\hb32\include\hbdefs.h: /* This value is used to hack the double FL value in round/int operation - similar thing is done by CL5.3 - I do not know only the exact factor value but it should be close to this one. When HB_CLP_STRICT is set this macro is not used. */ #define HB_DBLFL_PREC_FACTOR 1.0000000000000002; Приблизительный перевод: Это значение используется для взлома значения FL double в операции round/int аналогично CL5.3 - не знаю только точное значение множителя, но оно должно быть близко к этому. Когда HB_CLP_STRICT определено, этот макрос не используется.

Pasha: Да, до 2004 года реализация int была через вызовы floor/ceil. Затем было несколько переделок, в результате все пришло к такому виду. В комментариях еще написано, что точность гарантируется вплоть до 15-ти знаков, а больше в бизнес-процессах и не надо. Якобы в клиппере 5.3 так делается. Я запускал тесты на клиппере 5.2, там вроде такого нет. На 5.3 не собирал. Сейчас на 64-битных системах собирать клиппер-программы то еще удовольствие. Можно сделать свой аналог INT, без такой корректировки, чтобы не пересобирать харбор с макросом HB_CLP_STRICT: [pre]#pragma BEGINDUMP #include "hbapi.h" #include "hbapiitm.h" #include "hbapierr.h" #include "hbmath.h" HB_FUNC( MY_INT ) { PHB_ITEM pNumber = hb_param( 1, HB_IT_NUMERIC ); if( pNumber ) { if( HB_IS_NUMINT( pNumber ) ) hb_itemReturn( pNumber ); else { int iWidth; double dInt; ( void ) modf( hb_itemGetND( pNumber ), &dInt ); hb_itemGetNLen( pNumber, &iWidth, NULL ); hb_retnlen( dInt, iWidth, 0 ); } } else hb_errRT_BASE_SubstR( EG_ARG, 1090, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); } #pragma ENDDUMP [/pre]

SergKis: Pasha пишет Сейчас на 64-битных системах собирать клиппер-программы то еще удовольствие. С DosBox на 64 битных системах отлично clipper от Summer 87 и далее работает и собирается. Можно запустить VC (Волков командер, дос редактор, драйвер клавиатуры как в дос и т.д.) и работать как в дос под ним. Есть ветви от DosBox. Товарищ по работе использует DosBox plus (не уточнял точное название). Он добавил фонты латышские, там работают Windows Run с ожиданием и без и есть какие то свои примочки и все ok. Знаю только с его слов пока, т.к. свои проги (на bat файлах) clipper+hb+vo+wvt пошли с DosBox из темы http://clipper.borda.ru/?1-0-0-00000601-000-0-0-1578415122 под управлением менеджера на hmg ext.

ort: Pasha пишет: Можно сделать свой аналог INT, без такой корректировки, чтобы не пересобирать харбор с макросом HB_CLP_STRICT: Спасибо, Паша, так и сделаю!

Pasha: SergKis пишет: С DosBox на 64 битных системах отлично clipper от Summer 87 и далее работает и собирается. Можно запустить VC (Волков командер, дос редактор, драйвер клавиатуры как в дос и т.д.) и работать как в дос под ним. Именно этими продуктами я и пользуюсь



полная версия страницы