Форум » [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 Конечно так уже сделал! - "А что делать?"

Pasha: AndreyZh пишет: 4. Ваше объяснение не поясняет факт, что в Харб и Клиппере корректно считает (1.00 - (3.00 - 2.00) * 10000000000 = 0.0000 Как так ?!! А мне показалось, что я все обьяснил Тестовая программа: Local n1 := 10000.00 Local n2, n3, i Local i1 := 0 Local i2 := 0 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 i2 ++ endif next qout(i1, i2) __Wait('') Результат: 8733568 1266432 Т.е., в 87.3% сравнений получаем равенство, а в 12.7% - неравенство Вот такая она, арифметика с плавающей точкой. Это как повезет. Считайте, что для (1.00 - (3.00 - 2.00) - повезло Кстати, если варьировать параметры цикла, например поставить i до 100000, то результат будет совершенно другим, 52% на 48%

Pasha: Докладываю о проделанной работе. На форуме фокса выяснил, что в vfp используется вобщем-то некрасивое и недокументированное решение: при сравнении double числа не просто сравниваются, а сравниваются с округлением до количества десятичных знаков, которое задается для отображения переменной numeric. Это количество десятичных знаков задается при создании переменной в соответсвии со значением set decimals (или прямо в константе), и по умолчанию равно двум. Если перед созданием переменных задать SET DECIMALS TO 18, то при сравнении возникнет ошибка (.F.), точно такая же, как в харборе. Я рассказал об этом в devlist, предложив добавить подобную фичу и в харбор (по отдельной настройке SET). Виктор, естественно, отказал. Да я бы и сам подумал бы 10 раз, прежде чем это делать. Одно дело - предложить, другое - реализовать. Есть еще вариант решения этого вопроса - добавить в харбор еще один числовой подтип - currency. Имеется в виду хранение чисел в целом формате (4 или 8 байт), но с некоторой базой: например, 2 или 4. Если это 2, то, грубо говоря, значения хранятся в "копейках", если 4 - в десятитысячных долях целого. И используется целочисленная арифметика, при которой подобных пролбем в принципе быть не может. В формате dbf есть подобный тип данных - "Y" Несколько лет назад у меня самого чесались руки сделать это, но там есть свои подводные камни. Вобшем, пока этот вопрос открыт. В свою очередь, могу предложить такую функцию для проверки double на 0. В этой функции помимо сравнения значения с нулем проверяется еще и эксонента, и, если она меньше или равна -36 (т.е. значение меньше или равно 2**-36), то считается, что число равно нулю. Как показывает практика, при вычислениях большей погрешности не возникаает. Вот эта функция: [pre]#pragma BEGINDUMP #include "hbapi.h" static int exponent( double d ) { int iExponent = 0; union { double value; char string[sizeof( double )]; } xConvert; xConvert.value = d; if( xConvert.value != 0 ) { iExponent = ( int ) ( xConvert.string[7] & 0x07F ); iExponent = iExponent << 4; iExponent += ( int ) ( ( xConvert.string[6] & 0xF0 ) >> 4 ); iExponent -= 1023; } return iExponent; } HB_FUNC( EQU0 ) { double d = hb_parnd(1); hb_retl( d == 0.0 || exponent( d ) <= -36 ); } #pragma ENDDUMP[/pre]

petr707: По поводу "..используется целочисленная арифметика, при которой подобных пролбем в принципе быть не может" Это справедливо, видимо, только для операций, где нет деления ( вычисления частей) - сложение,вычитание, умножение на целое. Вопрос возник из учетной задачи с финансовыми суммами с дробями( где копейки - десятичные дроби). В этой среде -дополнительно к погрешности,вызванной машинным представлением чисел (то есть неточно), есть другая погрешность - из-за необходимости представлять промежуточные и конечные результаты целым числом копеек. Поскольку принципиально есть операции деления с потерей значаших разрядов ( например расчет сумм НДС), и где всегда ошибка (неточность) вычисления суммы частей не равна сумме ошибок(неточностей) частей. Как правило, при вычислениях необходимо , наборот, явно определять и контролировать получаемую погрешность и относить ее на особую статью учета. Например, товар 3 упаковки (упаковка = 1/3 часть целого) на общую сумму 1.00 руб (100 коп) при ставке НДС 10 % с суммой НДС 0.10 руб при продаже тремя частями при необходимости указывать цену продажи в целых копейках и фиксировать, как полную сумму, так и сумму НДС - при каждой продаже, приводит к разнице в копейку по сумме товара и сумме НДС: 1.00 руб(0.10 ндс) <> 3*0,33 (0,03 ндс - потеря значимости) = 0,99 ( 0,09 ндс) То есть, видимо, лучше применять свой специальный инструментарий для вычислений, в том числе и для сравнения финансовых сумм, чем полагаться на некие неявные свойства арифметических библиотек среды исполнения.

Pasha: petr707 пишет: По поводу "..используется целочисленная арифметика, при которой подобных пролбем в принципе быть не может" Это справедливо, видимо, только для операций, где нет деления ( вычисления частей) - сложение,вычитание, умножение на целое. Числовой тип харбора сейчас имеет несколько подтипов: целый (integer и long), и double. Операндами бинарной арифметической операции могут быть любые значения, и подтип результата такой операции определяется автоматически, чтобы избежать потери значности: скажем, если это операция long-long, то ее результатом может быть как long, так и double, если для long не хватает разрядности. Результат операции long div long - всегда double. Такие же правила можно выработать и для нового целого типа currency. Пусть результат операции currency div currency будет double, а результат остальных трех операций - currency или double (если разрядности currency не хватает). Так что этот вопрос как раз проблемы не составляет.

AndreyZh: Уважаемые господа! Особенно поклон Pasha за большие усилия по нахождению вариантов решения проблем! Ещё раз "оговорюсь", что в данной теме перечисляются проблемки, выявляющиеся в процессе эксплуатации конкретной системы и их разрешение позволит другим разработчика сразу их избежать при создании своих систем. Если и другие разработчики выявляют какие-то "технические проблемы системы разработки", то так же их хотелось бы знать заранее, что бы не наступать на "грабельки" в своих программах.

Pasha: Pasha пишет: Тестовая программа: Local n1 := 10000.00 Local n2, n3, i Local i1 := 0 Local i2 := 0 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 i2 ++ endif next qout(i1, i2) __Wait('') Из любопытства запустил подобную програмку на vfp6. Харбор показал в 2 раза лучший результат: фокс ее выполнил за 18 сек, харбор - за 9.

AndreyZh: Доброе утро! Опишу очередные геморрои с исправлениями "несовместимостей" между Clipper и xHarbour (может быть кто-то избежит ненужных потерь времени, сразу исправляя несовместимости): 1. Передаю в функцию переменную - func mmm(xPar) - .... - xPar := AllTrim(Upper(xPar)) Если переменная не задана ( =mmm() ), то клиппер нормально продолжает работать, воспринимая xPar, как пустое символьное значение... по крайней мере в моём последующем коде... xHarbour вылетает по ошибке "неопределенный тип"... Выявилось, когда user, самостоятельно настраивая прогу забыл задать параметр. 2. USE ls_works SHAR NEW Открываю таблицу, но алиас ls_works уже используется... Клиппер на это реагирует спокойно и правильно обрабатывает рабочую область... xHarbour вылетает по ошибке... На это натыкался в самом начале переделки системы и описывал, но среди кода затесалась эта фигня, к которой обращаются крайне редко... но обратились... и программа вылетела... и на меня справедливо наехали пользователи. 3. Фигня - конечно. Для просмотра создаётся пустой файл, есть "чужая" функция просмотра текстовых файлов неограниченного размера через класс TBroseDB... так и не смог подружить её с xHarbour... но выкрутился - memedit работает с файлами неогр. размера... но народ привык, что можно при просмотре Home/End просматривать широкий отчёт, но первая строка "пустая", т.е. не работает... выкрутился - заставляю курсор перемещаться вниз на реальные строки... но когда 40 чел "проедают плешь" не очень приятно. Это то, что вспомнил с "последнего" сообщения... на тему 100% совместимостей Clipper и [x]Harbour...

Pasha: AndreyZh пишет: - xPar := AllTrim(Upper(xPar)) Если переменная не задана ( =mmm() ), то клиппер нормально продолжает работать, воспринимая xPar, как пустое символьное значение... по крайней мере в моём последующем коде... xHarbour вылетает по ошибке "неопределенный тип"... Выявилось, когда user, самостоятельно настраивая прогу забыл задать параметр. Это не соответствует действительности. Клиппер (я проверил на 5.2е) работает точно так же, как Харбор Upper(nil) генерирует argument error

AndreyZh: Pasha пишет: Это не соответствует действительности. Клиппер (я проверил на 5.2е) работает точно так же, как Харбор Upper(nil) генерирует argument error Вот "Фома неверущий"... Clipper 5.01r + CTII... использовалось без ошибок с корректной обработкой: [pre2] #include "laks.ch" * ---------------------------------------------------------------------------- * Стартовая процедура. PROC Main( cPar, cSaveLog ) LOCA lRep:=FALSE, nSel:=1, nSelWork:=1, cTxt:="", aArr:={}, nC:=0, nI:=0 // Глобальные системные установки пакета и конфигурация по df. #include "cfg.ch" cnProgramm := "Администр." // Загружаем/изменяем значения переменных настройки из стандартной базы данных IF !NetUse( "LS.CFG", SHAR_MODE, 5 ) THEN fErrQuit("Недоступна БД конфигурации!","W+*/N") #include "config.ch" cpZatr := IF(Empty(Alltrim(cpZatr)),"В.РАСХОД",cpZatr) // Вставка моего заголовка и блокирование закрытия окна pWind(" Администратор и бухгалтерский модуль (УС Land)... Предприятие: "+Alltrim(cpName),"hla.ico") ..... // Настройка и ремонт запускается до открытия файлов. cPar := IF( Pcount()==0, "", cPar ) IF Upper(cPar)=="R" THEN pRepair() // Ремонт IF Upper(cPar)=="C" THEN aConfig(FALSE) // Конфигурация IF Upper(cPar)=="O" THEN lRep:=TRUE // Признак отчетной программы. ZhSoft() pOpAllBase() // Пользователь в режиме неопределенный. Принудительный вызов режима проверки логики после открытия БД IF Upper(cPar)=="L" CLS pChLogic(Upper(Alltrim(cPar)),Upper(Alltrim(cSaveLog))) ENDI // Вызов системы нуления программы. IF Upper(cPar)=="D" THEN pDestroyBase() .... // Блок ввода и проверки допуска к работе с программой [/pre2] Сейчас исправлено: [pre2] PROC Main( cPar, cSaveLog ) LOCA lRep:=FALSE, nSel:=1, nSelWork:=1, cTxt:="", aArr:={}, nC:=0, nI:=0 DEFAULT cPar TO "", cSaveLog TO "" [/pre2] где default команда препроцессора: [pre2] #xcommand DEFAULT <p> TO <v> [, <p2> TO <v2> ] => ; <p> := IF(<p> == NIL, <v>, <p>) ; [; <p2> := IF (<p2> == NIL, <v2>, <p2>) ] [/pre2]

Pasha: AndreyZh пишет: Вот "Фома неверущий"... Clipper 5.01r + CTII... использовалось без ошибок с корректной обработкой: Точнее формулировать надо. AllTrim(Upper()) это не то же самое, что Upper(Alltrim()) Проверяем: Alltrim(nil) 501 - работает 52, харбор - возникает ошибка Т.е. речь идет не о совместимости клиппера и харбора, а о несовместимости разных версий клиппера. Харбор естественно совместим с версиями 5.2e и 5.3b, которые считаются "каноническими".

AndreyZh: Pasha пишет: Alltrim(nil) 501 - работает 52, харбор - возникает ошибка Т.е. речь идет не о совместимости клиппера и харбора, а о несовместимости разных версий клиппера. Харбор естественно совместим с версиями 5.2e и 5.3b, которые считаются "каноническими Pasha пишет: Об ентом и написал выше... То есть, если писать прогу на Harbour "с нуля", то многие вещи будут казаться "очевидными" и прога, скорее всего не будет иметь ошибок, связанных "с совместимостью"... если переделывать, а особенно код, который перелопачивался на протяжении 16 лет, то "веселье" гарантировано. Точнее формулировать надо. AllTrim(Upper()) это не то же самое, что Upper(Alltrim()) Нормально, но

Pasha: AndreyZh пишет: Об ентом и написал выше... То есть, если писать прогу на Harbour "с нуля", то многие вещи будут казаться "очевидными" и прога, скорее всего не будет иметь ошибок, связанных "с совместимостью"... если переделывать, а особенно код, который перелопачивался на протяжении 16 лет, то "веселье" гарантировано. Если бы вы переводили программу с 501 на 52/53, то столкнулись с такой же проблемой. Дело не в харборе, а самом клиппере. Кстати, разработчики харбора предусмотрели возможность поведения харбора как для старых версий клиппера Если харбор собрать без флага HB_COMPAT_C53, то Alltrim не будет генерировать ошибку, если ему не передать параметр Так что слова о какой-то особой сложности перехода на харбор некорректны. Надо просто понимать эти несовместимости и учитывать их при переходе. Множество казалось бы несовместимостей связано с особенностиями ms dos, которых просто нет в современных ОС. По поводу ошибки, которую генерирует use, если попытаться 2-й раз открыть уже открытый файл 5.2 генерирует при этом ошибку, как и харбор, а 501 - игнорирует ошибку. Ну и что правильного в таком поведении ? И опять таки, мы имеем дело с разным поведением версий клиппера, а не с несовместимостью клиппера и харбора. Харбор же не может одновременно воспроизвести противоположное поведение разных версий клиппера. По TBrowseDB. Вообще-то это не класс, а функция с уже определенными блоками кода для навигации по таблице БД, и как ее можно прикрутить для навигации по текстовому файлу, я не представляю.

AndreyZh: Pasha пишет: По TBrowseDB. Вообще-то это не класс, а функция с уже определенными блоками кода для навигации по таблице БД, и как ее можно прикрутить для навигации по текстовому файлу, я не представляю. Не придирайтесь!!! - Да? Что по технологии - ловите, имеющий самостоятельную ценность исходник: [pre2] * =========================================================================== * Просмотр файлов неограниченной длины. Адаптация под стиль Жукова Андрея * программы Станислава Кросмана, а также исправление логических ошибок. * !!! Для xHarbour не удалось заставить работать - заменил редактированием. * =========================================================================== #include "function.ch" #define ATNUM(d,c,b,e) IF(At(d,Subs(c,e+1))==0,0,At(d,Subs(c,e+1))+nPointer-1) * #define BUFFER 4096 // Размер считываемого в начале буфера * #define BUFFER2 2048 // Размер считываемого куска файла * #define CRITICAL_LENTH 256 // Размер максимальной длины строки **** 09.2001 Переделал старые установки т.к. вылетал при просмотре больших файлов **** после чего программа стала работать более стабильно. **** ? Не понятно как повлияли данные размеры и почему. Память ОЗУ не менялась. #define BUFFER 2048 // Размер считываемого в начале буфера #define BUFFER2 1024 // Размер считываемого куска файла #define CRITICAL_LENTH 512 // Размер максимальной длины строки STAT nH // handler файла STAT nPointer // Указатель в файле // Флаг позиции в файле(0-достигнуто начало файла,1-внутри файла,2-достигнут конец файла) STAT nFl_pos STAT cStr // Строка-буфер STAT nStrPoint:=1 // Указатель в строке // Флаг позиции в строке-буфере(0-начало строки,1-внутри строки,2-достигнут конец строки) STAT nFf_pos STAT lFl_direction // Направление последнего перемещения STAT nLenFile // Длина текстового файла. // Отладочный пример. Даем параметры и вызываем функцию просмотра PROC M__12__34_(); SET SCOR OFF; Wboard(); CLS; lLookFile("LOOPFILE.PRG",1,2,22,73,"RG+/B") RETU /* Функция просмотра текстовых файлов неогран.длины при помощи обьекта-таблицы. Параметры: Имя файла, координаты окна, цвет отображения текста. Возврашает значиние ложь при обнаружении ошибки. */ FUNC lLookFile( cFile, nX, nY, nDx, nDy, cCol ) LOCA x:=2, y:=2, x1:=nX+nDx-2, y1:=nY+nDy-2, nOldCur:=SetCursor() LOCA cOldCol:=SetColor(), oB, oC, ik:=0 // Обьекты PRIV GetList:={} DEFAULT nX TO 0, nY TO 0, nDx TO 24, nDy TO 79, cCol TO "W/N" fSwopen( nX, nY, nDx, nDy, cCol, 4 ) @ 0,nY+nDy-42 SAY " Home-начало End-конец строки Esc - выход " SetCursor( 0 ) nH := Fopen(cFile, FO_READ) // Просматриваемый файл только для чтения IF nH == -1 THEN RETU FALSE // Ошибка при открытии файла. nLenFile := Fseek( nH, 0, FS_END) // Вымеряем длину файла. Go_home() // Устанавливаем указатель на начало файла oB := TBrowseNew(x, y, x1, y1) // Блоки кода перемещения по сканируемой строке. oB:goTopBlock := {|| Go_home() } oB:goBottomBlock:= {|| Go_end() } oB:skipBlock := {|nSkip| Skipp(nSkip) } // Колонка - извлеченная из строки буфера строка. oC := tbColumnNew("",{|| Take_str() }) // Пока без заголовка колонки. oC:width:= y1 - y + 1 oB:addColumn( oC ) oB:autolite := FALSE // Не выделять текущую строку в процессе стабилизации. // Начало обработки табличного обьекта. WHIL TRUE DispBegin() WHIL !oB:stabilize() .AND. NextKey()==0 // Выполняем цикл стабилизации ENDD @ 0,1 SAY " "+IF(nFl_pos==0," 0",IF(nFl_pos==2,"100",cProc()))+"% " DispEnd() IF ( ik:=Inkey(0) ) == K_ESC THEN EXIT DO CASE // Обрабатываем нажатую клавишу. CASE ik == K_LEFT IF nStrPoint > 1 // Можно перемещаться еще влево. nStrPoint-- oB:refreshAll() ENDI CASE ik == K_RIGHT // След. можно уходить за границу текста 256 знаков. nStrPoint++ oB:refreshAll() CASE ik == K_PGDN oB:rowPos := oB:rowCount // Текущая строка = количеству видим.строк IF !oB:hitBottom THEN oB:pageDown() CASE ik == K_PGUP oB:rowPos := 1 IF !oB:hitTop THEN oB:pageUp() CASE ik == K_UP oB:rowPos := 1 oB:up(); oB:up() CASE ik == K_DOWN oB:rowPos := oB:rowCount oB:down(); oB:down() CASE ik == K_CTRL_PGUP IF !oB:hitTop THEN oB:goTop() CASE ik == K_HOME IF nStrPoint <> 1 nStrPoint := 1 oB:refreshAll() ENDI CASE ik == K_CTRL_PGDN IF !oB:hitBottom THEN oB:goBottom() CASE ik == K_END nStrPoint += Max(0,60-nStrPoint) oB:refreshAll() * oB:panEnd() // Эта запись вместо двух была в оригинале текста. ENDC END Fclose( nH ) // Закрываем файл fDeact( cOldCol ) // Закрываем окно. SetCursor( nOldCur ) RETU TRUE /* Начальное считывание из файла и перерисовка экрана. */ STAT FUNC Go_home() nPointer := 1 // Указатель в просматриваемом файле. nFl_pos := nFf_pos := 0 // Позиция в буфере и файле. lFl_direction := TRUE // Направление последнего перемещения. Fseek( nH, 0, FS_SET ) // Позиционируемся в начало файла. cStr := FreadStr( nH, BUFFER ) // Начальное чтение RETU NIL /* Чтение с конца файла символов согласно размеру буфера и установ параметров */ STAT FUNC Go_end() LOCA nI:=0, nJ := Fseek( nH, 0, FS_END) // Вымеряем длину файла. Fseek( nH, -Min(BUFFER,nJ), FS_END ) // От какого места берем в буфер cStr := FreadStr( nH, Min(BUFFER,nJ) ) // Считали в сканируюмую строку Fseek( nH, 0, FS_END ) // Ушли на конец файла. nI := Rat( CRLF, cStr ) nPointer:= IF(/*есть еще знак конца строки CRLF*/ nI<>0, nI+2, 1 ) nFl_pos := nFf_pos := 2 // Признаки достижения конца строки и файла. lFl_direction := TRUE RETU NIL /* Перемещение по таблице на nN строк. Направление зависит от знака nN. */ STAT FUNC Skipp( nN ) LOCA nI := 0 IF nN >= 0 // Перемещение вниз по таблице FOR nI:=1 TO nN IF !Skipp_down() THEN nN := nI-1 // Достигнут конец файла. NEXT nI ELSE // Перемещаемся вверх по таблице. nN := -nN FOR nI:=1 to nN IF !Skipp_up() THEN nN := nI-1 // Достижение начала файла. NEXT nI nN := -nN ENDI RETU nN // На сколько сумели сдвинуться. /* Перемещение на одну строку вниз по таблице (строке-буфере,файлу). */ STAT FUNC Skipp_down() LOCA nI := ATNUM( CRLF, cStr, 1, nPointer-1 ) IF nFl_pos == 2 THEN RETU FALSE // Ранее достигли конца файла. // Необходима подкачка в буферную строку и есть для этого возможность. IF nI == 0/*нет строк вывода*/ .AND. nFf_pos <> 2 /*находимся внутри файла*/ Driver( TRUE ) // Читаем вниз по файлу. Пополняем cStr. nI := ATNUM(CRLF,cStr,1,nPointer-1) ENDI // Дальше некуда. Из файла считали все до самого его конца. IF nI == 0 THEN nFl_pos:=2/*достигли конца файла*/; RETU FALSE nPointer := nI+2 // Перемещаем указатель nFl_pos := 1 // Шагаем внутри файла. RETU TRUE /* Перемещение на одну строку вверх по таблице (строке-буферу,файлу) */ STAT FUNC Skipp_up() LOCA nI := 0 IF nFl_pos == 0 THEN RETU FALSE // Уже в начале строки. nI := Rat( CRLF, Left(cStr,nPointer-2) ) // Последнее вхождение CRLF IF nI == 0 .AND. nFf_pos <> 0 // Нужна и возможна подкачка из файла. Driver(FALSE) // Читаем вверх. nI := Rat( CRLF, Left(cStr,nPointer-2) ) ENDI IF nI == 0 // Более читать нечего. Достигли самого начала файла. nPointer := 1 nFl_pos := 0 RETU TRUE // При след.вызове проанализирует nFl_pos ENDI nPointer := nI+2 nFl_pos := 1 RETU TRUE /* Возвращает строку просмотра в табличный обьект. */ STAT FUNC Take_str() LOCA cSss:="", nI:=ATNUM( CRLF, cStr, 1, nPointer-1 ) // Нет отдельной строки, а подкачать можно т.к. не достигнут конец файла. IF (nI==0) .AND. (nFf_pos <> 2) Driver( TRUE ) // Подкачиваем из буфера в cStr и изменяем указатель nPointer. nI := ATNUM( CRLF, cStr, 1, nPointer-1 ) ENDI IF nI == 0 // Более нет текстовых строк ниже указателя. cSss := Subs( Subs(cStr,nPointer), nStrPoint ) ELSE cSss := Subs( Subs(cStr,nPointer,nI-nPointer), nStrPoint ) ENDI nI := At(CRLF,cSss) cSss := Left( cSss+Spac(CRITICAL_LENTH), CRITICAL_LENTH )+CRLF RETU cSss //tabexpand(sss) /* Драйвер подкачки из текстового файла в сканируемую строку. Параметр определяет направление просмотра. Истина читаем текст вниз по файлу. */ STAT FUNC Driver( lPar ) LOCA cBuf:="", nI:=0, nJ:=0, nK:=0, nL:=0 nFf_pos := 1 // Просмотр производится внутри строки. IF lPar .AND. nFf_pos <> 2 // Смотрим вниз, но конца файла не достигли. IF !lFl_direction // Идем в конец. Fseek( nH, Len(cStr), FS_RELATIVE ) // С текущего места. lFl_direction := TRUE ENDI IF Len( cBuf:=FreadStr(nH,BUFFER2) ) <> BUFFER2 THEN nFf_pos:=2 cStr := Right( cStr, Len(cStr) - Len(cBuf) ) + cBuf nPointer -= Len(cBuf) // nPointer += Len(cBuf) ELSEIF nFf_pos <> 0 // Нет еще начала файла. Просмотр идет вверх. IF lFl_direction // Идем в начало файла. Fseek( nH, -Len(cStr), FS_RELATIVE ) lFl_direction := FALSE ENDI nI := Fseek( nH, -Min((nL:=Fseek(nH,0,FS_RELATIVE)),BUFFER2), FS_RELATIVE) IF nI == 0 // Дальше некуда. nFf_pos := 0 nJ := nL - nI ELSE nJ := BUFFER2 ENDI /* nJ - реальное значение, на которое удалось передвинуться, nL - старое значение указателя в файле, считываем строку */ cBuf := FreadStr( nH, nJ ) Fseek( nH, nI, FS_SET ) cStr := cBuf+Left(cStr,Len(cStr)-nJ) // корректируем строку nPointer+=nJ ENDI RETU NIL /* Расчет и возврат процента прочтения текста из файла по статическим переменным */ STAT FUNC cProc() LOCA nCur := Fseek( nH, 0, FS_RELATIVE ) RETU Str( zInt(nCur*100/nLenFile), 3 ) [/pre2]

Pasha: AndreyZh пишет: Не придирайтесь!!! - Да? Что по технологии - ловите, имеющий самостоятельную ценность исходник: Да я не придираюсь, просто не очень был понятен вопрос. Что касается xHarbour TBrowse - то он не на 100% совместим с клипперовским. И с такой сложной схемой могут быть несовместимости. В этом отношении Harbour TBrowse лучше, я так и делал: собирал xHarbour, а TBrowse брал от Harbour А касательно этой процедуры: ну зачем же делать так сложно ? Лучше загнать текстовый файл в массив, используя MLCount/MemoLine(), и затем этот массив просматривать тем же TBrowse. Это будет и быстрее, и куда проще. Массив строк можно сформировать и другим способом: через TokenInit/TokenNext/ToeknEnd

AndreyZh: Здравствуйте! ... очередной глобальный глюк [x]harbour? Если так, то может быть послать разработчикам. Програмка примерно структуры: loca cc:=spac(1) .... @ 1,1 say "введите символ" get cc read .... построение отчета .... вызов запросов печати из формы и в зависимости от устройства вывод куда требуется. Проблема: Если введен символ точка или запятая, то как-бы в форме печати харб нажимает PgDn, на прочих знаках/буквах спокойненько ожидает что ему введут в качестве устройства и нажмут клавиши подтверждения. Можно, если интересно дать полный пример отчёта, но данный глюк во всех, где самым последним get вводится один символ. Как её можно побороть: Пока сделал так, благо после каждого read у меня есть вызов ф-ции верификации user, т.е. просто добавил в неё: if lastkey() = 44 .or. lastkey() = 46 keyb chr(K_ENTER) inkey(0) endi P.S. Уже была чем-то схожая проблема, когда харб не любил цифру 1, но Pasha связывался с разработчиками и они порешали её.

Dima: AndreyZh Проверил в Harbour и XHarbour , проблемы не увидел.

AlexMyr: Т.к. AndreyZh пишет: loca cc:=spac(1) , то при вводе любого символа read завершается пробуйте так @ 1,1 say "введите символ" get cc valid lastkey()=13

AndreyZh: Уважаемые господа. Есть некая сложность с тестами, т.к. всё является частью большой системы с кучей взаимопересекающихся процедур, но как то Pasha исхитрялся находить самодостаточные примеры иллюстрирующие приводимые мной уже пару лет "глюки" Dima пишет: AndreyZh Проверил в Harbour и XHarbour , проблемы не увидел. Вы скачивали систему... желающие могут это сделать уже с нормальным дистрибутивом дистрибутив с версией июня 2012 (34мб) где ещё имеется данная проблема: программа аналитика/динамические... любой отчет, на последний запрос знака разделителя вводите различные знаки (глюки только на точке и запятой) AlexMyr пишет: , то при вводе любого символа read завершается пробуйте так @ 1,1 say "введите символ" get cc valid lastkey()=13 Не в этом проблема... Ясно, что когда ввожу единственный знак, то это и завершает READ, но поведение проги в дальнейшем зависит от символа.

AlexMyr: AndreyZh пишет: но поведение проги в дальнейшем зависит от символа. каким боком Harbour к проблеме в Вашей проге ввиде обработки символа?

petr707: 1) в общем случае содержимое GET не совпадает с lastkey() 2) для исключения дефолтового поведения лучше использовать конструкцию с Picture 3) ниже код, где можно посмотреть разницу - при нажатии Esc , PageDown и прочее proc main() loca cc:=space(1) , dd:=space(1),ff:=space(1),i @0,0 cls for i=1 to 20 @ 1,1 say "введите символ 1 " get cc read @2,1 say "cc="+str( asc(cc),3) @3,1 say "lastkey()="+str( lastkey(),3) @ 5,1 say "введите символ 2" get dd picture "X" read @6,1 say "dd="+str( asc(dd),3) @7,1 say "lastkey()="+str( lastkey(),3) @10,1 say "введите символ 3" get ff picture "9" read @11,1 say "ff="+str( asc(ff),3) @12,1 say "lastkey()="+str( lastkey(),3) next i return

