Rambler's Top100
Форум: MS ACCESSVBVBA MS OfficeMS SQL server
Новые сообщения: 0000

Форум: MS ACCESS

Вопросы связанные с MS ACCESS

Обновить визитку
Участники «Online»
Все участники

 
 

Доброго времени суток, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Точность вычислений (кто знает помогите плз)
 
 автор: olegza   (18.05.2009 в 16:50)   личное сообщение
 
 

Столкнулся вот с такой проблемой практически на ровном месте.
В очёте - бланке накладной итоговая сумма считается по формуле: =CCur([Количество]*[ЦенаСндс]).
Так вот, для примера: при цене 120р и количестве 2647,2кг - итоговая сумма получается 317663,99р.
Почему?
Ведь должна быть 317664,00
Что-то не так с форматом исходных данных?
Подскажите, в какую сторону "рыть"???

  Ответить  
 
 автор: Анатолий (Киев)   (18.05.2009 в 17:59)   личное сообщение
 
 

Какой тип поля "Количество"? Похоже - Single (Одинарное с плавающей точкой), а это очень неточный числовой тип для дробных чисел. Если есть возможность - измените тип поля:
На Currecy (Денежный), если количество десятичных разрядов не превышает 4, или Decimal (Действительное), или (на худой конец) - Double (Двойное с плавающей точкой).
Проблема с точностью будет решена навсегда. Надеюсь, поле "ЦенаСндс" у вас денежное?

Дело в том, что если в формуле участвуют операнды различных типов - результат приводится к самому "грубому" типу. Вот пример в окне отладки:
?CCur(CSng(2647.2) * 120)
317663.9941

Это потому, что в реальности число 2647.2 типа Single хранится как:
?317663.9941 / 120
2647.19995083333

Вот правильные конструкции:
?CCur(CSng(2647.2)) * 120
317664
?CDec(CSng(2647.2)) * 120
317664

Т.е. преобразовывать к другому типу нужно не результат вычислений а самый неточный операнд.
Для вашей формулы это: =CCur([Количество])*[ЦенаСндс]

  Ответить  
 
 автор: osmor   (18.05.2009 в 18:02)   личное сообщение
 
 

цитата из FAQ fido7.ru.msaccess

1) Q1: Почему ошибочно считаются большие числа типа Currency в SQL?
Q2: Почему SELECT SUM (Single) выдает 27.2900012135506 вместо 27.29?
Q3: Почему Int & Fix для некоторых чисел неверно производят усечение?
Q4: Почему у меня получается 418.4 - 408.8 равным 9.59999999999997?
A: Все эти ошибки связаны с неверной (или вообще не проводимой) нормализацией чисел и преобразования типов в VB[A] и SQL. Следует учесть, что с Jet3.0 SQL реально использует лишь типы Long, Double и String. Byte, Boolean, Integer правильно преобразуются в Long. Date, Single, Currency преобразуются в Double. Последнее преобразование - грубейшее нарушение стандарта, так как Currency перестает быть целочисленным типом, используемым в бухгалтерии для точных расчетов (целочисленный {с фиксир.точкой} тип не обязательно целое). При этом возникают потери точности при больших числах. В ранних версиях Currency работает верно. Преобразование целочисленных значений (или Single) в Double (и, что важнее, обратно) делается криво (и в VB[A] и в SQL), хотя, в отличие от заблуждения (связанного с большОй распространенностью продуктов MS с таким багом), число меньшей значащей разрядности можно (и нужно) представить как число не меньшей значащей разрядности без потери точности.
Интеpесно, что пpедставление целого числа как Double не вызывает потеpи точности ни в VBA ни в SQL, сбой пpоисходит только для выpажений, пpичем даже для типа: (Val+0) (!!).
Обработка чисел с плавающей точкой по идее (из институтского курса:) должна заканчиваться округлением до пределов точности вычислений (с учетом того, что операции с плавающей точкой выполняются в расширенном формате). Увы, эта операция не производится (почему?). Отсюда 4/2=1.99...97
Рекомендации:
- где только возможно используйте целочисленные типы (Byte, Integer, Long, Currency);
- вместо Int и Fix в пpеделах точности 3 знаков после запятой использyйте для окpyгления Format(CCur(vVal), "#."), а для усечения - Format(CCur(vVal - SGN(vVal) * 0.5), "#.");
- хотя бы не используйте Int/Fix внутри выражений и выражения внутри них;
- явным образом следите за преобразованиями типов и корректируйте их;
- учитывайте, что Currency (Jet3.0+) имеет из 19 цифр только 16 значащих;
- если при работе с плавающей точкой достаточно точности Single, то проще считать числа как Double (впpочем, в SQL/MSA97 они и так будут Double), а pезультат пpиводить к Single, используя функцию CSng.
(Victor Maslovski, 5030/153.10)

  Ответить  
 
 автор: OlegZa   (18.05.2009 в 18:17)   личное сообщение
 
 

Огромное спасибо!
Помогло.
Поле Количество действительно было Single.
Переделал на Double - все встало на свои места.
Теперь считает правильно.

  Ответить  
 
 автор: Анатолий (Киев)   (18.05.2009 в 18:39)   личное сообщение
 
 


Переделал на Double - все встало на свои места.


И все же, почему Double, а не Currency или Decimal? Сколько знаков после запятой допускает количество? С Double вы тоже можете попасть в засаду при подсчете итоговых сумм на большом массиве данных.

  Ответить  
HiProg.com - Технологии программирования
Rambler's Top100 TopList