On-line: гостей 0. Всего: 0 [подробнее..]
АвторСообщение





Пост N: 7
Зарегистрирован: 01.01.10
ссылка на сообщение  Отправлено: 02.01.10 01:12. Заголовок: Что бы это значило и как с этим бороться?


// Программа
LOCAL n10 := 10, n3 := 3, n10div3, i
n10div3 := (n10 / n3)
FOR i := 1 TO n3
n10 := n10 - n10div3
NEXT
? n10
IF n10 == 0
? "ноль"
ELSE
? "не ноль"
ENDIF
?
// Результат
0.00
не ноль


Спасибо: 0 
ПрофильЦитата Ответить
Ответов - 29 , стр: 1 2 All [только новые]


постоянный участник




Пост N: 1018
Зарегистрирован: 12.09.06
ссылка на сообщение  Отправлено: 02.01.10 12:10. Заголовок: sergey5703 пишет: I..


sergey5703 пишет:

 цитата:
IF n10 == 0



Попробуй IF n10 == 0.0

Спасибо: 1 
ПрофильЦитата Ответить





Пост N: 9
Зарегистрирован: 01.01.10
ссылка на сообщение  Отправлено: 02.01.10 21:15. Заголовок: Andrey пишет: Попро..


Andrey пишет:

 цитата:
Попробуй IF n10 == 0.0


Попробовал - результат не изменился!


Спасибо: 0 
ПрофильЦитата Ответить
Администратор




Пост N: 1275
Зарегистрирован: 23.05.05
ссылка на сообщение  Отправлено: 03.01.10 00:21. Заголовок: Это результат исполь..


Это результат использования арифметики с числами double
Ничего с этим не поделаешь, точность представления double ограничена.
Такой же результат даст программка на С:

HB_FUNC( N10_3 )
{
hb_retl((10.0-10.0/3.0-10.0/3.0-10.0/3.0) == 0.0);
}

Вызов N10_3 даст .F.
так работает FPU

А лечение традиционное: вместо сравнения с нулем написать функцию:

Function Equ(n1, n2)
Return Abs(n1-n2) < 0.0001

точность сравнения подобрать самому по вкусу


Спасибо: 1 
ПрофильЦитата Ответить





Пост N: 11
Зарегистрирован: 01.01.10
ссылка на сообщение  Отправлено: 03.01.10 00:59. Заголовок: Вы абсолютно правы -..


Вы абсолютно правы - все дело в арифметике с плавающей точкой. Вы уж извините старого чудака - решил задать "вопрос на засыпку", хотя ответ на него я лично узнал после нескольких лет программирования на Клиппере, когда программировал задачу по распределению чего-то там на три декады месяца. В этой задаче печатался отчет и я чтобы не засорять отчет нулями вставил проверку на ноль и тогда печатал пробелы. Каково же было мое удивление когда отчет все равно печатался с нулями и что самое смешное и в отладчике тоже значение переменной - ноль, а в программе ветвление идет на "не равно нулю". Хотя должен все таки похвалить писишную арифметику и особенно арифметику с плавающей точкой в Клиппере - я знавал дипломированных программистов для которых было откровением узнать, что арифметика с плавающей точкой НЕ ТОЧНА "по определению". А решение этой проблемы простое - как мычание, мы в нашей организации после делений или умножений (с сложением и вычитанием все нормально) просто писали:
n10 := VAL(STR(n10)) и ВСЕ, и больше ничего не надо - теперь НОЛЬ!


Спасибо: 0 
ПрофильЦитата Ответить
Администратор




Пост N: 1276
Зарегистрирован: 23.05.05
ссылка на сообщение  Отправлено: 03.01.10 10:27. Заголовок: :)..


:)

Спасибо: 1 
ПрофильЦитата Ответить



Не зарегистрирован
Зарегистрирован: 01.01.70
ссылка на сообщение  Отправлено: 03.01.10 18:15. Заголовок: "вопрос на засыпку"


Можете попробовать для "простого решения VAL(str()) " 378.70*0.75-284.03 ?

Спасибо: 1 
Цитата Ответить





Пост N: 13
Зарегистрирован: 01.01.10
ссылка на сообщение  Отправлено: 03.01.10 22:28. Заголовок: Можете попробовать


// Программа
LOCAL n10 := (378.70 * 0.75) - 284.03
? n10
IF n10 == 0
? "ноль"
ELSE
? "не ноль"
ENDIF
?
// Результат
-0.0050
не ноль
// Вывод - все нормально, никакого "решения" - ни "простого" ни "сложного" не требуется, потому что выводится не ноль и условие проверки выдают "не ноль". Вы вероятно "не просекли" "фишку" - вопрос был в том, что выводился ноль, а для сравнения был не ноль.


Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 16
Зарегистрирован: 01.01.10
ссылка на сообщение  Отправлено: 04.01.10 01:05. Заголовок: Попробовал вычислить "эпсилон"


// Вычисление эпсилон
LOCAL n10 := 10, nEpsilon := 1, nOldEpsilon
nEpsilon := (nEpsilon / n10)
nOldEpsilon := nEpsilon
DO WHILE (nEpsilon == VAL(STR(nEpsilon)))
nOldEpsilon := nEpsilon
nEpsilon := (nEpsilon / n10)
ENDDO
? "Epsilon = " + ALLTRIM(STR(nOldEpsilon))
?
// Результат
Epsilon = 0.01

Получается что 0.001 - выводится как 0.00, а -0.005 как -0.0050? Загадка, однако ...


Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 17
Зарегистрирован: 01.01.10
ссылка на сообщение  Отправлено: 04.01.10 01:58. Заголовок: Хорошая мысля - приходит опосля ...


// Вычисление эпсилон
LOCAL n10 := 10, nEpsilon := -5, nOldEpsilon
nEpsilon := (nEpsilon / n10)
nOldEpsilon := nEpsilon
DO WHILE (nEpsilon == VAL(STR(nEpsilon)))
nOldEpsilon := nEpsilon
nEpsilon := (nEpsilon / n10)
ENDDO
? "Epsilon = " + ALLTRIM(STR(nOldEpsilon))
?
// Результат
Epsilon = -0.05

Получается - никакой загадки, просто в Вашей формуле отсутствует ДЕЛЕНИЕ - в этом вся "фишка" ...

Как там у А.С.Пушкина - "О сколько нам открытий чудных готовит просвещенья дух ..."


Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 19
Зарегистрирован: 01.01.10
ссылка на сообщение  Отправлено: 04.01.10 02:49. Заголовок: Две тестовых программы с ДЕЛЕНИЯМИ


// Программа 1
LOCAL n10 := 10, nm5 := -5
nm5 := (nm5 / n10)
nm5 := (nm5 / n10)
nm5 := (nm5 / n10)
? nm5
IF nm5 == 0.0
? "ноль"
ELSE
? "не ноль"
ENDIF
?
// Результат
-0.01
не ноль
// Программа 2
LOCAL n10 := 10, nm5 := -4
nm5 := (nm5 / n10)
nm5 := (nm5 / n10)
nm5 := (nm5 / n10)
? nm5
IF nm5 == 0.0
? "ноль"
ELSE
? "не ноль"
ENDIF
?
// Результат
0.00
не ноль


Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 79
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 09.01.10 20:56. Заголовок: Аффтар, вместо того,..


Аффтар, вместо того, чтобы выносить мозг себе и людям, замени строчку

? nm5

на

? STR(nm5,20,10)

и все встанет на свои места.

Спасибо: 1 
ПрофильЦитата Ответить



Пост N: 52
Зарегистрирован: 10.07.07
ссылка на сообщение  Отправлено: 10.01.10 13:30. Заголовок: Присоединюсь к Sergy..


Присоединюсь к Sergy.
Хочу только немного уточнить.
Приведенный выше алгоритм вычисления epsilon несколько озадачил. Вообще говоря, в серьезных математических вычислениях рекомендуют вычислять так называемый epsilon по следующему алгоритму
nEpsilon := 1.0 
DO WHILE ( 1.0 + nEpsilon > 1.0 )
nOldEpsilon := nEpsilon
nEpsilon := nEpsilon / 2
? nI, ",", nEpsilon
ENDDO


nOldEpsilon как раз то, что нам нужно. И несмотря на то, что оператор
? nEpsilon

начиная с 31 итерации будет выдавать 0.000000000 цикл продолжится и все-таки закончится. Причем итераций будет проделано 53. Поскольку деление было на 2, то это означает, что на мантиссу числа выделено примерно 7 байтов, что в свою очередь соответствует 16 значащим разрядам после запятой для чисел из интервала [-1,1]. Таким образом, во всех приведенных выше якобы курьёзах заменить в операторе "? <переменная>" на "? STR( <переменная>, 19, 16 )" и все встанет на свои места.

sergey5703 пишет:

 цитата:
(с сложением и вычитанием все нормально)


И здесь немного неточно. Как раз таки с вычитанием не все нормально. Именно при вычитаниях может возникнуть значительная потеря точности. Ваша первая программа тому подтверждение. Если правильно поставить печать то, n10 будет равно -0.0000000000000009.
Я не поленился и провёл аналогичные расчеты на С (компилятор Borland C 5.5) и на Pascal (компилятор Borland Pascal 7.0).
Вот что получилось для первого примера с вычитаниями.
На Pascal описал все переменные как double и тогда оператор writeln( n10 ) выдал
-8.8817841900125E-0016. Как нетрудно видеть соответствует полученному в Clipper.

А вот, на С с так же описанными переменными оператор
printf( "%f", n10 ) выдает 0.000000, но
printf( "19.16%f", n10 )
выдает результат точно такой же как в Clipper программе. Теперь, мне кажется, стало более понятно откуда у оператора "?" уши растут.
Кстати, в [x]Harbour расчеты такие же как в Clipper-е.

Итак, это означает, что в Clipper/[x]Harbour все числовые переменные представляют собой числа типа Double соответствующего С-компилятора и бороться с этим не имеет смысла. Для правильности расчетов надо это учитывать.


Спасибо: 1 
ПрофильЦитата Ответить
постоянный участник


Пост N: 783
Зарегистрирован: 09.10.06
ссылка на сообщение  Отправлено: 10.01.10 16:43. Заголовок: TimTim пишет: Таким..


TimTim пишет:

 цитата:
Таким образом, во всех приведенных выше якобы курьёзах заменить в операторе "? <переменная>" на "? STR( <переменная>, 19, 16 )" и все встанет на свои места.


Я думаю, тут все в пылу дискусии забыли о кoманде SET DECIMALS TO nDecimal и ее влиянии на вывод на экран. Позволю себе напомнить, что по умолчанию nDecimal = 2

и все встанет на свои места

Спасибо: 1 
ПрофильЦитата Ответить
постоянный участник




Пост N: 1035
Зарегистрирован: 12.09.06
ссылка на сообщение  Отправлено: 10.01.10 17:50. Заголовок: Петр пишет: о кoман..


Петр пишет:

 цитата:
о кoманде SET DECIMALS TO nDecimal



Точно, Петр ! Я сам хотел об этом написать ...

Спасибо: 1 
ПрофильЦитата Ответить



Пост N: 53
Зарегистрирован: 10.07.07
ссылка на сообщение  Отправлено: 10.01.10 18:53. Заголовок: Безусловно, Петр, дл..


Безусловно, Петр, для выдачи на экран можно и так.
Но параметр nDecimal равный именно 16 ставит все на свои места.

Спасибо: 1 
ПрофильЦитата Ответить





Пост N: 36
Зарегистрирован: 01.01.10
ссылка на сообщение  Отправлено: 11.01.10 02:38. Заголовок: Спасибо большое госп..


Спасибо большое господа, что высказали свое мнение. Все абсолютно правы, вот только в РЕАЛЬНОЙ программистской работе не всегда есть время задуматься над тем, какие числа в программе получатся, тем более при подсчете рублей.копеек. Так что в нашей организации не я один вставлял в "подозрительных" местах программы конструкцию: var := VAL(STR(var)) - лучше заранее "соломки" подстелить!


Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 80
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 14.01.10 23:52. Заголовок: sergey5703 пишет: т..


sergey5703 пишет:

 цитата:
только в РЕАЛЬНОЙ программистской работе не всегда есть время задуматься над тем, какие числа в программе получатся, тем более при подсчете рублей.копеек. Так что в нашей организации не я один вставлял в "подозрительных" местах программы конструкцию: var := VAL(STR(var)) - лучше заранее "соломки" подстелить!


Не рекомендую категорически.
Иначе при элементарном подсчете суммы накладной, если используется НДС, курс валют с точностью более одного знака после запятой, либо дробные части количества (кг, тонн и тп) - сумма не сойдется НИКОГДА.

Спасибо: 0 
ПрофильЦитата Ответить



Пост N: 68
Зарегистрирован: 29.07.05
ссылка на сообщение  Отправлено: 15.01.10 09:14. Заголовок: Sergy пишет: Не рек..


Sergy пишет:

 цитата:
Не рекомендую категорически.


это понятно
при таком ответе должна быть рекомендуемая стратегия

Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 81
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 17.01.10 00:33. Заголовок: les пишет: при тако..


les пишет:

 цитата:
при таком ответе должна быть рекомендуемая стратегия



1) задуматься над тем, как, когда и какие числа в программе получаются
2) никогда не использовать усечение, тем более такое, как x:=VAL(STR(x))
3) всегда использовать максимально возможную точность в таблицах, 3 минимум, а лучше 4-5 знаков после запятой (для руб/коп)
4) выводить результаты усечения в документах в полях "сумма", "итого" и тп - только после того, как с макс. точностью просчитан столбец или строка.