AndreyZh: Доброе утро. Напишу много букф, т.к. исправление данного бага считаю важным и это проявляется в программе на Harbour, а на клиппере всё, правильно, как и должно быть .... Наверное не был услышан, но умею пользоваться шаблонами и etc. Более того понимаю Диму - попытался сделать самостоятельный пример и там всё работает правильно. Пример (иммитация логики программы): proc ptest() loca a:=" ", b:=" " cls @ 1,1 say "введите символы" get a @ 2,1 say "нажмите символ " get b read ptest2() retu proc ptest2() loca a:=" ", b:=" " @ 4,1 say "введите символы" get a @ 5,1 say "нажмите символ " get b read @ 6,0 say "нажмите клавишу "+b+" "+a inkey(0) retu Далее приведу реальный текст процедур, где ***** будут выделены ключевые моменты. Это один из десятков отчетов, где наблюдается данный глюк. Разбил на два сообщения, т.к. форум не хочет по русски воспринимать копипаст

AndreyZh: „P„‚„Ђ„t„Ђ„|„w„u„~„y„u. „Q„u„p„|„Ћ„~„Ђ„u „Ѓ„‚„y„|„Ђ„w„u„~„y„u... Всё конечно жутко понятно? ... попробую разделить на маленькое кусочки [pre2] * --------------------------------------------------------------------------- * Оборотная ведомость по финансовым операциям. Анализ кассы, банка по осно- * ваниям документов. * 03.2007 Доб. коррекцию начального сальдо. Работа по нескольким расч/счетам STAT PROC pObFins() LOCA cOldCol:=SetColor(), GetList:={}, dD:=Date(), dT:=Date(), nN:=0, nS:=0, cT:="" LOCA dBeg:=Date(), dEnd:=Date(), nPer:=1, nCash:=3, cReas:=Spac(15), nSaldo:=0 LOCA nBeg:=0, nEnd:=0, nPrih:=0, nRash:=0, np:=0, nr:=0 LOCA nStr:=99999, nPage:=0, nC:=0, nJ:=0, nRep:=77 LOCA cDbf:="", cNtx:="", cTxt:="" LOCA aArr:={{"dMove", "D", 8, 0},; {"sum", "N", 15, 2},; // Приход {"sumPut", "N", 15, 2}} // Расход LOCA sOp:="7655", cOff:=" " S_PROC cSent3 := Spac(25) // Из ЭФ читаем параметры построения отчета. fsWopen(16,18,7,59,cColor,2) @ 1,1 SAY "Пожалуйста вв. дату начала ........ конца ........ периода" @ 2,1 SAY "Цифру 1-Касса,2-Банк,3-Все . Длину подпериода(0-месяц) ..." @ 3,1 SAY "Набор букв основания документов или ничего ..............." @ 4,1 SAY "Набор букв сист.метки (F3) ........................." @ 5,1 SAY "Коррекция для начального сальдо по кассе/банку ..........." @ 6,1 SAY "Разделитель чисел для экспорта в MsOffice или ничего ." @1,28 GET dBeg VALI lValid({||dBeg<=Date()},"Больше текущей!") @1,43 GET dEnd VALI lValid({||dBeg<=dEnd},"Меньше начальной!") @2,28 GET nCash PICT "9" VALI Eval({||nSaldo:=IF(nCash=1,nCashSaldo,IF(nCash=2,nBankSaldo,nCashSaldo+nBankSaldo)),TRUE}) @2,56 GET nPer PICT "999" VALI lValid({||nPer>=0},"Отрицательная длина периода!") @3,44 GET cReas @4,34 GET cSent3 PICT "@S25" @5,48 GET nSaldo PICT "99999999.99" ***** Поведение зависит от введенного символа (глюки только, если точка или запятая) @6,58 GET cOff PICT "X" READ fDeact(cOldCol) cReas := Upper(Alltrim(cReas)) cSent3 := Upper(Alltrim(cSent3)) AP__INPUT ***** В принципе данная вставка решает проблему ****** изначально её не было и пока всё не переделал IF LastKey() == 44 .OR. LastKey() == 46 KEYB Chr(K_ENTER) Inkey(0) ENDI ******************************************** далее постороение отчета - некой вспомогательной таблицы // Настройка баз, расчет бегунка и т/д fTxt_act(" Пожалуйста подождите несколько минут!",cColor) nBeg := nSaldo SELE CASH_ORD ORDE CO_DAT_NUMBER IF nCash <> 2 COUNT TO nC WHIL dat <= dEnd ENDI SELE ACCOUNT ORDE A_DAT_NUMBER IF nCash <> 1 COUNT TO nN WHIL dat <= dEnd ENDI nC += nN cDbf := zTemp(cdTemp,"DBF",32) cNtx := zTemp(cdTemp,"NTX",32) cTxt := zTemp(cdTemp,"TXT",32) DbCreate(cDbf,aArr) LanUse("",cDbf,NO_INDEX,"TEMP",EXCL_MODE,-1,NEW_SEL) INDE ON dMove TO (cNtx) fDeact( cOldCol ) // Построение временной базы на основе первичных документов. pOpenView(cColor,cError,"Подождите! Строю оборотку по деньгам",TRUE) FOR nN := 1 TO 2 IF nCash == 1 .AND. nN == 2 THEN LOOP IF nCash == 2 .AND. nN == 1 THEN LOOP DbSelectArea( IF(nN=1,"CASH_ORD","ACCOUNT") ) DbGoTop() DO WHIL !Eof() .AND. dat <= dEnd pChangeView(++nJ*100/nC) IF Empty(datPay) THEN DbSkip(); LOOP IF !Empty(cReas) .AND. At(cReas,Upper(reason)) <= 0 THEN DbSkip(); LOOP IF !Empty(cSent3) .AND. At(cSent3,Upper(lab1)) <= 0 THEN DbSkip(); LOOP // Расчет начального сальдо. IF dat < dBeg nBeg += IF(tip=="1",(+1),(-1))*sum DbSkip() LOOP ENDI // Обработка операции. Добавляю при необходимости запись во времянку dD := dat nS := sum cT := tip SELE TEMP SEEK dD IF Eof() DbAppend() dMove := dD ENDI IF cT == "1" sum += nS ELSE sumPut += nS ENDI DbSelectArea( IF(nN=1,"CASH_ORD","ACCOUNT") ) DbSkip() ENDD NEXT nN ****** Отчет (таблица) преобразовывается в текстовый файл, который затем отражаю через набор устройств // Вывожу отчет в текстовый файл, считая итоги по подпериодам. SELE TEMP TOP dT := Max(dBeg,dMove) dD := Min(IF(nPer==0,Eom(dT),dT+nPer-1),dEnd) O____A ****** В принципе на эту верку попадаю, когда определяю знак разделитель в форме, но проверял в "обычных" вариантах - такая же херь IF !Empty(cOff) // Экспорт в офис ? "Оборотная ведомость по "+IF(nCash=1,"кассе",IF(nCash=2,"банку","деньгам"))+" с "+Dtoc(dBeg)+" по "+Dtoc(dEnd) ? " Подпериод времени Ост. на начало Приход Расход Ост.на конец " DO WHIL !Eof() X_DEMO IF dMove > dD // Перешли в другой подпериод. Отражаем итоги. ? IF(nPer==0,Left(zCmonth(dT)+Spac(17),17)+Str(Year(dT),4),Dtoc(dT)+" - "+Dtoc(dD))+" "+zStr(nBeg,14,2,cOff)+" "+zStr(np,12,2,cOff)+" "+zStr(nr,12,2,cOff)+" "+zStr(nBeg+np-nr,14,2,cOff) nBeg += np - nr np := nr := 0 dT := dMove dD := Min(IF(nPer==0,Eom(dT),dT+nPer-1),dEnd) ++nStr ENDI // Считаем параметры. np += sum nr += sumPut DbSkip() ENDD // Отражаю данные по последнему периоду и общие итоги. ? IF(nPer==0,Left(zCmonth(dT)+Spac(17),17)+Str(Year(dT),4),Dtoc(dT)+" - "+Dtoc(dD))+" "+zStr(nBeg,14,2,cOff)+" "+zStr(np,12,2,cOff)+" "+zStr(nr,12,2,cOff)+" "+zStr(nBeg+np-nr,14,2,cOff) ? Chr(12) *********** ELSE // Печатаемый формат DO WHIL !Eof() X_DEMO // Выводим шапку, если надо. IF nStr > nLenst IF nPage > 0 THEN Qout(Chr(12)) ? Padc("Оборотная ведомость по "+IF(nCash=1,"кассе",IF(nCash=2,"банку","деньгам"))+" с "+Dtoc(dBeg)+" по "+Dtoc(dEnd),nRep-7)+"Стр."+Str(++nPage,3) ? Repl("-",nRep) ? " Подпериод времени |Ост. на начало| Приход | Расход | Ост.на конец " ? Repl("-",nRep) nStr := 4 ENDI IF dMove > dD // Перешли в другой подпериод. Отражаем итоги. ? IF(nPer==0,Left(zCmonth(dT)+Spac(17),17)+Str(Year(dT),4),Dtoc(dT)+" - "+Dtoc(dD))+" "+cStr(nBeg,14,2)+" "+cStr(np,12,2)+" "+cStr(nr,12,2)+" "+cStr(nBeg+np-nr,14,2) nBeg += np - nr np := nr := 0 dT := dMove dD := Min(IF(nPer==0,Eom(dT),dT+nPer-1),dEnd) ++nStr ENDI // Считаем параметры. np += sum nr += sumPut nPrih += sum nRash += sumPut DbSkip() ENDD // Отражаю данные по последнему периоду и общие итоги. ? IF(nPer==0,Left(zCmonth(dT)+Spac(17),17)+Str(Year(dT),4),Dtoc(dT)+" - "+Dtoc(dD))+" "+cStr(nBeg,14,2)+" "+cStr(np,12,2)+" "+cStr(nr,12,2)+" "+cStr(nBeg+np-nr,14,2) ? Repl("-",nRep) ? Spac(36)+cStr(nPrih,13,2)+cStr(nRash,13,2) ? Chr(12) ENDI C____A pCloseView() ***************** Вывожу текстовый файл, используя отдельную процедуру печати, где по сути и проявляется данный глюк // Демонстрирую отчет и восстанавливаю состояние среды. pFileOutDevice(cTxt) pCloseErase("TEMP",{cDbf,cNtx,cTxt}) pinStat(sOp,0) RETU [/pre2]

AndreyZh: [pre2] PROC pFileOutDevice( cFile, nLen, nW, cdbfm ) FIEL compr, filen, begStr, endStr, qtyCopy LOCA nDev := ngOutDev LOCA nBeg := 1 // „N„p„‰„p„|„Ћ„~„p„‘ „ѓ„„„‚„p„~„y„?„p LOCA nEnd := 9999 // „K„Ђ„~„u„‰„~„p„‘ „ѓ„„„‚„p„~„y„?„p. LOCA nQty := 1 // „K„Ђ„|„y„‰„u„ѓ„„„r„Ђ „Џ„{„x„u„}„Ѓ„|„‘„‚„Ђ„r. LOCA cOldCol:=SetColor(), nSel:=Select(), cStr:="", aDbf:={}, cF:="" LOCA nSize:=FileSize(cFile), cString:="", GetList:={} LOCA nI:=0, cSt:="" LOCA axbk:={{"compr", "L", 1, 0},; {"filen", "C", 70, 0},; {"begStr", "N", 10, 0},; {"endStr", "N", 10, 0},; {"qtyCopy", "N", 10, 0}} PRIV cNameFile:="", cOutFile:="", lLoop:=TRUE DEFAULT nLen TO 80 DEFAULT nW TO 6 DEFAULT cdbfm TO "" MEMV->cNameFile := AllTrim(cFile) fSwopen(16,17,7,60,cOther,4) DO WHIL TRUE ******* Казалось бы читаем из обычной формы ввода, но Harbour ппосле её открытия нажимает некие клавиши, что даёт сразу вывод на устройство по умолчани. @ 5,0 SAY Chr(199)+Repl("„џ",59)+Chr(182) COLO PosRepl(cOther,Repl(" ",AT("/",cOther)-2)+"N",1) @ 1,2 SAY "„D„|„‘ „Ѓ„u„‰„p„„„y „Ђ„„„‰„u„„„p/„t„Ђ„{„…„}„u„~„„„p „Ѓ„Ђ„w„p„|„…„z„ѓ„„„p „…„{„p„w„y„„„u „…„ѓ„„„‚„Ђ„z„ѓ„„„r„Ђ" @ 2,2 SAY "1-„P„‚„y„~„„„u„‚,2-„U„p„z„|,3-„^„{„‚,4-„V„A„K,5-Exc„V„A„K,6-„Q„u„t„p„{„„„Ђ„‚,7-Word ." @ 3,2 SAY "„~„p„‰„p„|„Ћ„~„…„ђ „y „{„Ђ„~„u„‰„~„…„ђ „ѓ„„„‚„p„~„y„?„Ќ „y„x „t„Ђ„{„…„}„u„~„„„p" @ 4,2 SAY "„p „„„p„{„w„u „{„Ђ„|„y„‰„u„ѓ„„„r„Ђ „Џ„{„x„u„}„Ѓ„|„‘„‚„Ђ„r „Ѓ„u„‰„p„„„y „t„Ђ„{„…„}„u„~„„„p " @2,58 GET nDev PICT "9" VALI nDev>=1 .AND. nDev<=7 @3,12 GET nBeg WHEN nDev==1.OR.nDev==4 PICT "9999" VALI nBeg>=1 @3,30 GET nEnd WHEN nDev==1.OR.nDev==4 PICT "9999" VALI nBeg<=nEnd @4,56 GET nQty WHEN nDev==1.OR.nDev==4 PICT "999" VALI nQty>=1 READ ****** Это старая ошибка Harbour, которые разработчики уже исправили, но по своей глупой привычке использую свои обработки этого глюка /***** Смотреть как Lack будет реагировать на данный обработчик глюка. При этом появляется глюк Clipper - при прощелкивании Enter запросы идут по кругу, т.е. Ent не обрабатывается и переходим в обработку цикла */ IF lGlukHarb(nDev) THEN LOOP [/pre2]

AndreyZh: Добрый день! Системные программисты (разработчики), понимающие принципы "математики" xHarbour... ГДЕ ВЫ!!! Очередная пачка глюков данной системы разработки: 1. Деление и умножение обсудили раннее, а оказывается xharbour не умеет даже вычитать и складывать Сколько по Вашему будет (12.2 - 4.4 - 7.8) = ?, а теперь проверьте: WAIT Str((12.2 - 4.4 - 7.8)*1000000000,19,6) 2. Синтаксическая ошибка Wait "MAMA" * "PAPA" успешно пропускается компилятором, но программа вываливается по windows ошибке "too many recursive error handler calls"

Dima: AndreyZh пишет: Сколько по Вашему будет (12.2 - 4.4 - 7.8) = ?, Округляй результат. Clipper кстати так же отработал. ? (12.2 - 4.4 - 7.8)==0 // .F. ? round((12.2 - 4.4 - 7.8),2)==0 // .T.

Сыроежка: AndreyZh пишет: Сколько по Вашему будет (12.2 - 4.4 - 7.8) = ?, а теперь проверьте: Проверил! MS VC++ 2010: [pre2]if ( 12.2 - 4.4 - 7.8 == 0 ) std::cout << "equal to zero\n"; else std::cout << "not equal to zero\n"; std::cout << 12.2 - 4.4 - 7.8 << std::endl;[/pre2] Результат: not equal to zero -8.88178e-016

TimTim: AndreyZh пишет: Сколько по Вашему будет (12.2 - 4.4 - 7.8) = ? Это явление в вычислительной математике давно описано в учебниках по методам вычислений. Например, Бахвалов Н.С. Численные методы, М. 1975. В параграфе 4 "О вычислительной погрешности", в частности, автор пишет: "Здесь нам впервые встретилось явление потери значащих цифр (или "пропадания значащих цифр"), имеющее место при вычитании близких величин ...".

AndreyZh: Dima пишет: Округляй результат. Clipper кстати так же отработал. ? (12.2 - 4.4 - 7.8)==0 // .F. ? round((12.2 - 4.4 - 7.8),2)==0 // .T. На это считаю полезным отметить... заодно посмотрите результат Сыроежки... получаемая цифирь может быть, как больше, так и меньше нуля, кроме это вполне допустимы расчеты, где нормально, что результат "около нуля", т.е. банальные проверки типа "если имеется долг (сумма отгрузки - сумма платежей) клиента, то запретить ему отгрузку", а особенно если имеются скидки/наценки по накладной превращаются в громадные аналитические конструкции, где пытаешься отрабатывать, как "нормальные" погрешности округления, так и погрешности, связанные с логикой подгонки цифр в документах, так и с погрешностями "типа правильного счета" системы разработки. Просто замечу, что ни в клиппер, ни в фоксе, ни в си шарп, ни в аксес таких заморочек (на всей этой команде приходится пописывать) и "особенностей" не возникает, т.е. это не "математические особенности округления", а недоработки инструмента... в данном случае xharbour. Что по особенности Клиппер: а := 0.00 if a == 0.... Над этой ошибкой пришлось в древности много работать и учитывать, кроме того она по разному обрабатывается на разных ОС и разных типах процессоров. Вообще в данной темке "не обсираю" харб, а просто предупреждаю о возможных грабельках других раработчиков и если не интересно, то ...

Pasha: AndreyZh пишет: 1. Деление и умножение обсудили раннее, а оказывается xharbour не умеет даже вычитать и складывать Так мы ведь в прошлом году как раз вычитание и обсуждали, не ? Вот цитата от 22.09.11 18:58: Если "объяснения" по делению можно было как-то понять, то ошибки выитания (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 Я и тест делал, в котором видно, что примерно в 1/8 случаев при вычитании double fpu не дает ноль, или равенство. Для гарантированного получения нужного результата необходимо промежуточное округление. И харбор тут ни при чем, как и клиппер и любой другой язык, использующий явно или неявно тип double.

Pasha: AndreyZh пишет: Просто замечу, что ни в клиппер, ни в фоксе, ни в си шарп, ни в аксес таких заморочек (на всей этой команде приходится пописывать) и "особенностей" не возникает, т.е. это не "математические особенности округления", а недоработки инструмента... в данном случае xharbour. Как же не возникает, когда именно возникает именно такая же заморочка с клиппером. Дима же проверил. Да и я только что проверил. Насчет фокса мы когда-то выясняли, там имеется недокументированное неявное округление. О прочих инструментах говорить не буду.

PSP: Надо уже в Интел и АМД телегу писАть. Чё-та их ФПУ хреново складыватьумножатьвычитатьделить умеют... :)

Dima: По поводу фокса можно почитать тут

AndreyZh: Dima пишет: По поводу фокса можно почитать тут Доброе утро господа! Я не фоксист, не сишник, не и etc... Просто приходится зачастую использовать разный инструмент для решения конкретных задач. Все задачи связаны с бизнес расчетами и как следствие математика является основным нюансом на который обращают внимание пользователи. Как уже отмечал... не пытаюсь очень вникнуть во внутреннию топологию систем разработки. Все проблемки выявляют пользователи (по скромной оценке около 1000 человек) и ставят меня в известность... после чего пытаюсь найти источник проблемы и способ её исправления. Если пофилософствоать, то инструмент работы с базами или финансовой информацией должен в первую очередь обеспечивать стабильность работы с ней и "бухгалтерскую" точность (точность бухгалтерских расчетов). Если же в программе нужно также рассчитать траекторию полета спутника, то придется дописывать програмку на Си. Теперь по конкретным инструментам. Пока ещё в основном используется Clipper 5.01R + CTII и на его "методику" ориентируюсь в "сравнениях". На "вход" переделки под xharbour пошла программа отлаженная в течении 17 лет, в том числе отработаны "грабельки" данной версии клиппера, а тут оказывается не только есть "частичная" несовместимость языков, но и иные алгоритмы "математики". Лирика... на sql фоксисты рассуждают "куда податься с него" и получается, харбоур "тоже не вариант"? Хотя и имеет море предпосылок, что бы заменить все виды померших настольных СУБД. Что по "неумению считать" здесь озвучена идея "недокументированное неявное округление", наверное, что имело быть в пятом клиппере... а ведь это весьма разумно в бизнес приложениях. Под обсуждение арифметики как-то спрятались и другие "занятные" проблемки, озвученные выше: 1. Синтаксическая ошибка Wait "MAMA" * "PAPA" успешно пропускается компилятором, но программа вываливается по windows ошибке "too many recursive error handler calls" 2. Нелюбовь xHarbour к точке и запятой, в качестве переменной формы ввода.

Pasha: AndreyZh пишет: 1. Синтаксическая ошибка Wait "MAMA" * "PAPA" успешно пропускается компилятором, но программа вываливается по windows ошибке "too many recursive error handler calls" Что-то я не могу подтвердить такой результат. Компилятор и должен пропускать такую конструкцию, поскольку харбор язык с нестрогой типизацией. Это не синтаксическая ошибка, и клиппер это выражение тоже компилирует, как и харбор. А при его выполнении возникает ошибка "argument error", поскольку операция умножения для строк недопустима. "too many recursive error handler calls" - это уже результат работы обработчика ошибок. Стандартный обработчик ошибок xHarbour такое сообщение не дает. Возможно, у Вас он заменен своим. Смотрите свой обработчик ошибок.

PSP: AndreyZh пишет: то инструмент работы с базами или финансовой информацией должен в первую очередь обеспечивать стабильность работы с ней и "бухгалтерскую" точность (точность бухгалтерских расчетов). Откуда инструмент может знать, что программисту нужна "бухгалтерская" точность? Инструмент её обеспечивает, но только тогда, когда человек явно этого попросит.

Pasha: AndreyZh пишет: Что по "неумению считать" здесь озвучена идея "недокументированное неявное округление", наверное, что имело быть в пятом клиппере... а ведь это весьма разумно в бизнес приложениях. Ничего не понятно. Клиппер 5.01, который Вы используете, при операциях с double ведет себя точно так же, как и харбор. Никакого недокументированного округления там и в помине нет. Так зачем его вводить в харборе ? Тогда харбор будет вести себя не так, как клиппер. В ваших примерах клиппер и харбор дают одинаковый результат. Можете дать пример, в котором они ведут себя по разному ? С клиппером у вас дожны были быть такие же заморочки, как и с харбором. Но с клиппером почему-то это проблемы не создавало, а с харбором начало создавать ? Или просто на клиппер некому было пожаловаться ? :)

