Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2003.12.23;
Скачать: [xml.tar.bz2];

Вниз

Суммирование чисел   Найти похожие ветки 

 
Pilot   (2003-12-09 18:47) [0]

Доброе время суток!
Возникла проблема с суммированием чисел:
есть число разбитое на 3 части при их сложении результат либо больше, либо меньше на 0.01, 0.02.
Подскажите как от этого избавиться(в смысле как правильно сложить без ошибок)?
Всем заранее спасибо!!!


 
Cosinus   (2003-12-09 18:50) [1]

???
Что такое "разбитое на 3 части"???


 
Тимохов   (2003-12-09 18:51) [2]

Подробнее, пожалуйста.


 
Pilot   (2003-12-09 19:12) [3]


> Cosinus © (09.12.03 18:50) [1]


> Тимохов (09.12.03 18:51) [2]

Eсть число 240:
1. 240/1,26=190,476190
2. 190,476190*0,2=38,095238
3. 190,476190*0,06=11,428571
Если их сложить то получается 239,999999 при округленнии должно получиться 240.00. А программа выдает 239.99. А при 4-х единицах по 240.00 960.00.


 
panov   (2003-12-09 19:16) [4]

Первое правило суммирования - округляется сумма, а не слагаемые.


 
Кот Бегемот   (2003-12-09 19:17) [5]

Это потому что ты делишь неправильно
240/1.26 ~ 190,47619047619047619047619047619(476190)
почувствуйте разницу !!!


 
Тимохов   (2003-12-09 19:26) [6]

Вопрос, все-таки, не очень ясен.


 
Pilot   (2003-12-09 19:35) [7]


> panov © (09.12.03 19:16) [4]

Мне необходимо вывести сумму и все слогаемы так, чтобы их сумма была равной показанной. Точность должна быть 2 знака после запятой. Аобщую сумму "правильную" я могу получить.


> Кот Бегемот © (09.12.03 19:17) [5]
> Это потому что ты делишь неправильно
> 240/1.26 ~ 190,47619047619047619047619047619(476190)
> почувствуйте разницу !!!

Я это знаю но при округлении до сотых используется 3-ий знак после запятой, а остальные не учитываются.
Поэтому мне необходимо округлить все слогаемые и просуммировать их, но так чтобы сумма была правильная.


 
Тимохов   (2003-12-09 19:37) [8]

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


 
panov   (2003-12-09 19:42) [9]

Ошибка в 17-й строке.


 
Pilot   (2003-12-09 19:43) [10]


> Тимохов (09.12.03 19:37) [8]

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


 
Тимохов   (2003-12-09 19:52) [11]

Правильно все только в раю.
А в дискретном мире (мире компов) всегда что-то неправильно...


 
Pilot   (2003-12-09 20:01) [12]


> panov © (09.12.03 19:42) [9]

Да я знаю.


 
Pilot   (2003-12-10 18:26) [13]

Вот исходник как я это делал
Вариант1:
sum1:=0;
sum2:=0;
sum3:=0;
summ:=0;
Dm.qNDS.First;
for i:=1 to Dm.qNDS.RecordCount do
begin
{sum1:=sum1+Dm.qNDS.FieldByName("PF").AsFloat*Dm.qNDS.FieldByName("Kol").AsFloat;
sum2:=sum2+Dm.qNDS.FieldByName("NDS").AsFloat*Dm.qNDS.FieldByName("Kol").AsFloat;
sum3:=sum3+Dm.qNDS.FieldByName("Price").AsFloat*Dm.qNDS.FieldByName("Kol").AsFloat;}
summ1:=Dm.qNDS.FieldByName("PF").AsFloat+Dm.qNDS.FieldByName("NDS").AsFloat+Dm.qNDS.FieldByName("Price").AsFloat;
summ:=summ+summ1*Dm.qNDS.FieldByName("Kol").AsFloat;
Dm.qNDS.Next;
end;
//Sum:=FormatFloat("0.000",sum3);
//Sum:=FormatFloat("0.00",StrToFloat(Sum));
rez:=FormatFloat("0.00",summ);
summ:=StrToFloat(rez);
//sum1:=StrToFloat(FormatFloat("0.00",sum1));
//sum2:=StrToFloat(FormatFloat("0.00",sum2));
//sum:=FormatFloat("0.00",summ-sum1-sum2);
rez:="";
Transform(rez,summ{sum1+sum2+sum3},0);
s:=Trim(rez);
lProp:=s;