вроде как прописные истины...

Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост N: 132
Зарегистрирован: 24.09.05
ссылка на сообщение  Отправлено: 13.02.10 19:04. Заголовок: сто раз обсуждали)) ..


сто раз обсуждали))

?0.3-(0.1+0.2)

-0.000000000000000055511151231258

Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост N: 133
Зарегистрирован: 24.09.05
ссылка на сообщение  Отправлено: 13.02.10 19:13. Заголовок: Sergy пишет: 2) ник..


Sergy пишет:

 цитата:
2) никогда не использовать усечение



усечение, а именно, округление промежуточных результатов - обязательная вещь
привожу пример

суммируются N числовых полей с 2мя знаками после запятой
на каждом шаге необходимо округлять результат до 2го знака
иначе накопится ошибка в сумме

Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост N: 134
Зарегистрирован: 24.09.05
ссылка на сообщение  Отправлено: 13.02.10 19:16. Заголовок: Sergy пишет: 4) выв..


Sergy пишет:

 цитата:
4) выводить результаты усечения в документах в полях "сумма", "итого" и тп - только после того, как с макс. точностью просчитан столбец или строка.



учитывая вышесказанное, п.4 неверен

Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост N: 135
Зарегистрирован: 24.09.05
ссылка на сообщение  Отправлено: 13.02.10 19:39. Заголовок: Sergy пишет: 3) все..


Sergy пишет:

 цитата:
3) всегда использовать максимально возможную точность в таблицах, 3 минимум, а лучше 4-5 знаков после запятой (для руб/коп)



а почему не 10? )))
я могу за тебя ответить. потому если не применяются правильные алгоритмы, то как недостаточная точность, так и избыточная точность приводит тем или иным проблемам.

в общем, этот пункт тоже неверен. Копейки прекрасно умещаются в 2 знака, если речь идет о стоимости. И ДОЛЖНЫ умещаться в 2 знака, ибо таковы реалии бухучета. Вряд ли тебя поймут в налоговой, если ты с жаром будешь доказывать, что продал 1шт изделия за 3рубля 33.33333333333333 копейки, потому что ты их покупал 3 штуки за 10 рублей.

В данном случае 1е изделие продается за 3.33, второе за 3.34, третье - за 3.33

имеем 3 шт за 10.00
продаем 1шт за RoundTo(10/3,2) == (3.33)
остается 2шт и стоят они 10-3.33==6.67
второе изделие при продаже будет стоить RoundTo(6.67/2,2) == 3.335==3.34 (при округлении 5 к четному, равно как и при округлении 5 к большему)
и останется одно изделие со стоимостью 3.33, которое прекрасно продастся и останется ровно НОЛЬ на суммовом остатке.

А избыточная точность может например привести к тому, что на остатке будет числится 0.000001 изделия (одна миллионная штуки вместо нуля) со стоимостью -0.000000001 руб (минус одна миллиардная рубля) и средней стоимостью МИНУС тысяча рублей за штуку, что приведет к хрен знает к чему, чаще всего к коллапсу системы.

Надо просто применять правильные алгоритмы.

Спасибо: 0 
ПрофильЦитата Ответить



Пост N: 69
Зарегистрирован: 29.07.05
ссылка на сообщение  Отправлено: 16.02.10 09:39. Заголовок: suv2 пишет: имеем 3..


suv2 пишет:

 цитата:
имеем 3 шт за 10.00


обычно в накладной есть колонки "цена", "количество", "сумма".
как тут получить 3 шт за 10.00

suv2 пишет:

 цитата:
Надо просто применять правильные алгоритмы.


согласен!

Вот в Excell 2003 есть такая фишка:
Сервис->Параметры->Параметры книги->Точность как на экране.
Бухам нравится



Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост N: 136
Зарегистрирован: 24.09.05
ссылка на сообщение  Отправлено: 18.02.10 13:37. Заголовок: les пишет: обычно в..


les пишет:

 цитата:
обычно в накладной есть колонки "цена", "количество", "сумма".
как тут получить 3 шт за 10.00



я в курсе, и цифры там двузначные причем.
и в чем вопрос?

Спасибо: 0 
ПрофильЦитата Ответить



Пост N: 70
Зарегистрирован: 29.07.05
ссылка на сообщение  Отправлено: 18.02.10 15:15. Заголовок: suv2 пишет: и в чем..


suv2 пишет:

 цитата:
и в чем вопрос?

какая цена 1 штуки?

Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост N: 137
Зарегистрирован: 24.09.05
ссылка на сообщение  Отправлено: 19.02.10 18:08. Заголовок: Допустим, речь о зак..


Допустим, речь о закупочной цене. Тебе их продавали как комплект, а ты его разукомплектовал и продаешь поштучо. Допустим, в Уставе прописан учет по средней. Цена одной штуки 3.333333333 (в таком виде закупочная цена будет хранится в таблице), но это вещь вспомогательная, потому что приоритетом является стоимость всех штук, она точнее по определению. В момент продажи лучше закупочная стоимость одной штуки вычисляется точно, округляется до 2х знаков и в таком виде попадает в расходный документ. На складе остается суммовой остаток 10руб за минуом округленного ухода - 6.67, средняя стоимость 1ш будет 3.335

Если речь о продажной цене, то неточностей обычно нет, потому что наценка идет от одной штуки с 2мя точно прописанными знаками. Тем не менее и там бывают случаи, когда из-за применение скидок, стоимость 1 штуки не укладывается точно в 2 знака. Ну и что, она округляется, приоритетом все равно является ИТОГО, а не ЦЕНА

Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 8
Зарегистрирован: 12.11.06
ссылка на сообщение  Отправлено: 22.02.10 11:24. Заголовок: Добрый день! В посл..


Добрый день!

В последний год часто начались встречаться глюки с "математикой", что заставило переделать множество старых механизмов работы с числами:

1. x:=0; (х==0) даёт .f.
Помогает. Empty(x)

2. много лет корректно работал механизм разделения количества на упаковки и штуки.
Упаковки u := Int(количество/фасовка); Штуки = количество - (u*фасовка)... Народ стал активно использовать дробные фасовки и стало получаться, например: Фасовка = 5.4 кг.
- количество 21.6 разбивает на 3 упаковки + 5.4 штуки, но
- количество 27 разбивает на 5 упаковок + 0 штук.

Пришлось сменить алгоритм на (помогло)
Упаковки Int((количество + 0.00000001)/фасовка); Штуки = Round(количество - (u*фасовка),6) // у меня точность количеств 6 знаков

3. Новая "засада" по вопросу цены/суммы отгрузки и соответственно точности:
цена 235.99 * количество 1.072 равно сумма 252.98128 при этом разные функции по разному могут округлять данное значение... Пока ограничился "предупреждением для user"..


Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост N: 138
Зарегистрирован: 24.09.05
ссылка на сообщение  Отправлено: 03.03.10 15:42. Заголовок: AndreyZh пишет: 1..


AndreyZh пишет:

 цитата:
1. x:=0; (х==0) даёт .f.


x == 0 даёт TRUE. что у тебя за странный клиппер?

AndreyZh пишет:

 цитата:
Упаковки u := Int(количество/фасовка);


Это совершенно неверная формула. Int возвращает то, что получилось при ОТБРАСЫВАНИИ дробной части числа!!!!!! Если у тебя в результате операции деления должно получится целое число 4, но в из-за математических неточностей получилось 3.99999999999999999, то результат Int будет ТРИ, а не 4. Правильная формула для упаковок u:=round(количество/фасовка,0)

Ну и кроме того, клиппер (паскаль, ассемблер, процессор) абсолютно точно делит 21.6 на 5.4 и дает РОВНО 4, без всяких там арифметических ошибок, абсолютно целое число (дамп: 00 00 00 00 00 00 10 40), так что наблюдаемые тобой факты опять не подтверждаются. Даже по потенциально неверной формуле Упаковки u := Int(количество/фасовка) мы получим 4 упаковки и ноль штук, а не 3 упаковки и 5.4 штук

AndreyZh пишет:

 цитата:
252.98128 при этом разные функции по разному могут округлять данное значение


господи, да о чем ты? что тут можно по-разному округлить?

Спасибо: 0 
ПрофильЦитата Ответить
Ответов - 29 , стр: 1 2 All [только новые]
Ответ:
1 2 3 4 5 6 7 8 9
большой шрифт малый шрифт надстрочный подстрочный заголовок большой заголовок видео с youtube.com картинка из интернета картинка с компьютера ссылка файл с компьютера русская клавиатура транслитератор  цитата  кавычки моноширинный шрифт моноширинный шрифт горизонтальная линия отступ точка LI бегущая строка оффтопик свернутый текст

показывать это сообщение только модераторам
не делать ссылки активными
Имя, пароль:      зарегистрироваться    
Тему читают:
- участник сейчас на форуме
- участник вне форума
Все даты в формате GMT  3 час. Хитов сегодня: 520
Права: смайлы да, картинки да, шрифты да, голосования нет
аватары да, автозамена ссылок вкл, премодерация откл, правка нет