Форум » [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

TimTim: Не прошел проверку и Exel http://shot.qip.ru/008CE3-1CkKxIa82/ Однако результат напоминает тот о котором Сыроежка пишет: Проверил! MS VC++ 2010 PSP пишет: Откуда инструмент может знать, что программисту нужна "бухгалтерская" точность? Инструмент её обеспечивает, но только тогда, когда человек явно этого попросит. Прав PSP, однако

AndreyZh: ... я не просил у форума только новых сообщений... по памяти на совет по decimal отвечаю, что сильно в тему не вникал, но в инструции "Note that the command affects only the display and not the accuracy of calculations with numeric values", т.е. эта установка не влияет на точность счета. Хотя на самом деле всё более чудастее!!! В принципе по "схожей" причине не было мыслей по неприятию точки и запятой при печати... Приведу очень занятную картинку, но в начале отмечу, что если в тестовой программе на клиппер написать выражение ? Str( (12.2 - 4.4 - 7.8)*10000000,15,8) то увидем также отличное от нуля выражение округленное до формата str. В реальноых же программах картина радикально меняется - всё на картинке.

PSP: AndreyZh пишет: но в инструции "Note that the command affects only the display and not the accuracy of calculations with numeric values", т.е. эта установка не влияет на точность счета. Да, согласен. Тут я ошибся. Тогда Round и все дела...


AndreyZh: PSP пишет: Да, согласен. Тут я ошибся. Тогда Round и все дела... На это уже ответил: колебания могут быть, как положительными, так и отрицательными и не везде идет сравнение с нулем. Для "нуля" наиболее правильная проверка через Empty(nnn).

Dima: AndreyZh Не пойму совсем о чем спорим ;) Ведь очевидно же что полученный результат нужно округлять , иначе будут периодически лезть вот такие вот "глюки" в программе. Должен признать что и сам (очень давно правда) в своих программах не округлял результат и соответственно лезли похожие глюки. На скрине идет работа с килограммами и граммами , ну так ясное дело что округлять нужно результаты до 3 знаков после запятой , иначе пользователи Ваc заклюют

Pasha: AndreyZh пишет: Этот блок использовался без изменения уже больше 20 лет... еще и системы не было... а операция "распределения" производится (провожу ежегодный анализ) более 50 000 раз по всем клиентам (или перебирают больше 200 000 комплектов цифр ежегодно)... была бы проблема - давно бы наткнулся. На xHarb она поперла в виде звонков ежедневно, как начал переводить розничные магазины. Это все лирика. Попробуйте привести пример разного поведения клиппера и харбора с вещественными числами aka double ieee 754. С 12.2 - 4.4 - 7.8 поведение одинаковое. Вам же каждый день идут звонки от клиентов, то есть материала для проверки более чем достаточно. Попробуйте найти пример, где клиппер дает равенство нулю, а харбор - неравенство. Иначе говорить не о чем. Только сразу говорю - такого примера Вы не найдете, так как. fpu и для клиппера, и для харбора работает одинаково.

Pasha: Я для проверки на равенство использую такую функцию: #pragma BEGINDUMP #include "hbapi.h" #include "math.h" HB_FUNC( EQU ) { double d1 = hb_parnd( 1 ); double d2 = hb_parnd( 2 ); hb_retl( fabs( d1 - d2 ) < 0.005 ); } #pragma ENDDUMP

AndreyZh: Да мы как-бы ни о чем не спорим... просто обсуждаем возможные проблемы и пути их разрешения... появляются довольно много дельных советов полезных, как для меня, так и других разработчиков на харборе. Хотя есть проблемки, но в чем то не очевидные: вернёмся к примеру с "округлением"... и играясь на конкретных числах 12.2/4.4/7.8 - на них наткнулись пользователи, но не факт, что операции с другим набором чисел будет приводить к схожим результатам... тест для других операций обсуждался на первой страницы. "Очередная" заморочка (или непонятка) выявилась в процессе тестов, которые вынужден был провести: 1. Если просто проверить результат выражения wait Str( (12.2 - 4.4 - 7.8)*10000000,15,8), то и Clipper 5.01 и xHarbour дают идентичные результаты - число отличное от нуля. 2. Вводим данные значения в конкретной программе, собранной под Clipper и xHarbour - пока вынужден поддерживать совместимость исходников и получаем уже разные результаты - показаны на картинке. Что меняется??? Может быть у меня код "кривой"... но ведь всё время успешно работал, не вызывая нареканий. Повторю его снова: [pre2] DO WHIL !Eof() .AND. codInv==cInv // Читаем распределение по конкретному складу и товару. cCodStores := Spac(2) nQty := nMax **** Здесь различно срабатывает условие проверки nQty>=0.AND.nQty<=nMax На картинке просто вывел результат после второй итерации, где видно, что программа на клиппере даёт НОЛЬ @ 1,1 SAY WARES->name+" Осталось распред."+Str(nMax,10,3) @2,1 SAY "Распределить на склад:" GET cCodStores VALI Eval(bCodStores,cCodStores) .AND. Eval({||DevPos(2,28),DevOut(HB_STORE->shotName,cOther),TRUE}) @2,56 SAY "Количество:" GET nQty PICT "9999999.999" VALI lValid({||nQty>=0.AND.nQty<=nMax},"Неверное кол-во. Отрицательно или слишком большое!") .AND. zlWar(DETALREC->codWares,nQty) READ IF LastKey()==K_ESC lBreak := TRUE; EXIT ENDI /* Запоминаем данные в массиве и меняем настройки. Склад может повторится, в этом случае добавляем количество в туже строку */ lArr := TRUE FOR nI := 1 TO Len(aArr) IF aArr[nI,1]==DETALREC->codWares.AND.aArr[nI,2]==cCodStores lArr := FALSE; EXIT ENDI NEXT nI IF lArr // Новый товар и склад. Aadd(aArr,{DETALREC->codWares,cCodStores,nQty,DETALREC->sales,DETALREC->tax_n,DETALREC->tax_s}) ELSE // Имеется строка в массиве. aArr[nI,3] += nQty ENDI nMax -= nQty // Еще не весь товар текущего наименования распределили. IF nMax > 0 THEN LOOP DbSkip() nMax := qtyAll ENDD [/pre2]