Вариант2:
sum1:=sum1+Dm.qNDS.FieldByName("PF").AsFloat*Dm.qNDS.FieldByName("Kol").AsFloat;
sum2:=sum2+Dm.qNDS.FieldByName("NDS").AsFloat*Dm.qNDS.FieldByName("Kol").AsFloat;
sum3:=sum3+Dm.qNDS.FieldByName("Price").AsFloat*Dm.qNDS.FieldByName("Kol").AsFloat;
summ1:=Dm.qNDS.FieldByName("PF").AsFloat+Dm.qNDS.FieldByName("NDS").AsFloat+Dm.qNDS.FieldByName("Price").AsFloat;
summ:=summ+summ1*Dm.qNDS.FieldByName("Kol").AsFloat;
sum1:=StrToFloat(FormatFloat("0.00",sum1));
sum2:=StrToFloat(FormatFloat("0.00",sum2));
Dm.qNDSAll1.Value:=StrToFloat(FormatFloat("0.00",summ-sum1-sum2));

Подскажите пожалейста где ошибка, если есть, или что я неправильно делаю.
Всем заранее большое спасибо!!!


 
Тимохов   (2003-12-10 18:36) [14]

А что собственно нужно сделать?
Сложно по постановке этого и всех предыдущих вопросов понять что вообще ты хочешь?


 
Тимохов   (2003-12-10 18:37) [15]

Опиши по пунктам: хочу добиться того-то и того-то. Как мне это сделать?

На такой вопрос намного легче отвечать.


 
Sandman25   (2003-12-10 18:38) [16]

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


 
Pilot   (2003-12-10 19:19) [17]


> Sandman25 © (10.12.03 18:38) [16]

Когда я округляю до двух знаков то общая сумма "бьет" на 0,01.
Почему я не знаю.

> Тимохов (10.12.03 18:37) [15]

1. Есть число(240).
2. Считаем число с которым работаем(240/1,26=190,47619047619047619047619047619)
x=190,47619047619047619047619047619
3. Считаем 20% от числа(y=x*0,2=38,095238095238095238095238095238)
4. Считаем 6% от числа (z=x*0,06=11,428571428571428571428571428571)
x+y+z=239,9999999999999999999999999999
Вопрос в том как правильно округлить, чтобы ошибка(0,01) пропала и встала в нужном слагаемом.
Т.к. если округлять до 2-х знаков получается следующее:
190,48+38,10+11,43=240,01.
Вот такай вопрос.
Заранее большое спасибо!!!


 
Тимохов   (2003-12-10 19:25) [18]

Насколько я понимаю это НДС и НП (или что-то типа того)?

Если ты хошь добиться точности, то этого сделать никак нельзя.
Всегда будет ошибка.

Я уже писал ранее (сам занимаюсь финансовыми системами), что в аналогичном случае выбирается жертва, котрая считается не по понятиям, а путем вычитания из общей суммы всех слагаемых кроме последнего.

В твоем случае я бы следал так.
1. Посчитал делением х и округлил бы его до 2 знаков (типа, копейки)
2. Посчитал умножением у и округлил бы его до 2 знаков (типа, тоже копейки)
3. Почитал z = 240-x-y.

Тогда все будет верно. Можешь жертвой выбрать другое слагаемое.
Вообще говоря, по другому ты никак не сделаешь - это общий подход, который используется во всех финансовых системах.


 
Тимохов   (2003-12-10 19:28) [19]

я в своей практике жертвой выбираю сумму без НДС и НП, т.е. в твоем изложении это х.


 
Pilot   (2003-12-10 19:51) [20]


> Тимохов (10.12.03 19:28) [19]

Делов том что, если выбирать жертвой сумму без НДС и НП, т.е. это х, то при нескольких х сумма без НДС может отличаться от реальной суммы. Этот способ я пробовал и мне сказали, что такое решение проблемы не подходит.Вот.


 
Тимохов   (2003-12-10 19:55) [21]

Ну бейтесь дальшей, упрямые.
Я тебе сказал - других решений нет.
Всегда что-то будет неточно.
Могу говорить об этом вполне уверено - лимон строк бухгалтерской системы на дельфи и фигова туча на sql, и конечно, успешная эксплуатация всего комплекса не первый год, хорошее доказательство этого.

Другое решение, может заключаться в том, что отталкиваться надо не от суммы с НДС и НП, а от суммы без НДС и НП. Т.е. х сделать хранимой в базе и вводимой пользователем. Тогда проблем точно не будет.


 
Anatoly Podgoretsky   (2003-12-10 20:00) [22]

Именно неверный алгоритм, отсюда и проблемы и отсутсвие решения.


 
Тимохов   (2003-12-10 20:04) [23]

Не очень понял кому это "Именно неверный алгоритм, отсюда и проблемы и отсутсвие решения." многоуважаемого Аналолия.

Но если это к автору вопроса, то я с ним согласен.
Из какой суммы без НДС и НП можно получить число 240? Такого числа с двумя знаками после запятой точно нет.

Здесь дырки в логике... однозначно.


 
Anatoly Podgoretsky   (2003-12-10 20:11) [24]

Конечно к автору вопроса, и по логике, надог добавляется к стоимости, а не наоборот, или в России не так?


 
Pilot   (2003-12-10 20:11) [25]


> Тимохов (10.12.03 19:55) [21]