AndreyZh: Pasha пишет: AndreyZh пишет: цитата: 1. Синтаксическая ошибка Wait "MAMA" * "PAPA" успешно пропускается компилятором, но программа вываливается по windows ошибке "too many recursive error handler calls" Что-то я не могу подтвердить такой результат. Компилятор и должен пропускать такую конструкцию, поскольку харбор язык с нестрогой типизацией. Это не синтаксическая ошибка, и клиппер это выражение тоже компилирует, как и харбор. А при его выполнении возникает ошибка "argument error", поскольку операция умножения для строк недопустима. "too many recursive error handler calls" - это уже результат работы обработчика ошибок. Стандартный обработчик ошибок xHarbour такое сообщение не дает. Возможно, у Вас он заменен своим. Смотрите свой обработчик ошибок. Использую редакцию xHarbour 1.2.1 rev 6633... по обработчикам ошибок не пугайте такими словами (шутка). Ругается не харб, а судя по win окнам сами винды... Смотрите:

PSP: AndreyZh пишет: Ругается не харб, а судя по win окнам сами винды... Нет, это не винда, а именно хХ. Обработчик ошибок зациклился на вызовах самого себя.

AndreyZh: PSP пишет: Откуда инструмент может знать, что программисту нужна "бухгалтерская" точность? Инструмент её обеспечивает, но только тогда, когда человек явно этого попросит. А что... какой результат можно попросить от операции 12.2 - 4.4 - 7.8? Теперь... от куда данные цифры. Есть операция распределения товаров накладной по нескольким складам (отделам магазина). В данном случае пришло 12.2 кг. товара, где в первый отдел нужно определить 4.4 кг, а во второй 7.8. Бедный оператор соглашается с числом 7.8, а прога в ответ не могу.... блок программы уже с извращениями (исправлениями): [pre2] nMax := qtyAll fSwopen(21,0,3,79,cOther,2) DO WHIL !Eof() .AND. codInv==cInv // Читаем распределение по конкретному складу и товару. cCodStores := Spac(2) 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+0.000001},"Неверное кол-во. Отрицательно или слишком большое!") .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 пишет: С клиппером у вас дожны были быть такие же заморочки, как и с харбором. Но с клиппером почему-то это проблемы не создавало, а с харбором начало создавать ? Или просто на клиппер некому было пожаловаться ? :) Этот блок использовался без изменения уже больше 20 лет... еще и системы не было... а операция "распределения" производится (провожу ежегодный анализ) более 50 000 раз по всем клиентам (или перебирают больше 200 000 комплектов цифр ежегодно)... была бы проблема - давно бы наткнулся. На xHarb она поперла в виде звонков ежедневно, как начал переводить розничные магазины.

