Форум » [x]Harbour » Волшебные числа и операции » Ответить

Волшебные числа и операции

AndreyZh: Доброе утро! Вот наткнулся на очередную ошибку xHarbour и Clipper. Думал, что глюк ОС или ПК, но нет. Пример ошибки - оператор "остаток от деления": 8.8 * 3 = 26.4 или 3.3 * 3 = 9.9, но операции (%) дают 26.4%8.8 = 8.8 или (НО правильно) 9.9%3.3 = 0 Вопрос - как Вы обходите данные глюки? Или где в "арифметике" ожидать очередных "засад"? До кучи напомню об ошибочной работе функции Int в Clipper (в xHarbour кажется работает правильно)

Ответов - 150, стр: 1 2 3 4 5 6 7 8 All

Петр: AndreyZh пишет: Вот наткнулся на очередную ошибку xHarbour и Clipper. Думал, что глюк ОС или ПК, но нет. #include <stdio.h> #include <math.h> [pre2]int main( void ) { double d1 = fmod( 9.9, 3.3 ); double d2 = fmod( 26.4, 8.8 ); printf( "9.9%%3.3=%f, 26.4%%8.8=%f\n", d1, d2 ); return 0; } [/pre2] Протестируйте с любым доступным вам С компилятором. У меня PellesC 6.5 "отличился", вывел 9.9%3.3=3.300000, 26.4%8.8=8.800000 все остальные (ms vc 15; bcc 5.5, 5.82, 6.3; mingw 3.5, 4.5.1 ) > 9.9%3.3=0.000000, 26.4%8.8=8.800000 AndreyZh пишет: Или где в "арифметике" ожидать очередных "засад"? Вот на таком коде упадет BCC [pre2] proc main() local i, n n := 1 for i:=1 to 100000 n*=2 next ? n return[/pre2]

AndreyZh: Петр - спасибо! Хотя и не успокоили... Запустил поиск и уменя в программе операция (%) более 1000 раз, ну алгоритмы такие размножал... Как можно попытаться порешать эти проблемки? По проверке на других компиляторах - мне доступны и проверил на C#/VFP5 ошибок не получил! А пример кода "роняющего" программу сейчас проверю - очень интересно!

AndreyZh: Действительно роняет! Но мне проще - мои финансовые программы не работают с такими размерностями


Петр: AndreyZh пишет: операция (%) более 1000 раз, ну алгоритмы такие размножал... Как можно попытаться порешать эти проблемки? По проверке на других компиляторах - мне доступны и проверил на C#/VFP5 ошибок не получил! Перестаньте вы называть эту особенность ошибкой. Операция взятия остатка в различных языках программирования реализованы по разному. И поэтому некорректно сравнивать результаты Clipper ([x]Harbour) из семейства xBase c C#. Clipper и [x]Harbour позволяют получить одни и те же результаты - и это главное. [x]Harbour унаследовал все ошибки функции Mod() и оператора % от Clipper и это документированная особенность. Не знаю, что вы хотели бы увидеть, но мне кажется, что что-то типа [pre2]#xtranslate <xExp1> % <xExp2> => fMod( <xExp1>, <xExp2> ) FUNCTION main SET DECIMALS TO 2 SET FIXED ON ? " 8.8 * 3.0 =", 8.8 * 3.0 ? " 3.3 * 3.0 =", 3.3 * 3.0 ? ? " 18.5 % 4.2 =", 18.5 % 4.2 ? ? " 26.4 % 8.8 =", 26.4 % 8.8 ? " 9.9 % 3.3 =", 9.9 % 3.3 ? "-26.4 % 8.8 =", -26.4 % 8.8 ? " -9.9 % 3.3 =", -9.9 % 3.3 ? " 26.4 %-8.8 =", 26.4 % -8.8 ? " 9.9 %-3.3 =", 9.9 % -3.3 RETURN 0 FUNCTION fMod( x, y ) RETURN x - Round( x/y, 0 ) * y [/pre2] Вот в этом направлении и двигайтесь.

AndreyZh: Спасибо! - Это идея, но разве на Clipper могу переопределить оператор (%)?

Петр: Во-первых, вы попробуйте, за #xtranslate <xExp1> % <xExp2> => fMod( <xExp1>, <xExp2> ) отвечает препроцессор, Clipper ни о чем и не догадывается, что ему собираются подсунуть. Во вторых с помощью какого-то gsar, sed или других утилит сделать 1000 замен, что раз плюнуть. В третьих я же вам не предложил ASSOCIATE CLASS ... OPERATOR "%" ... и т.п.

