Автор | Сообщение |
|
| |
Пост N: 166
Зарегистрирован: 12.11.06
|
|
Отправлено: 07.11.10 10:24. Заголовок: Волшебные числа и операции
Доброе утро! Вот наткнулся на очередную ошибку 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
[только новые]
|
|
|
| постоянный участник
|
Пост N: 991
Зарегистрирован: 09.10.06
|
|
Отправлено: 07.11.10 13:10. Заголовок: AndreyZh пишет: Вот..
AndreyZh пишет: цитата: | Вот наткнулся на очередную ошибку xHarbour и Clipper. Думал, что глюк ОС или ПК, но нет. |
| #include <stdio.h> #include <math.h> 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; } Протестируйте с любым доступным вам С компилятором. У меня 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 proc main() local i, n n := 1 for i:=1 to 100000 n*=2 next ? n return
|
|
|
|
| |
Пост N: 167
Зарегистрирован: 12.11.06
|
|
Отправлено: 07.11.10 13:40. Заголовок: Петр - спасибо! Хотя..
Петр - спасибо! Хотя и не успокоили... Запустил поиск и уменя в программе операция (%) более 1000 раз, ну алгоритмы такие размножал... Как можно попытаться порешать эти проблемки? По проверке на других компиляторах - мне доступны и проверил на C#/VFP5 ошибок не получил! А пример кода "роняющего" программу сейчас проверю - очень интересно!
|
|
|
|
| |
Пост N: 168
Зарегистрирован: 12.11.06
|
|
Отправлено: 07.11.10 13:56. Заголовок: Действительно роняет..
Действительно роняет! Но мне проще - мои финансовые программы не работают с такими размерностями
|
|
|
|
| постоянный участник
|
Пост N: 994
Зарегистрирован: 09.10.06
|
|
Отправлено: 07.11.10 23:02. Заголовок: AndreyZh пишет: опе..
AndreyZh пишет: цитата: | операция (%) более 1000 раз, ну алгоритмы такие размножал... Как можно попытаться порешать эти проблемки? По проверке на других компиляторах - мне доступны и проверил на C#/VFP5 ошибок не получил! |
| Перестаньте вы называть эту особенность ошибкой. Операция взятия остатка в различных языках программирования реализованы по разному. И поэтому некорректно сравнивать результаты Clipper ([x]Harbour) из семейства xBase c C#. Clipper и [x]Harbour позволяют получить одни и те же результаты - и это главное. [x]Harbour унаследовал все ошибки функции Mod() и оператора % от Clipper и это документированная особенность. Не знаю, что вы хотели бы увидеть, но мне кажется, что что-то типа #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 Вот в этом направлении и двигайтесь.
|
|
|
|
| |
Пост N: 169
Зарегистрирован: 12.11.06
|
|
Отправлено: 08.11.10 10:51. Заголовок: Спасибо! - Это идея,..
Спасибо! - Это идея, но разве на Clipper могу переопределить оператор (%)?
|
|
|
|
| постоянный участник
|
Пост N: 995
Зарегистрирован: 09.10.06
|
|
Отправлено: 08.11.10 13:11. Заголовок: Во-первых, вы попроб..
Во-первых, вы попробуйте, за #xtranslate <xExp1> % <xExp2> => fMod( <xExp1>, <xExp2> ) отвечает препроцессор, Clipper ни о чем и не догадывается, что ему собираются подсунуть. Во вторых с помощью какого-то gsar, sed или других утилит сделать 1000 замен, что раз плюнуть. В третьих я же вам не предложил ASSOCIATE CLASS ... OPERATOR "%" ... и т.п.
|
|
|
|
| |
Пост N: 170
Зарегистрирован: 12.11.06
|
|
Отправлено: 08.11.10 16:29. Заголовок: Спасибо... Этой же е..
Спасибо... Этой же ерундой уже занимаюсь! Увы % это не только знак "операции", но и обозначения "процента", использующегося в бизнесе. Да'с сколько еще открытий чудных меня ожидает?
|
|
|
|
| |
Пост N: 197
Зарегистрирован: 12.11.06
|
|
Отправлено: 22.01.11 14:11. Заголовок: 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 - как то быстро разобрался
|
|
|
|
| Администратор
|
Пост N: 1805
Зарегистрирован: 23.05.05
|
|
Отправлено: 22.01.11 14:57. Заголовок: AndreyZh пишет: Фун..
AndreyZh пишет: цитата: | Функция IndexExp() - расширение индексного файла рабочей области в Clipper возвращает ".NTX", а в xHarbour ".ntx" |
| У меня сохранились сырцы Харбора версии 0.39 от 2002 года, и там уже IndexExt() был на нижнем регистре. Почему ? Я могу только сказать, что так сложилось исторически. Возможно, разработчики ориентировались на *nix, где принято использовать нижний регистр.
|
|
|
|
| постоянный участник
|
Пост N: 1642
Зарегистрирован: 12.09.06
|
|
Отправлено: 22.01.11 17:04. Заголовок: AndreyZh пишет: В x..
|
|
|
|
| |
Пост N: 199
Зарегистрирован: 12.11.06
|
|
Отправлено: 22.01.11 18:54. Заголовок: Andrey пишет: Польз..
|
|
|
|
|
| Администратор
|
Пост N: 1807
Зарегистрирован: 23.05.05
|
|
Отправлено: 22.01.11 22:45. Заголовок: Здесь необходимо исп..
Здесь необходимо использовать другой подход. Если Вы нашли какую-то несовместимость, которую считаете существенной, то приймите меры, чтобы ее устранить. Устранить можно либо самому, передав фикс разработчикам, либо долбать разработчиков, чтобы это кто-то сделал. И клевать надо не здесь, а непосредственно в майл-листе харбора. Здесь конечно тоже есть разработчики, но очень мало. Мне, к примеру, эта несовместимость по IndexExt совершенно неинтересна. Более того, поскольку я уже много лет программирую не на клиппере, а на харборе, ориентируюсь на нижний регистр. И мне устранение этой несовместимости помешает. Устранить ее - раз плюнуть. Надо в include/hbrddntx.h заменить строку-литерал. Если считаете, что это необходимо - доказывайте это, но не здесь, а в специально предназначенном для этого месте. Не ждите, что это кто-то сделает за Вас. Будьте сами кузнецом своего счастья. Если здесь не помогли, то этим форумом мир харбора не ограничивается. Я, кстати, так и поступал с обнаруженными мной когда-то несовместимостями.
|
|
|
|
| |
Пост N: 208
Зарегистрирован: 12.11.06
|
|
Отправлено: 22.09.11 17:58. Заголовок: Pasha пишет: Здесь ..
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
|
|
|
|
| Администратор
|
Пост N: 2066
Зарегистрирован: 23.05.05
|
|
Отправлено: 22.09.11 22:37. Заголовок: В который раз толчем..
В который раз толчем воду в ступе Согласно стандарту 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 двойной точности. Опять что-то непонятно ?
|
|
|
|
| Администратор
|
Пост N: 2067
Зарегистрирован: 23.05.05
|
|
Отправлено: 22.09.11 23:26. Заголовок: Чтобы было совсем уж..
Чтобы было совсем уж понятно, перепишем немного функцию 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
|
|
|
|
| Администратор
|
Пост N: 2068
Зарегистрирован: 23.05.05
|
|
Отправлено: 23.09.11 08:31. Заголовок: AndreyZh пишет: ещё..
AndreyZh пишет: цитата: | ещё один крайне серьёзный, непонятный глюк xHarbour (или BCC) (в clipper такой ошибки нет). |
| Чтобы не возвращатся к этой якобы ошибке, или якобы глюку, замечу. что клиппер делает вычисления точно так же. Т.е., эта т.н. "ошибка" есть и в клиппере. Еще бы ее не было, ведь вычисления делает не клиппер, и не харбор, а fpu Думаю, что такая же "ошибка" присутствует и в Delphi, и в любом компиляторе, который выполняет вычисления с числами double
|
|
|
|
| |
Пост N: 209
Зарегистрирован: 12.11.06
|
|
Отправлено: 23.09.11 09:30. Заголовок: Спасибо Pasha за ооо..
Спасибо 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#
|
|
|
|
| Администратор
|
Пост N: 2069
Зарегистрирован: 23.05.05
|
|
Отправлено: 23.09.11 10:14. Заголовок: AndreyZh пишет: 5. ..
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. В харборе - тоже самое
|
|
|
|
| Администратор
|
Пост N: 2070
Зарегистрирован: 23.05.05
|
|
Отправлено: 23.09.11 10:23. Заголовок: AndreyZh пишет: Поп..
AndreyZh пишет: цитата: | Попытаюсь дать Ваше подробное пояснение этой "гориле-безопастнику" - посмотрю на его реакцию |
| Мнээ.. не советую. Сьедят (с) Понедельник начинается в субботу Лучше слелайте в своих программах проверку на ноль не простым сравнением, а через Round(n1, 2) Я так сделал еще в те далекие времена, когда небо было голубее, трава зеленее, и первый раз попался в клиппере на такую особенность вычислений с double
|
|
|
|
| |
Пост N: 210
Зарегистрирован: 12.11.06
|
|
Отправлено: 23.09.11 10:57. Заголовок: Pasha пишет: Лучше ..
Pasha пишет: цитата: | Лучше слелайте в своих программах проверку на ноль не простым сравнением, а через Round(n1, 2) Я так сделал еще в те далекие времена, когда небо было голубее, трава зеленее, и первый раз попался в клиппере на такую особенность вычислений с double |
| Конечно так уже сделал! - "А что делать?"
|
|
|
Ответов - 150
, стр:
1
2
3
4
5
6
7
8
All
[только новые]
|
|