04.09.2007, 15:14 | #1 |
Участник
|
Алгоритм расчета общей суммы
Граждане форумчане,
Помогите составить алгоритм рассчета общей суммы. Вкратце опишу проблему на примере: Формируется отчет, в котором выводятся строки документа с указанием кол-ва, цены и суммы по строке. По этим суммам рассчитывается итоговая сумма документа. Фиксированно кол-во по строке и исходная сумма (в отчет не попадает). Все суммы округляются до 2ого знака после запятой. Цена (расчетная) рассчитывается как Сумма (исходная) / Кол-во Сумма (расчетная) рассчитывается как Цена (расчетная) * Кол-во Пример: Итого, 9 копеек разницы. Необходимо: Менять цену так, чтобы свести к минимуму расхождение общей суммы. Последний раз редактировалось kashperuk; 04.09.2007 в 15:18. Причина: картинку вставил |
|
|
За это сообщение автора поблагодарили: petr (2). |
04.09.2007, 15:20 | #2 |
Banned
|
Цифры 3.34 и 6.63 заранее известны?
Если да, то сравнивайте расчетную и исходную накопленные суммы по каждой строке: Delta1 = 3,34 - decRound(3,34/10, 2) = 3,34 - 3,30 = 0,04 decRound(Delta1/10, 2) = decRound(0,004, 2) = 0 => коррекция невозможна Delta2 = 3,34 + 6,63 - 3,30 - 6,60 = 0,07 decRound(Delta2/10, 2) = decRound(0,007, 2) = 0,01 => коррекция = +0,01 => цена = 0,67 Последний раз редактировалось EVGL; 04.09.2007 в 15:27. |
|
04.09.2007, 15:21 | #3 |
Участник
|
Да, конечно.
Известно кол-во по строке, правильная (до округления) сумма по строке, и, соответственно, правильная (без округления) общая сумма. |
|
04.09.2007, 15:32 | #4 |
Banned
|
Тогда см. предыдущий пост. Возможно, надо будет еще обработку последней строки вставить, чтобы оставшаяся ошибка включалась в последнюю расчетную сумму (если это возможно, что последняя "Сумма расчетная" != "Цена расчетная" * "Количество").
Проще говоря: 10 ----- 0,67 ----- 6,67 (!= 6,70) ----- 6,63 Последний раз редактировалось EVGL; 04.09.2007 в 15:35. |
|
04.09.2007, 16:02 | #5 |
Участник
|
Цитата:
Менять цену так, чтобы свести к минимуму расхождение общей суммы.
|
|
04.09.2007, 16:06 | #6 |
Участник
|
Да. То есть разница между 10.00 и 9.97 будет уже 0.03, а не 0.07.
То есть пытаемся уменьшить общее отклонение итоговой суммы |
|
04.09.2007, 16:13 | #7 |
Участник
|
Цитата:
суммы всегда храняться с большим числом знаков. суммы всегда отображаются в отчете с округлением. Рассчитывать итоговую сумму по НЕОРУГЛЕННЫМ суммам - большая методическая ошибка. Перед выводом, перед записью в БД, любая сумма должна быть округлена при помощи Currency::amount(...) или Currency::amountCur(...). Это правило. Кстати, любое количество также должно быть округлено перед выводом и перед записью в БД. |
|
04.09.2007, 16:17 | #8 |
Banned
|
Тот алгоритм, который я описал, используется в русской книге продаж в случае "НДС по оплате" с несколькими оплатами к одной накладной. Нетрудно видеть, что ошибка в моем алгоритме <= 0,01 * Среднее_количество_по_строке ~ 0,10 в вашем случае.
|
|
04.09.2007, 16:18 | #9 |
Участник
|
Ну тогда вам в математический справочник. Идея, насколько я помню такая:
У вас есть числа A1, A2, An (в вашем примере это 3,34 и 6,63). Вам надо найти такие числа B1, B2, Bn (в вашем случае это сумма округлвения), чтобы выполнялось два условия. 1-ое условие: (А1/Х1 - В1)*100 - целое число. (Х1 - это кол-во для первой строки 10). Второе условие: Сумма (В1*Х1 + В2*Х2 + Вn*Хn) - (А1 + А2 + Аn) стремиться к нулю (причем по модулю). Т.е. задача на минимизацию. Я думаю такие задачи решаютмя в численных методах, или может еще в каком разделе математики. Подумаю вечерком, может что сам еще вспомню, но тут скорее надо литературу по этой теме искать или знакомых математиков трясти. |
|
|
За это сообщение автора поблагодарили: kashperuk (3). |
04.09.2007, 16:19 | #10 |
Banned
|
Цитата:
Сообщение от mazzy
По-моему, уже сказали. Но еще раз:
суммы всегда храняться с большим числом знаков. суммы всегда отображаются в отчете с округлением. Рассчитывать итоговую сумму по НЕОРУГЛЕННЫМ суммам - большая методическая ошибка. Перед выводом, перед записью в БД, любая сумма должна быть округлена при помощи Currency::amount(...) или Currency::amountCur(...). Это правило. Кстати, любое количество также должно быть округлено перед выводом и перед записью в БД. |
|
04.09.2007, 16:21 | #11 |
Участник
|
Цитата:
|
|
04.09.2007, 16:23 | #12 |
Banned
|
|
|
04.09.2007, 16:24 | #13 |
Участник
|
Вот немного усложненный пример, на котором можно думать
Расхождение в этом случае = 11.29 2 mazzy: Да оно так и хранится. Проблема в том, что цены округлены до второго знака тоже. и бухгалтерия не хочет видеть более 2 знаков в цене. А соответственно возникают расхождения. P.S. Именно, EVGL правильно говорит |
|
04.09.2007, 16:30 | #14 |
Участник
|
Цитата:
Посмотрите настройку валюты на закладке Округление. Обычно достаточно там настроить: цены округлять до сотой доли единицы валюты и т.д. Или, речь о закупках? Откуда такая забавная задачка? |
|
04.09.2007, 16:33 | #15 |
Участник
|
to Михаил Андреев, mazzy
Да вполне нормальная задача. Посмотрите как получаются отклонения в основной валюте, это практически тоже самое. Только там никто разницу не оптимизирует, а просто она кидается на счет расхождений в основной валюте и все. А kashperuk хочет в своем отчете эту разницу немного оптимизировать, т.е. уменьшить |
|
04.09.2007, 16:33 | #16 |
Участник
|
Цитата:
Не факт, что так и ХРАНИТСЯ. Аксапта всегда ПОКАЗЫВАЕТ округленные суммы, а ХРАНИТ как записал программист. Точно-точно? Ну и пусть ВИДИТ! Если же вопрос не о представлении, а о ХРАНЕНИИ. У цен свое правило округления задается в параметрах валют. У цен свой тип, для которого можно настроить свое количество знаков после запятой. Но тогда у бухов будет расхождение с контрагентами, которые работают с двумя знаками после запятой в цене Если цена округляется, то согласен с EVGL, будут нестыковки либо в цене каждой строчки, либо в общем НДСе в зависимости от того, в каком направлении будет выполняться расчет (от цены к общей сумме или от общей суммы к цене) |
|
|
За это сообщение автора поблагодарили: kashperuk (3). |
04.09.2007, 16:38 | #17 |
Banned
|
Мой вариант: 0.33 --- 0.67 --- 0.23 --- 2.10 => 271.50. Да, хреново.
0.33 --- 0.67 --- 0.24 --- 2.05 => 280.75 гораздо лучше. |
|
|
За это сообщение автора поблагодарили: kashperuk (3). |
04.09.2007, 16:43 | #18 |
Banned
|
Самый тупой вариант - это на каждом шаге попробовать изменить цену на -0,01 и +0,01 соответственно, посмотреть, что будет. Т.е. порядка 2^(количество_строк -1) итераций.
|
|
04.09.2007, 17:11 | #19 |
Участник
|
Есть, кстати, еще одно условие, усложняющее в значительной мере алгоритм
Цена не должна уменьшаться/увеличиваться более, чем на 10% от своего начального значения. Отослал данные для анализа знакомому профессору. Если ничего умного не придумает до завтра, будем сами изобретать какой-то много-итерационный алгоритм. Спасибо всем за участие. Продолжение следует... |
|
04.09.2007, 17:17 | #20 |
Участник
|
Цитата:
Спасибо всем за участие.
|
|