PSP: AndreyZh пишет: А что... какой результат можно попросить от операции 12.2 - 4.4 - 7.8? _SET_DECIMALS в какое значение установлен? Может поменьше сделать, а? Ты уж определись, какая точность тебе нужна. Не думаю, что при расчете масс, сумм, количеств нужна точность в 10 знаков.

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 так же

Pasha: Dima пишет: 5.01 .F. 5.2e .F. без picture так же Да у меня тоже самое. Со стандартной getsys. Но в рабочих программах я использую свою getsys, и она дает результат T Возможно, у Андрея Жукова тоже своя нестандартная getsys, которая меняет значение переменной, даже если она не изменяется.

Dima: Pasha пишет: Возможно, у Андрея Жукова тоже своя нестандартная getsys и мне так кажется. AndreyZh пишет: 2. Нелюбовь xHarbour к точке и запятой, в качестве переменной формы ввода. И тут похоже в этом дело. Ждем Андрея.

Pasha: Все-таки ситуация другая, getsys ни при чем. Во время редакции значения 4.4 переменная содержит не 4.4, а результат 12.2-7.8, то есть 4.4+eps Если в клиппере нажать просто enter, то значение останется 4.4+eps, и сравниваться будет сама с собой, и сравнение сработает Если ввести 4.4, то затем сравнение 4.4 с 4.4+eps не сработает В xHarbour имеется побочное действие: если не вводить 4.4, а нажать enter, то значение переменной все равно изменится с 4.4+eps на 4.4, и затем сравнение 4.4 с 4.4+eps не сработает в Harbour этого побочного действия нет, и он работает так же, как и клиппер