AndreyZh: Спасибо... Этой же ерундой уже занимаюсь! Увы % это не только знак "операции", но и обозначения "процента", использующегося в бизнесе. Да'с сколько еще открытий чудных меня ожидает?

AndreyZh: AndreyZh пишет: Да'с сколько еще открытий чудных меня ожидает? Добрый день! Очередные "детские грабельки", на которые потратил часок: Использую DBU пересобранную (какие-то несовместимости Clipper--xHarbour убирал), а пересобрать пришлось из-за обсуждённой раннее несовместимости индексных файлов NTX в данных системах. Но по мере увеличения числа users варианта программы на xHarbour и соотвтственно более частого использования данной утилиты обнаружил небольшой глюк - при создании индексного файла отрезались первые два знака ключевого выражения. Писалось "правильное" выражение и проблема "снималась" - решил разобраться в причине: очередная "засада"... выяснил только по одной функашке, к счастью не использующейся мной в программах: Функция IndexExp() - расширение индексного файла рабочей области в Clipper возвращает ".NTX", а в xHarbour ".ntx" Причём все примеры от "Clipper" и многие "тупо перенесённые" от xHarbour производят сравнения в стиле (IndexExp() = ".NTX") и аналогично в исходниках DBU, что в общем неправильно, а надо везде (Upper(IndexExp()) = ".NTX"). Другие ф-ции с данной "особенностью" искать пока недосуг , но может быть Вам известны другие "грабельки", связанные с несовместимостью Clipper & xHarbour? Вспомнил. В xHarbour нет ф-ции PrintReady, но есть "аналог" IsPrinter - как то быстро разобрался

Pasha: AndreyZh пишет: Функция IndexExp() - расширение индексного файла рабочей области в Clipper возвращает ".NTX", а в xHarbour ".ntx" У меня сохранились сырцы Харбора версии 0.39 от 2002 года, и там уже IndexExt() был на нижнем регистре. Почему ? Я могу только сказать, что так сложилось исторически. Возможно, разработчики ориентировались на *nix, где принято использовать нижний регистр.

Andrey: AndreyZh пишет: В xHarbour нет ф-ции PrintReady, но есть "аналог" IsPrinter - как то быстро разобрался Пользуйся поиском на форуме. Много чего узнаешь интересного... http://clipper.borda.ru/?1-20-0-00000363-000-0-0-1200576623 AndreyZh пишет: может быть Вам известны другие "грабельки", связанные с несовместимостью Clipper & xHarbour? Можешь открыть отдельную тему. Но только перечень этих несовместимостей.

AndreyZh: Andrey пишет: Пользуйся поиском на форуме. Много чего узнаешь интересного... http://clipper.borda.ru/?1-20-0-00000363-000-0-0-1200576623 Уважаемый тёзка! Проблема "грабель" и "несовместимостей" заключается в том, что они выявляются в процессе реальной работы реального приложения, т.е. возникает проблема, там где её никогда не было. Только после этого начинается поиск её источника и даже трижды перечитав данный весьма полезный форум сложно ассоциировать "грабли" с конкретным обсуждением!!! Посему изредка эти "грабли" описываю, что часть проблем другие смогли избежать. Форум крайне полезен, когда возникает конкретный вопрос использованию конкретных возможностей, но увы в меньшей степени помогает избежать проблем в "очевидных" вещах. Можешь открыть отдельную тему. Но только перечень этих несовместимостей. Довольно много их с вашей помощью обсудили в "простынках": 1. http://clipper.borda.ru/?1-4-100-00000527-000-0-0-1270323717 2. http://clipper.borda.ru/?1-3-0-00000137-000-0-0-1287163818 Но "ОБСУЖДЕНИЯ" очень сильно помогают в решении проблемы, но при этом сильно "ПРЯЧУТ" конкретные проблемы за потоком сопутствующей информации, т.е. нужна темы "СО СПИСКОМ ПРОБЛЕМ" без их обсуждений, что только сможет сделать модератор добавляя туда инфу и запрещая "обсуждение" в данной теме. Пока вспомнил ещё "несовместимости": 1. Имею поиск по первым буквам, который не контролировал, т.е. можно искать даже там, где нет последовательности по символам. Более того Clipper пытается искать даже если нет индекса у таблицы по DbSeek() - конечно ничего не находя. xHarbour при такой попытке "вываливается" по ошибке. 2. Более сложно? - Не нашел решения, да и не сильно нужно. Для просмотра больших текстовых файлов использовал ф-цию С.Кроссмана - исходник loopfile.prg, если кто скачивал мою прожку... Она всегда идеально работала, но не с xHarbour: работает во всех режимах, кроме попыток сместиться вверх стрелкой или PgDn - улетает на самую первую строку. Пошаговое тестирование в клиппере показывало "логичную" обработку каждого действия, но xHarbour на любую клавишу ведёт себя, как "пьяная обезьяна" хотя в по большей части приходит к нужному результату. Вопрос для меня не критичен, т.к. оказалось (нигде в иструкциях не нашел), что memoedit работает с файлами любого размера?

Pasha: Здесь необходимо использовать другой подход. Если Вы нашли какую-то несовместимость, которую считаете существенной, то приймите меры, чтобы ее устранить. Устранить можно либо самому, передав фикс разработчикам, либо долбать разработчиков, чтобы это кто-то сделал. И клевать надо не здесь, а непосредственно в майл-листе харбора. Здесь конечно тоже есть разработчики, но очень мало. Мне, к примеру, эта несовместимость по IndexExt совершенно неинтересна. Более того, поскольку я уже много лет программирую не на клиппере, а на харборе, ориентируюсь на нижний регистр. И мне устранение этой несовместимости помешает. Устранить ее - раз плюнуть. Надо в include/hbrddntx.h заменить строку-литерал. Если считаете, что это необходимо - доказывайте это, но не здесь, а в специально предназначенном для этого месте. Не ждите, что это кто-то сделает за Вас. Будьте сами кузнецом своего счастья. Если здесь не помогли, то этим форумом мир харбора не ограничивается. Я, кстати, так и поступал с обнаруженными мной когда-то несовместимостями.

AndreyZh: Pasha пишет: Здесь конечно тоже есть разработчики, но очень мало. Добрый вечер! По видимому реакция Pasha показывает почему ошибки данных систем разработки не "тревожат" посетителей форума. Но всё же если таковые есть, то ещё один крайне серьёзный, непонятный глюк xHarbour (или BCC) (в clipper такой ошибки нет). Если "объяснения" по делению можно было как-то понять, то ошибки выитания (10000.00 - (21832.60 - 11832.60)) * 10000000000 = 0.018189894 (10000.00 - (21932.65 - 11932.65)) * 10000000000 = -0.018189894 (1.00 - (3.00 - 2.00) * 10000000000 = 0.0000

Pasha: В который раз толчем воду в ступе Согласно стандарту IEEE 754, числа двойной точности занимают в памяти 8 байт (64 бита), из которых 1 бит приходится на знак, 52 бита - на мантиссу, и 11 бит - на экспоненту (по основанию 2) Посмотрим, как FPU (не xHarbour, не bcc, а именно FPU) выполнит эту операцию: Local nd := (10000.00 - (21832.60 - 11832.60)) ? Mantissa(nd), Exponent(nd) Результат: 1 -39 т.е. 1*2**(-39) умножаем этот результат на 10**10, и получаем 0.018189894 Если использовать числа четверенной точности, т.е. 128-ми битные, то такой ощибки округления не возникнет. Но и 128-ми битные числа неизбежно дадут ошибку округления по других операндах. Но харбор использует double двойной точности. Опять что-то непонятно ?

Pasha: Чтобы было совсем уж понятно, перепишем немного функцию mantissa, чтобы она возвращала ее как целое значение. В нашем случае это будет дробная часть нормализованной мантиссы: PROCEDURE Main() Local n2 := 10000.00 Local n3 := 21832.60 - 11832.60 ? Mantissa2(n2), Exponent(n2) ? Mantissa2(n3), Exponent(n3) wait RETURN #pragma BEGINDUMP #include "hbapi.h" HB_FUNC( MANTISSA2 ) { union { double value; char string[sizeof( double )]; } xConvert; union { double value; HB_ULONGLONG ll; } xConvert2; xConvert.value = hb_parnd( 1 ); if( xConvert.value != 0 ) { xConvert.string[6] |= 0xF0; xConvert.string[7] |= 0x3F; xConvert.string[7] &= 0xBF; } xConvert2.value = xConvert.value; hb_retnll( xConvert2.ll ); } #pragma ENDDUMP Получаем: Мантисса n2: 4608176377311526912 Мантисса n3: 4608176377311526911 Эти числа разные, разница - в 19-м десятичном разряде, и операция вычитания между ними не дает 0

Pasha: AndreyZh пишет: ещё один крайне серьёзный, непонятный глюк xHarbour (или BCC) (в clipper такой ошибки нет). Чтобы не возвращатся к этой якобы ошибке, или якобы глюку, замечу. что клиппер делает вычисления точно так же. Т.е., эта т.н. "ошибка" есть и в клиппере. Еще бы ее не было, ведь вычисления делает не клиппер, и не харбор, а fpu Думаю, что такая же "ошибка" присутствует и в Delphi, и в любом компиляторе, который выполняет вычисления с числами double

AndreyZh: Спасибо Pasha за ооочень обстоятельный ответ! Но позвольте несколько замечаний: 1. Clipper - каюсь до конца поленился проверять то же при использовании констант даёт данный результат 0.018189894 вычислений. 2. Понятно, что не занимаюсь выискиванием проблем у систем разработок. Просто пользователи замечают несуразицы -- я пытаюсь найти их причины -- натыкаюсь на проблемки систем разработок. В частности по "последней" ОШИБКЕ: В товарной накладной есть дата просрочки платежа и сумму, которую необходимо доплатить клиенту и если у покупателя обнаруживается просроченные долги, то им начинается заниматься служба безопастности предприятия. В накладной есть поле "сумма к оплате" и поле "оплачено всего по накладной" - платежей может быть несколько. В конкретном случае, где мне пришлось выслушать очень много лестного от "безопастника": Накладная на 21832.60, было два платежа 11832.60 и 10000.00. Для "сигнала" о просрочке платежа программа просто из суммы накладной вычитает суммы оплат и сравнивает с нулем (думаю аналогичные алгоритмы во всех бизнес разработках): if ("сумма накладной" - "все платежи" > 0) .and. имеется_просрочка_оплаты <выдача задания службе безопастности> endi Попытаюсь дать Ваше подробное пояснение этой "гориле-безопастнику" - посмотрю на его реакцию 3. В клиппере данная конструкция IF даёт корректный результат 4. Ваше объяснение не поясняет факт, что в Харб и Клиппере корректно считает (1.00 - (3.00 - 2.00) * 10000000000 = 0.0000 5. Стало любопытно, а как обрабатывают (считают) другие системы разработки... ВСЕ СЧИТАЮТ "КАК ПОЛОЖЕНО", именно дают в результате ноль проверенные сейчас: Visual FoxPro5.0, MS Acces 2000, OO Calc 3.2, MS VS C#

Pasha: AndreyZh пишет: 5. Стало любопытно, а как обрабатывают (считают) другие системы разработки... ВСЕ СЧИТАЮТ "КАК ПОЛОЖЕНО", именно дают в результате ноль проверенные сейчас: Visual FoxPro5.0, MS Acces 2000, OO Calc 3.2, MS VS C# Мне тоже стало любопытно из всего этого безобразия у меня случайно оказался только vfp 6. Даже ms office нет Проверяю: n1 = 10000.00 n2 = 21832.60-11832.60 ? n1 == n2 Результат - .T. казалось бы.. но проверим еще раз на всякий случай: ? (n1-n2)*10000000000 результат - точно такой же, как в клиппере и харборе. Что и неудивительно. Вывод: в фокспро процедура сравнения double выполняется не просто сравнением двух значений, а сравнением с учетом некоторой погрешности eps. Что не совсем верно, и это может вылезти где-то еще. В клиппере операция сравнения - просто сравнение double. В харборе - тоже самое

Pasha: AndreyZh пишет: Попытаюсь дать Ваше подробное пояснение этой "гориле-безопастнику" - посмотрю на его реакцию Мнээ.. не советую. Сьедят (с) Понедельник начинается в субботу Лучше слелайте в своих программах проверку на ноль не простым сравнением, а через Round(n1, 2) Я так сделал еще в те далекие времена, когда небо было голубее, трава зеленее, и первый раз попался в клиппере на такую особенность вычислений с double

AndreyZh: Pasha пишет: Лучше слелайте в своих программах проверку на ноль не простым сравнением, а через Round(n1, 2) Я так сделал еще в те далекие времена, когда небо было голубее, трава зеленее, и первый раз попался в клиппере на такую особенность вычислений с double Конечно так уже сделал! - "А что делать?"



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