Pasha: AndreyZh пишет: Что меняется??? Может быть у меня код "кривой"... но ведь всё время успешно работал, не вызывая нареканий. Повторю его снова: Код может быть и не кривой, только выполнить его вне вашего окружения невозможно, и соответвенно прогнать на клиппере и харборе тоже невозможно Мне рассказать, что такое самодостаточный пример ? Без такого примера анализ этого кода невозможен. Ведь код надо собрать двумя компиляторами (клиппером и харбором), запустить его, так чтобы он запустился, что-то ввести, получить результат и его проанализировать. В таком виде ничего этого сделать нельзя.

Pasha: Немного модифицировал свой старый тест: func main Local n1 := 10000.00 Local n2, n3, i Local i1 := 0 Local i2 := 0 dbCreate('fpu', {{'D1', 'N', 12, 2}, {'D2', 'N', 12, 2}}) use fpu new for i := 1 to 10000000 n2 := Round(n1+i*0.01, 2) n3 := Round(n1+n1+i*0.01, 2) if n1-(n3-n2) == 0.00 i1 ++ else fpu->(dbAppend()) fpu->D1 := n2 fpu->D2 := n3 i2 ++ endif next qout(i1, i2) return nil и прогнал его на клиппере и харборе. Результат получился идентичный. То есть, если различие между компиляторами и есть, то это не результат выполнения арифметических операций. А без самодостаточного примера его выявить нельзя. Так дайте пример. Что его делать то ? Там того кода всего ничего. Выбросьте все лишнее, дайте в конце концов дбф-файл, откуда выбираются данные, напишите, что надо вводить в get Без этого ничего сделать нельзя.

AndreyZh: Pasha пишет: Код может быть и не кривой, только выполнить его вне вашего окружения невозможно, и соответвенно прогнать на клиппере и харборе тоже невозможно Мне рассказать, что такое самодостаточный пример ? Куда же проще? К тому же любопытно, как может влиять окружение? Что же еще упростил! Варианты на клиппер даёт 0, на харб нет: [pre2] nmax := 12.2 DO WHIL .t. nQty := nMax @ 1,1 SAY " Осталось распред."+Str(nMax,10,3) @1,56 SAY "Количество:" GET nQty PICT "9999999.999" READ IF LastKey()==K_ESC EXIT ENDI @ 3,1 say str((nqty-nmax)*100000000,19,9) nMax -= nQty IF nMax > 0 LOOP endi ENDD wait [/pre2] Пардон - вводите волшебные числа: Сначала 4.4, затем 7.8... на другом наборе результаты могут разичаться P.S. Надеюсь для пользы развития Харбора "стараюсь".... а не просто потрындеть...

AlexMyr: Тест на harbour (17592) 0.000000089 clip*er5.3 0.000000089

AndreyZh: AlexMyr пишет: clip*er5.3 0.000000089 Прога на 5.01R

Dima: AlexMyr пишет: Тест на harbour (17592) 0.000000089 clip*er5.3 0.000000089 И у меня тоже самое + Xharbour выдал тот же результат ЗЫ Clipper 5.2e у меня

Dima: AndreyZh пишет: Прога на 5.01R в нем были глючки , хорошо это помню когда переводил прогу с Clipper 5.01 на 5.2e Нашел в архиве Clipper (R) Version 5.01 Copyright (c) Nantucket Corp 1985-1991. All Rights Reserved. Microsoft C Floating Point Support Routines Copyright (c) Microsoft Corp 1984-1987. All Rights Reserved. Результат тот же

Dima: AndreyZh А какой результат выдаст такой тест на Вашей машинке ? [pre2] IF 4195835.129876 - ((4195835.129876 / 3145727.129876) * 3145727.129876) #0 ? "BAD" ELSE ? "OK" ENDIF [/pre2]

AlexMyr: И clip* и harbour - OK

petr707: Цитата nQty := nMax @ 1,1 SAY " Осталось распред."+Str(nMax,10,3) @1,56 SAY "Количество:" GET nQty PICT "9999999.999" возможно, часть Вашей проблемы в этом сегменте кода. Видимое значение в поле ввода округлено, однако если не менять значение в поле ввода, а просто подтвердить клавишей <Enter> будет передано неокругленное значение. Если просто тупо перебить в поле ввода видимые цифры в общем случае значение переменной ввода после GET будет другим.

Pasha: petr707 пишет: в общем случае значение переменной ввода после GET будет другим. Именно так Предлагаю уважаемой публике выполнить такой тест на разных версиях клиппера и харбора: local n1 := 12.2 - 7.8 local n2 := 4.4 @ 1,1 say if(n2==n1, 'T', 'F') // ежу понятно, что на всех версиях клиппера и харбора результат будет F @ 2,1 say 'Ввод' get n1 picture '9999999.999' read // ничего вводить не надо, просто нажать enter @ 3,1 say if(n2==n1, 'T', 'F') а после read возможны различия: на харборе по-прежнему будет F, а на клиппере - скажите У меня возникло впечатление, что по read в клиппере содержимое переменной n1 будет округлено. Только в каких версиях ? От 5.01 до 5.3 Так же интересно прогнать этот тест без picture

Dima: Pasha 5.01 .F. 5.2e .F. без picture так же



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