Pasha: Во всяком случае причина понятна. Это не разное выполнение арифметических операций, никакое не неправильное вычитание. Причина как раз в том, что в xHarbour имеется недокументированное свойство округлять при вводе в get значение переменной. А округление как раз и не нужно, так как после get оно приводит к неравенству при сравнении с округленного и неокругленного значения.

PSP: Да уж... Вот тебе и xHarbour...

AndreyZh: Громадное спасибо за весьма конструктивное обсуждение!!! Причины возможно ясны... только хотелось бы сейчас при наличии ПК проверить все высказанные гипотезы и тесты... а затем, если Вы захотите попробуем разобраться с нелюбовью xHarbour к точке и запятой - конструкции довольно громоздкие, т.е. боюсь, что самодостаточный пример сложно будет придумать, но... если сможете быть любезны скачать дистрибутив (очень легкая сейчас установка), содержащий и исходники, как проги на клиппер, так и на Харб (правда 35 метров) ДИСТРИБУТИВ, то может быть легче будет меня понять... в принципе дистрибутив содержит и батники для сборок, т.е. несложно пересобрать и под любую версию клиппера Сейчас, с Вашего позволения я поиграюсь с высказанными идеями и вернусь.....

PSP: AndreyZh, проверь, заодно, свои задачи на Harbour.

AndreyZh: PSP пишет: AndreyZh, проверь, заодно, свои задачи на Harbour. Млин!!! - Советчик... Основное время потратил, что бы установить и как-то научиться делать на нем компиляцию... Harbour 2.0.0 Rev 13372 Отмечу сразу - идентично Clipper 5.01R Мне понравилось предположение по PICTURE (GET - у меня неизмененноы) и сразу решил его прокачать - да... здесь проблема, причем действительно у xHarbour. Чуть изменил тест и на первое поле вводил число ручками, а во втором просто нажимал Enter. В первом get результаты были нулевыми везде, а во втором Clipper&Harbour, если не менять значение, то получалось ноль, а в xHarbour ненулевое число. Различие только тут... все остальные числа идентичны. Использовал код: [pre2] loca nmax loca nqty loca nq loca getlist:={} //****** ТЕСТЫ ХАРБА CLS nmax := 12.2 nQty := nQ := nMax @1,1 SAY "Количество:" GET nQty PICT "9999999.999" @2,1 SAY "Количество:" GET nQ PICT "9999999.999" READ @ 3,1 say str((nqty-nmax)*10000000000,19,9) @ 4,1 say str((nq-nmax) *10000000000,19,9) nmax := 12.2-4.4 nQty -= 4.4 nQ -= 4.4 @6,1 SAY "Количество:" GET nQty PICT "9999999.999" @7,1 SAY "Количество:" GET nQ PICT "9999999.999" READ @ 8,1 say str((nqty-nmax)*10000000000,19,9) @ 9,1 say str((nq-nmax) *10000000000,19,9) @10,1 say str((nmax-7.8) *10000000000,19,9) IF 4195835.129876 - ((4195835.129876 / 3145727.129876) * 3145727.129876) #0 ? "BAD" ELSE ? "OK" ENDIF wait //****** КОНЕЦ ТЕСТА [/pre2] Dima пишет: А какой результат выдаст такой тест на Вашей машинке ? IF 4195835.129876 - ((4195835.129876 / 3145727.129876) * 3145727.129876) #0 ? "BAD" ELSE ? "OK" ENDIF Все 3 системы (clipper 5.01r, xHarbour, Harbour) - OK Dima пишет: А какой результат выдаст такой тест на Вашей машинке ? IF 4195835.129876 - ((4195835.129876 / 3145727.129876) * 3145727.129876) #0 ? "BAD" ELSE ? "OK" ENDIF Dima пишет: Не пойму совсем о чем спорим ;) Ведь очевидно же что полученный результат нужно округлять , иначе будут периодически лезть вот такие вот "глюки" в программе. Должен признать что и сам (очень давно правда) в своих программах не округлял результат и соответственно лезли похожие глюки. На скрине идет работа с килограммами и граммами , ну так ясное дело что округлять нужно результаты до 3 знаков после запятой , иначе пользователи Ваc заклюют Здесь, к сожалению не всё так просто... в реальности приходится прогибаться под набор требований: 1. Что бы считало, как 1ц... либо по логике бухов 2. Реальные оперативные суммы (по разным клиентам) от 1 руб до 1 000 000 000 и количества от 0.001 до 1 000 000 3. Приходится манипулировать весами (точность 3 знака), объемами (точность 5 знаков) и количествами в производстве (точность 6 знаков)... тут ещё и алкоголь (с плавающей точностью). Конечно... и уже увидел, что нужно перепахивать все расчеты - весьма неприятно, т.к. придется лезть в многочисленные отлаженные блоки и это ни к чему хорошему не приведёт!

PSP: AndreyZh пишет: Млин!!! - Советчик... Основное время потратил, что бы установить и как-то научиться делать на нем компиляцию... А что ж так? В файле INSTALL есть вся информация.

AndreyZh: PSP пишет: что ж так? В файле INSTALL есть вся информация. Кто же инструкции читает? Покажите мне такого человека?... но вообще говоря Харбор у меня не стоял, да и щупал его очень давно... К сожалению вынужден исчезнуть до 13 в места, где к счастью нет компьютеров... и даже телефон не ловит. Всем приятных праздников!

Pasha: AndreyZh пишет: Основное время потратил, что бы установить и как-то научиться делать на нем компиляцию... Harbour 2.0.0 Rev 13372 Отмечу сразу - идентично Clipper 5.01R Уже почти год как вышел Harbour 3.0, и лучше использовать его. И для развития своей системы лучше ориентироваться на Harbour. Развитие xHarbour остановилось уже почти 4 года как, разработчики или перешли в команду Harbour, или занимаются другими делами. А Harbour как раз продолжает развиваться, и по этой причине несовместимостей с клиппером у него меньше. Хотя, конечно, в редких случаях могут быть неожиданные сюрпризы с совместимостью и в Harbour.

AndreyZh: Всем приятного "понедельника"! Pasha пишет: Уже почти год как вышел Harbour 3.0, и лучше использовать его. И для развития своей системы лучше ориентироваться на Harbour. Развитие xHarbour остановилось уже почти 4 года как, разработчики или перешли в команду Harbour, или занимаются другими делами. А Harbour как раз продолжает развиваться, и по этой причине несовместимостей с клиппером у него меньше. Хотя, конечно, в редких случаях могут быть неожиданные сюрпризы с совместимостью и в Harbour. Желающих помочь разобраться с неприятием точки и запятой xHarbour нет? Ну и ладно нашел решение, хотя и без понимания его эффекта... если у кого так же будут глюки, но после read вставьте код типа: if lastkey() = 44 .or. lastkey() = 46 keyb chr(K_ENTER) inkey(0) endi Теперь для уважаемого Pasha - почему xharbour? Во первых прочтение инструкции Верченко Андрея (Andrey), где очень легко описывалось "вхождение" в данную систему разработки стимулировало попробовать её, а во вторых xHarbour, как прочитал на данном форуме лучше поддерживал оконные функции CT II. Менять уже более-менее отлаженную систему на "неизвестно что" пока не вижу смысла, да и глюки с вашей помощью получается обходить. Что касается "глобальной" переделки под графический интерфейс и с нормальной СУБД, то внимательно присмотрюсь к творчеству Филатова (miniGui) и Кресина (LetoDB) и очень надеюсь, что к тому моменту появится нечто стабильное и хоть как-то документированное ... и конечно Harbour.

Pasha: AndreyZh пишет: Желающих помочь разобраться с неприятием точки и запятой xHarbour нет? Ну и ладно нашел решение, хотя и без понимания его эффекта... если у кого так же будут глюки, но после read вставьте код типа: if lastkey() = 44 .or. lastkey() = 46 keyb chr(K_ENTER) inkey(0) endi Этот код можно заменить одной строкой: SetLastKey( K_ENTER ) Заодно и проблема становится понятной. В клиппере и xHarbour после read наверное остается разное значение lastkey Можно попробовать сделать тесты. Как я понимаю, в односимвольную переменную вводится точка с запятой ? Вот и прогнать тест: local c := ' ' @ 1, 1 say 'Ввод' get c read ? lastkey() Я сейчас работаю под win64, так что клиппер и запустить то не могу, разве что под эмулятором Интересно, есть ли эта несовместимость в Harbour ?

Pasha: AndreyZh пишет: xHarbour, как прочитал на данном форуме лучше поддерживал оконные функции CT II Откуда взялось это мнение, и когда оно было высказано, теперь наверное и не выяснить. Я сам оконные функции ct не использую, так что по поводу совместимости ничего не скажу. Могу рассказать историю создания этих функций. Она имеет польские корни. Изначально эти функции были сделаны как prg-модуль в xHarbour, автор - Adam Lubszczyk. Затем в xHarbour же они были переписаны на C-уровень, причем часть функциональности перенесена непосредственно в терминал-api, работа Henryk Olkowski. Затем в 2006-м, уже в Harbour, Przemek их полностью переписал. Позднее вариант Przemek'a был портирован в xHarbour. Таким образом, в олбеих продуктах сейчас присутствует одна и та же реализация оконных функций. Разница в том, что xHarbour перестал развиваться, в отличие от Harbour, так что думается, в Harbour они более проработаны, тем более их автор уже давно как в команде Harbour, а не xHarbour.

AndreyZh: Pasha пишет: Вот и прогнать тест: local c := ' ' @ 1, 1 say 'Ввод' get c read ? lastkey() Во первых и клиппер и [x]Harbour возвращают ожидаемые key коды. Проблема: в тестовом примере, приведённом раннее все работает правильно и ожидаемо, а в реальном приложении приходится изголяться. Что по развивающемуся Harbour или стагнирующему xHarbour (хотя Patrick постоянно присылает релизы об успехах развития XHarbour) приведенный пример wait "mama" * "papa" обе системы, хоть и по разному но "необрабатывают" на уровне компилятора: xHarbour вызывает переполнение стека, как пояснили выше Harbour выполняя wait далее вываливается по ошибке выполнения, т.е. "те же balls только вид сбоку" - ИМХО

Pasha: AndreyZh пишет: приведенный пример wait "mama" * "papa" обе системы, хоть и по разному но "необрабатывают" на уровне компилятора: Не только оба харбора, но и все 5-е клипперы, от 5.01 до 5.3 точно также "необрабатывают" этот оператор на уровне компилятора, поскольку этот оператор допустим с точки зрения синтаксиса этих языков. Ну а по поводу ошибки переполнения стека, так она возникает в модуле errorsys. При выполнении "mama" * "papa" возникает ошибка argument error, управление передается обработчику ошибок, в нем во время обработки этой ошибки тоже возникает ошибка, управление опять передается этому же обработчику, ну и так далее до переполнения стека. Прчем в стандартном обработчике ошибок xHarbour ошибки в errorsys не возникает, Возможно, вы переопределили этот обработчик на свой, в котором и возникает ошибка.

AndreyZh: Pasha пишет: Прчем в стандартном обработчике ошибок xHarbour ошибки в errorsys не возникает, Возможно, вы переопределили этот обработчик на свой, в котором и возникает ошибка Ничего не менял...

Pasha: AndreyZh пишет: Желающих помочь разобраться с неприятием точки и запятой xHarbour нет? Так в чем состоит различие в поведении клиппера и хХарбора ? Собрать и запустить ваш пример возможности нет никакой. Можете описать словами ? Какие переменные вводятся ? Что именно вводится ? Различие проявляется в процессе ввода ? Вводимые переменные получают разные значения ? После ввода анализируется lastkey, и управление передается на другую ветку ? Что-то другое ?

AndreyZh: Pasha пишет: Так в чем состоит различие в поведении клиппера и хХарбора ? Различий нет, но при вводе (. или ,) в последний запрос прога на xHarb "начинает жить своей жизнью", если любой другой символ (/*-~ и etc), то она сохраняет его для дальнейшего использования. Тестовый пример, иллюстрирующий подход, но где и xHarb работает конкретно приведён выше. Если Вас не затруднит, то все подробно описано со второй страницы. Pasha пишет: Собрать и запустить ваш пример возможности нет никакой Почему? Всё нормально работает и на 64 разрядной Win All... Установка сделана "для блондинок"... проблемка лишь скачать 35 mb дистрибутива (ссылка есть выше) и ничего собирать не нужно... в нём и clipper и xharbour программы с исходниками, а мои попытки разместить набор связанных исходников оказался почти безуспешным - форум преобразует текста в козябяки

Pasha: AndreyZh пишет: Различий нет, но при вводе (. или ,) в последний запрос прога на xHarb "начинает жить своей жизнью", если любой другой символ (/*-~ и etc), то она сохраняет его для дальнейшего использования. Тестовый пример, иллюстрирующий подход, но где и xHarb работает конкретно приведён выше. Если Вас не затруднит, то все подробно описано со второй страницы. Что такое начинает жить своей жизнью ? Ввод не завершается ? Переменные получают какие-то другие значения, не те, что введены ? После ввода что-то анализируется, например lastkey, и управление передается на другую ветку ? При чем тут 64 бит ? Это клиппер на них не работает. Вы мне предлагаете сравнивать поведение 2-х вариантов вашей системы. Я должен как-то запустить эти 2 варианта, один из них 16-битный, зайти не знаю куда, вводить не знаю что, увидеть в чем-то разницу, потом копаться в мегабайтах сырцов ? Дайте самодостаточный пример. Или хотя бы опишите проблему. Когда я много лет назад адаптировал свои программы под харбор, и не мог сам решить какую-то проблему, я поступал не так. Всю эту предварительную работу проделывал сам, и таки делал этот самодостаточный пример, и давал его тому, кто мог решить эту проблему. Это всегда срабатывало. Не помню, чтобы какая-то существенная проблема оставалась нерешенной.

AndreyZh: Уважаемый Pasha! Я не прошу Вас решить мою проблему, тем более, что её через опу сам порешал. Просто предположил, что нахождение источника её возникновения в интересах сообщества. Вся она досконально описана на 2, 3 страницы с описанием структуры вызовов и приведением связанных выжимок из исходного кода. Самодостаточный пример не придумал, а упрощенный вариант алгоритма давал "правильные" и ожидаемые результаты. Почему предложил использовать для выяснения проблемы дистрибутив? Там бы Вы смогли бы наглядно увидеть глюк программы на xHarbour и четко его отследить по прилагаемым исходникам. Данная проблема возникала во всех отчетах, где в качестве последнего значения вводится единственный символ и он точка или запятая.

Andrey: AndreyZh пишет: Что касается "глобальной" переделки под графический интерфейс и с нормальной СУБД, то внимательно присмотрюсь к творчеству Филатова (miniGui) и Кресина (LetoDB) и очень надеюсь, что к тому моменту появится нечто стабильное и хоть как-то документированное ... и конечно Harbour. Я уже с нового года ковыряю МиниГуи... Успехи так себе, застрял на главном меню программы - стартере для терминалки.... Скин 1 http://shot.qip.ru/003YZC-12Q3rKUxL/ Скин 2 http://shot.qip.ru/003YZC-32Q3rKUxM/ Скин 3 http://shot.qip.ru/003YZC-22Q3rKUxN/ Думаю потом все таки нужно переходить на Harbour + Qt Посмотрел на исходники БАРС-Бюджет http://www.bars-open.ru/ (сборка для 3-х платформ: Linux;Mac OS;MS Windows) Много чего интересного в нем.

Dima: Andrey пишет: Я уже с нового года ковыряю МиниГуи Учел для разных разрешений экрана ? ;) И потом к чему твое сообщение тут ?

Andrey: Dima пишет: Учел для разных разрешений экрана ? ;) Да нет. Пока только 800*600..... Dima пишет: И потом к чему твое сообщение тут ? Из-за этого: Что касается "глобальной" переделки под графический интерфейс и с нормальной СУБД, то внимательно присмотрюсь к творчеству Филатова (miniGui) Работает МиниГуи, и под Ubuntu 11.10, Wine 1.36. Нечего присматриваться, работать надо...

AndreyZh: Andrey пишет: Посмотрел на исходники БАРС-Бюджет http://www.bars-open.ru/ (сборка для 3-х платформ: Linux;Mac OS;MS Windows) Много чего интересного в нем. Извините, если что! Но Вы в курсе, что в "Барсе" непонятно что реализовано на Харбор... по крайней мере весь интерфейс, по их утверждению сделан на C++ & QT

Pasha: Сделал для примера маленький класс Money, в котором исключены ошибки округления при операциях с плавающей точкой, поскольку значения в обьекте класса хранятся в целом формате. К значению переменной класса надо обращаться через метод value: oMoney:value Для создания переменной надо вызвать метод new: local m1 := Money():new( 12.2 ) Переменные класса Money поддерживают арифметические операции, операции сравнения и операцию присваивания. Думаю, этот класс можно будет выложить в harbour\tests Ссылка: http://zalil.ru/33476877

AndreyZh: Спасибо Pasha за пример создания собственного класса Очень интересно для освоения работы с классами, хотя и здесь глобальная "беда" проектов, связанных с Harbour - полное отсутствие документации и документирования, но я разобрался Увы... пока "для меня" это решение пока не подходит - использую единный код для программы на Clipper 5.01 + CT II (там еще нет механизмов создания своих классов) и xHarbour. Для себя определил следующий механизм: #define _ZRND(x) => Round(x,9) ..... После операции/чтения Get записать/переопределить nVal := _ZDND(nVal) что в общем тоже приводит к корректным результатам... P.S. А по нелюбви к точке и запятой идей не появилось?

AndreyZh: ... в догонку ... по теме документирования... Вроде бы всем пользователям в реале объясняю новые вещи в своей системе, отвечаю на "мыло" и звонки, но ВСЕ требуют какую нибудь бумажку для самостоятельного чтения и без неё ну ни как!... пример ежемесячной писульки список модификаций программы При взаимодействии с другими разработчиками по связанным проектам те так же требуют (и дают) четкую и однозначную "ксиву" - если интересно покажу "регламент от программистов Лукойл".

gustow: Про "список модификаций" - у нас это рутина: не наобъясняешься же 200-300 больничкам, что там изменилось. Т.ч. кроме краткого описания (см., например, тут), есть еще отдельным DOC-файликом (чтобы можно было "распечатать и в папочку подшить" - ибо бюрократия вещь хорошая и бессмертна :) ) (например, вот такой стандартный текстик). Снимает 90% "дурацких" вопросов - хотя оставшиеся 10% тоже хорошо взрывают мозг разработчика :). Извиняюсь за оффтоп в ветке, AndreyZh - но сам нарвался :)

AndreyZh: gustow пишет: Про "список модификаций" - у нас это рутина: не наобъясняешься же 200-300 больничкам, что там изменилось По то же и толкую... Что бы сложным продуктом пользовались нужна доходчивая инструкция, понятные статьи и желательно коллективный разум на форуме. gustow пишет: Т.ч. кроме краткого описания (см., например, тут), есть еще отдельным DOC-файликом Да это ссылка для "читателей" сайтов, а так конечно (и это можно увидеть по страничке), что сделана она из word документа. Кроме таких описаловов имеются детальные статейки по реализации и нюансам сложным бизнес технологий и etc... Ну всё это просто на тему - нужны хоть какие-то описания!

gustow: Честно говоря, не совсем понял (жара, туп с утра :) ). AndreyZh пишет: нужны хоть какие-то описания! - это про "описания работы с Harbour/MiniGUI" (поскольку упоминается "коллективный разум на форуме") или про более детальное описание (для разработчиков/юзеров некоего "практического ПО", разрабатываемого более чем одним человеком) апдейтов этого "бизнес-ПО" (того же "Реестра-Стационара")? Если про Harbour (и сопутствующее ему) - какое-то время назад начал склонять желающих пописАть описание Харбора в формате Викиучебника (в этой темке форума), да что-то "что они не делают - не идут дела..." :) ("заготовку" первоначальную сделал - а дальше надо со структурой [содержание] публикации определяться и кропать кто может и хочет "по 3 копейки" кусочками). Если про это разговор - м.б. лучше продолжить в указанной темке?

AndreyZh: Добрый день! Не "соскучились"? А теперь "Memoedit": Логично, да и в Clipper... при перемешении по линии влево и достижении первой колонки курсор должен оставаться на первой колонке при последующих нажатиях стрелки влево, но "фигфам" в xHarbour он улетает в "бесконечность" вправо за территорию текста, т.е. курсор перемещается не по фактически редактируемой строке, а по некой виртуальной буферной строке (шириной 231 знак). Но пользователи этой "задумки" не понимают и ругаются. "Решено" добавлением в функцию пользователя memoedit строчек: FUNC FMEdit(nMode,nRow,nCol) LOCA nKeys:=LastKey() LOCA nRet:=ME_DEFAULT .... DO CASE .... CASE nKeys == K_LEFT .AND. nCol >= 230 CLEAR TYPEAHEAD KEYB Chr(K_HOME) ENDC RETU nRet

AndreyZh: gustow пишет: Если про Harbour (и сопутствующее ему) - какое-то время назад начал склонять желающих пописАть описание Харбора в формате Викиучебника (в этой темке форума), да что-то "что они не делают - не идут дела..." :) ("заготовку" первоначальную сделал - а дальше надо со структурой [содержание] публикации определяться и кропать кто может и хочет "по 3 копейки" кусочками). Если про это разговор - м.б. лучше продолжить в указанной темке? Прочитал это раннее, но и тогда и сейчас сказать по сути нечего... Понятной и вменяемой документации, как ни по Харбор, так ни по обсуждаемых здесь всеьма интересным системам типа LetoDB, miniGUI НЕТ, но кто-то должен её написать. Можно было потребовать её от "коллективного разума", но он это только "щупает" не понимая технологий данных библиотек... а даже краткий список функций с параметрами разработчики не сильно стремяться предоставить... понимаю им интереснее творить. При таком подходе "боюсь", что системы Харбоур остануться уделом, как отметили на другом форуме "секты" выходцев из Clipper

gfilatov2002: AndreyZh пишет: краткий список функций с параметрами Уже есть! См. здесь

Dima: AndreyZh пишет: miniGUI НЕТ В теме есть сайтик где лежит дока.

AndreyZh: gfilatov2002 и уважаемый Dima - пятница вечер и уже сложно, понятно и однозначно выражать свою мысль, но всё же отделив "мух от котлет": 1. xharbour - есть нормальная дока от 2007 года 2. harbour 3.0 - наконец то появился, надеюсь правильный и полный список функций... хотя материалов для "быстрого старта" окромя описалова Кресина от 2002 года (устарело однако) НЕТ 3. по miniGUI какие-то доки появились "на днях"... что же может быть и стоит уже "поиграться" 4. LetoDB в readme есть упоминания о каких-то функциях.... Обалденно богатая и полезная библиотека? Но спасибо и на этом... опираясь на базовые знания клиппера хоть что-то можно понять. P.S. http://www.whosaway.com/ у меня IE пишет о проблемах подключения... и раньше не хотел его открывать

Dima: AndreyZh пишет: http://www.whosaway.com/ Андрей сайт спокойно открывается в Мозилла и в Opera. Если надо я могу перелить доку на files.mail.ru , мне не сложно. PS IE8 спокойно открыл сайт

AlexMyr: AndreyZh Есть и другой вариант - взять платный продукт для разработки и балдеть от того что там все есть, включая саппорт AndreyZh пишет: 2. harbour 3.0 - наконец то появился, надеюсь правильный и полный список функций... хотя материалов для "быстрого старта" окромя описалова Кресина от 2002 года (устарело однако) НЕТ а что конкретно интересует по старту?

AndreyZh: Dima пишет: Андрей сайт спокойно открывается в Мозилла и в Opera. Если надо я могу перелить доку на files.mail.ru , мне не сложно Буду благодарен... и не обращайте внимание на уставшего и недовольного сегодняшним днём человека

AndreyZh: AlexMyr пишет: Есть и другой вариант - взять платный продукт для разработки и балдеть от того что там все есть, включая саппорт А Вы уважаемый! - не передёргивайте... Например Lazarus, впрочем и другие популярные системы разработок (PHP, C++, ...) имеет большой набор литературы, да если поискать на сайтах разработчиков библиотек Harbour то же многое можно накопать!

Dima: AndreyZh Держи http://files.mail.ru/RSTCM6

AndreyZh: Dima пишет: Держи http://files.mail.ru/RSTCM6 Спасибо - скачал

AlexMyr: AndreyZh пишет: А Вы уважаемый! - не передёргивайте... Например Lazarus, впрочем и другие популярные системы разработок (PHP, C++, ...) имеет большой набор литературы, да если поискать на сайтах разработчиков библиотек Harbour то же многое можно накопать! Спокойно! Вот видите Вы уже многое и накопали! Так что там про старт Вас интересует?

AndreyZh: AlexMyr пишет: Так что там про старт Вас интересует? Доброе утро! Не ответить - наверное неприлично, хотя уже мало интересно... А для пользы, если есть на русском яыке интересно бы было изучить: 1. Harbour 3. Сборка программы, работа с hbmk 2. Список функций и пример для начинающего по LetoDB 3.... По остальному... Надо посмотреть руквоводство любезно данное Dima.

AlexMyr: AndreyZh пишет: 1. Harbour 3. Сборка программы, работа с hbmk Для начала hbmk2 -help Допустим у вас проект из двух файлов p1.prg, p2.prg, создадим pr1.hbp //begin pr1.hbp p1 p2 //end pr1.hbp Собираем: hbmk2 pr1.hbp Если нужно дополнительно подключить библиотеку, тогда //begin pr1.hbp -l<namelib1> -l<namelib2> p1 p2 //end pr1.hbp Больше примеров на SVN\contrib AndreyZh пишет: 2. Список функций и пример для начинающего по LetoDB Изучаем readme.txt и readme_rus.txt, примеры в в letodb/tests

Dima: Вроде не было в этой теме [pre2] set fixed on SET DECIMALS TO 15 ? 33724.30+6120.30 // 39844.600000000010000 [/pre2] Откуда взялась 1 в 11 знаке после запятой ? Ведь не множим , не делим...

AndreyZh: Что по этому примеру, что http://clipper.borda.ru/?1-4-0-00001174-000-0-0-1486729322 на xHarbour при использовании любых функция преобразования чисел к строке получается идентичные результаты... осталось проверить "прародителя" - проверить это на чистом С

AndreyZh: Вдогонку... на VFP 9 так же сложение даёт хвост, но Int там работает, на этом примере правильно

Петр: AndreyZh пишет: осталось проверить "прародителя" - проверить это на чистом С Так вроде ж прародитель Clipper bcc55 #include <stdio.h> [pre2]int main () { double a = 33724.30; double b = 6120.30; printf( "result = %.15f\n", a + b ); printf( "result = %.15f\n", a - b ); return( 0 ); }[/pre2] Вывод result = 39844.600000000005820 result = 27604.000000000003640 PellesC 8.0 result = 39844.600000000005821 result = 27604.000000000003638

Dima: AndreyZh пишет: но Int там работает, на этом примере правильно А что покажет Foxpro на такой пример ? [pre2] local n := (3.14 ^ 3.14 ^ 3.14 ^ 3.14) / 0.002 ? n ? int(n) [/pre2] Harbour 1211955117675862000.00 1211955117675862528

AndreyZh: Просто есть fox под руками - вот и проверил. Win 10/64

Петр: [pre2]PROCEDURE main() LOCAL n := (3.14 ^ 3.14 ^ 3.14 ^ 3.14) / 0.002 ? n ? Int( n ) SET FIXED ON SET DECIMALS TO 15 ? 33724.30+6120.30 // 39844.600000000010000 RETURN C:\ALASKA\XPPW32\bin>pbuild.bat test_f.prg Xbase++ (R) Compiler 1.90.331 Apr 27 2006 Copyright (c) Alaska Software. All rights reserved. File: C:\ALASKA\XPPW32\bin\test_f.prg Line: 13 File C:\ALASKA\XPPW32\bin\test_f.prg successfully compiled. Alaska 32-Bit Linker Version 1.90.331 Copyright (c) Alaska Software 1997-2006. All rights reserved. 1211955117675862000,00 1211955117675862000 39844,600000000010000[/pre2]

Dima: Петр пишет: 39844,600000000010000 А Excel считает без "хвоста"

Петр: У всех свои правила - вот знать бы их Но harbour, xharbour, xbase++ и, думаю, clipper пользуются одним и тем же правилом.

Dima: Петр Да в Clipper такой же результат (проверил)

Pasha: Петр пишет: У всех свои правила - вот знать бы их Но harbour, xharbour, xbase++ и, думаю, clipper пользуются одним и тем же правилом. Все эти операции выполняет одно и то же устройство - FPU, и думается, выполняет одинаково. Не забывайте, что числа хранятся в двоичном представлении, то есть с базой 2. Отображаются они в привычном для нас десятичном формате. Для преобразования числа в строковое представление с базой 10 необходимо выполнить массу арифметических операций: в основном это операции вычитания и умножения или деления на 10. Эти операции во-первых могут выполняться по разному и в разной последовательности, во вторых каждая такая операция тоже дает некоторую погрешность, обычную для операций fpu. Отсюда получается различный результат для разных компиляторов и программных комплексов.

Pasha: Вот сам нарвался на ситуацию: Есть простое суммирование поля с размерностью N, 12, 2. Суммируется около 2 тыс значений В итоге получается результат: 6947703.00000001 Набегает погрешность 10 нанорублей, или 1 микрокопейка Я бы и не заметил такую погрешность, но результат передается в Excel, а там в строке ввода погрешность видно. Пользователи нервничают, ну как обычно

rvu: Pasha пишет: В итоге получается результат: 6947703.00000001 Набегает погрешность 10 нанорублей, или 1 микрокопейка Я еще когда на клиппере писал, стал в таких случаях писать округление до копейки для каждого числа, которые после округления суммировал. По логике это округление не нужно, но приходилось, чтобы таких ошибок не было.

Dima: Pasha пишет: Есть простое суммирование поля с размерностью N, 12, 2. Суммируется около 2 тыс значений Тут вопрос возникает. Округлять результат операции суммирования для всех 2 тыс значений или только конечную цифру ?

Pasha: Достаточно конечную цифру, я так и делаю

Dima: Pasha пишет: Достаточно конечную цифру, я так и делаю А если складывать вот так ? [pre2] X+= Base->KLV * Base->CENA , где KLV , "N" ,10,3 а CENA , "N" ,10,2 [/pre2]

Pasha: здесь конечно требуется промежуточное округление, иначе погрешность в случае дробного количества будет достигать до полкопейки

rvu: Я сейчас уже не помню, что у меня было, но были примеры где промежуточное округление и итоговое разные значения давали. Очевидно, что ошибка была не в 0,00....001, а большая и они накапливались.

Pasha: round(1/3+1/3+1/3, 2) --> 1.00 round(1/3, 2)+round(1/3, 2)+round(1/3, 2) --> 0.99

rvu: Все округления могут быть полезны, лучше все и делать.

Pasha: Я обычно обхожусь без округления Сделал такую функцию, для сравнения чисел с точностью до двух десятичных знаков: [pre] #include "hbapi.h" #include "math.h" HB_FUNC( EQU ) { double d1 = hb_parnd( 1 ); if( HB_ISNUM( 2 ) ) { double d2 = hb_parnd( 2 ); hb_retl( fabs( d1 - d2 ) < 0.005 ); } else hb_retl( fabs( d1 ) < 0.005 ); } [/pre] вместо nSum1 == nSum2 или подобное использую Equ(nSum1, nSum2)

Pasha: Если скинуть в Excel достаточно большой заполненный dbf-файл, порядка 10 тыс.записей, с числовым полем размерностью N,12, 2 и затем с произвольной строки помечать числовую колонку, то начиная примерно с пометки 1500-2000 строк обязательно возникает погрешность суммы (которую видно внизу Excel) в 8-м знаке в ту или другую сторону, та же микрокопейка Если продолжать помечать колонку дальше, то при пометке 3-4 тыс строк погрешность может аннигилироваться. Забавно Эффект лучше наблюдать в LibreOffice. Погрешность суммирования то появляется, то исчезает

rvu: Pasha пишет: использую Equ(nSum1, nSum2) А я вставил округление до копейки в функцию и где считал нужным писал valround(значение).

SergKis: rvu пишет где считал нужным писал valround(значение) Помогает исп. рабочих полей в dbf "N", 19, <все нужные варианты>, т.е через них расчеты. Т.к. клиент сам ставит варианты nDec для разных групп номенклатуры (2, 3, 4, 5, 7), то привязывал имя раб. поля к номенклатуре (picture тоже если надо), работает вариант со времен S87

Pasha: Просто крик души Сдаем отчет РСВ-1 в ФНС Получаем протокол: 0400400013-СНИЛС XXX-XXX-XXX XX ст.170 (2 м.) = 8873.77 Расчетная сумма = (ст.150 поп + ст.150 (1 мес. + 2 мес.)) * тариф - ст.170 поп - ст.170 (1 мес.) = 150678.66 * 30/100 - 36329.82=8873.79 разница = -.02 V не принимается. II. По основаниям, предусмотренным пунктом 7 статьи 431 Налогового кодекса Российской Федерации: 0400400011-Нарушено условие равенства значения суммы страховых взносов по плательщику страховых взносов совокупной сумме страховых взносов по застрахованным лицам конец протокола проверяю на калькуляторе: 150678.66 * 30/100 - 36329.82 = 8873.78 и там дальше 4 такие же ошибки ФНС, если кто не знает, это Федеральная Налоговая Служба Российской Федерации Риторический вопрос: как научить ФНС арифметике ?



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