Я так и сделал, т.е.в базе хранится информация о сумме без НДС и от него пляшут все расчеты. Но это не помогает.
Вот эти числа:
Dm.qNDS.FieldByName("PF").AsFloat=Dm.qNDS.FieldByName("Price").AsFloat*0,06
Dm.qNDS.FieldByName("NDS").AsFloat=Dm.qNDS.FieldByName("Price").AsFloat*0,2,
а Dm.qNDS.FieldByName("Price").AsFloat это цена без НДС и НП.


 
panov   (2003-12-10 20:13) [26]

1. Где округлять - см. panov © (09.12.03 19:16) [4]
2. Ткни пальцем, пожалуйста, в каком месте ты вообще округляешь?


 
Тимохов   (2003-12-10 20:18) [27]

Все-таки Панов прав: ты округляешь то где?

Посчитал НДС, округли.
Посчитал НП, округли.
Потом сложи сумму без НДС и НП, сумму НДС и сумму НП. Получишь сумму с НДС и НП.

Конечно, если ты начнешь сумму с НДС и НП обратно разварачивать в сумму без НДС и НП, то скорее исходную сумму не получишь, но ты этого и не делай.

В общем-то в чем проблема? Зачем тебе понадобилось обратное действие делать?


 
Anatoly Podgoretsky   (2003-12-10 20:27) [28]

Обратное действие смысл не имеет, вот пример A:=1/3, a*3


 
Anatoly Podgoretsky   (2003-12-10 20:29) [29]

Тимохов (10.12.03 20:18) [27]
При том округление наверняка по закону до целых, до копейки, цента, сантима и т.д..


 
Тимохов   (2003-12-10 20:30) [30]

Anatoly Podgoretsky © (10.12.03 20:27) [29]
Я имел в виду до двух знаков после запятой.


 
Anatoly Podgoretsky   (2003-12-10 20:31) [31]

То есть до 0.01 копейки?


 
Anatoly Podgoretsky   (2003-12-10 20:31) [32]

То есть до 0.01 копейки?


 
panov   (2003-12-10 20:32) [33]

Специально провел последовательно все операции в соответствии с panov © (09.12.03 19:16) [4].

Результат(без округлений) такой:

x=190,47619047619048200000000
y=38,09523809523809490000000
z=11,42857142857142880000000
Summa=240,00000000000000500000000


Далее, воспользовавшись функцией округления

FormatFloat("0.00",Round((Summa+0.0005)*100)/100);

получаем значение 240.00


 
panov   (2003-12-10 20:34) [34]

А если тебе обязательно нужно использовать числа x,y,z, то в этом случае обязательно будет погрешность.
Её прибавляют к одному из значений(как правило).


 
Тимохов   (2003-12-10 20:39) [35]

Anatoly Podgoretsky © (10.12.03 20:31) [31]
Ну я так понял, что целое это рубль. Значит два знака после запятой для целого, это 1 коп.

panov © (10.12.03 20:34) [34]
Полностью согласен с тем, что погрешность куда нибудь прибавляют.


 
Pilot   (2003-12-11 17:13) [36]


> Тимохов (10.12.03 20:18) [27]

При подсчете я округляю следующим образом:
1.Сумма без НДС и НП 190,48
НДС 190,48*0,2=38,10(38,096)
НП 190,48*0,06=11,43(11,4288)
Сумма 240,01
2.Сумма без НДС и НП 190,48*2=380,96
НДС 380,96*0,2=76,19(76,1904)
НП 380,96*0,06=22,86(22,85712)
Сумма 480,01
И если считать Сумму без НДС и НП по формуле
Сумма - НДС - НП, то получаю
1.Сумма без НДС и НП 190,47
2.Сумма без НДС и НП 190,48*2=380,95
Т.о. видна ошибка при подсчете суммы.
Как поступить в таком случае?
Заранее благодарен!!!


 
Тимохов   (2003-12-11 17:17) [37]

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


 
PIlot   (2003-12-11 17:27) [38]

Всем большое спасибо за помощь!
Я понял что больше ничего толкового не подскажут.


 
BorisKb   (2003-12-11 17:32) [39]

Если не привязываться к НДС и НП (например идет счет и суммирование по людям), то еще один вариант, используемый мной. Это "по копейке сверху" или "по копейке снизу". Т.е. Разницу округления по 0,01 раскидываю по отдельным слагаемым, нужным образом отсортированным.



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2003.12.23;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.54 MB
Время: 0.009 c
8-75270
K-Sergey
2003-08-15 10:55
2003.12.23
Как получить картинку с WebCam


7-75432
Gregory
2003-10-15 13:14
2003.12.23
Управление сигналом RTS в COM порте.


3-75080
loki128
2003-12-01 10:24
2003.12.23
Обращение к динамически созданным TADOQuery


14-75313
LLL
2003-12-01 20:47
2003.12.23
Делфи и его функции


14-75382
alex134
2003-11-28 00:21
2003.12.23
Вопрос по Вебдизайну, авось кто знает?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский