Скажите, как вы округляете деньги в клиентской части?

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

Нашел метод Terrasoft.roundValue()  и даже им пользовался некоторое время, пока не поймал баг.

Terrasoft.roundValue(4758.985, 2) - вернул 4758.98

Если посмотреть исходный код, то становится понятно.

ƒ (value, decimalPlaces) {

    var exponent = Math.pow(10, decimalPlaces || 0);

    return Math.round(value * exponent) / exponent;

}

4758.985 * 100 = 475898.49999999994

Math.round(475898.49999999994)/100 = 4758.98, от сюда и баг.

Находил метод roundValue из миксина MoneyUtilsMixin, он считает вроде правильно, но вторым аргументом принимает не число, а объект this.roundValue(value, {"decimalPlaces": 2}), что приносит некоторые неудобства.

Если использовать метод roundMoney, то он округляет по умолчанию до 4х знаков.

Пожалуйста подскажите наиболее правильный путь?

Нравится

5 комментариев

Посмотрите обсуждение подобного вопроса в этом посте.

Алла Савельева,

 не очень понимаю, что именно в этом обсуждении нужно посмотреть? Вопрос был в том, как правильно округлить число до двух знаков средствами creatio, не изобретая велосипед, а не что такое Mantissa.

Трефилов Павел Сергеевич,

Изначально неверно поняла ваш вопрос.

Для поля, которое содержит деньги, в creatio есть специальный тип 'Деньги'. Данный тип содержит 2 знака после запятой и, если у Вас получается для этого поля значение 4758.985, то система в данном случае сама должна округлить до второго знака в сторону увеличения без каких-либо дополнительных округлений со стороны разработчика.

Добавить комментарий

Алла Савельева,

а если мне нужно округлить до сохранения в бд? К примеру я считаю что-то, добавляю в переменную и сравниваю со старым значением из поля (БД).

Вообще, дробные числа, даже написанные в коде константы, сравнивать между собой опасно, как раз отличие в 0.0000000001 может проявиться. И даже сравнение разницы с Number.EPSILON помогает не всегда.

См. статьи:

Автор там вообще предлагает «to store your numbers as strings».

Показать все комментарии

В FastReport присутствует пользовательская функция Round, которая округляет исключительно до целого числа.
Чтобы вывести результат, округленный до определённого знака, необходимо:
1 . Открыть сервис отчета. Перейти на закладку «Code». Добавить функцию вида:

function RoundTo(X:Extended; N: Integer): Extended;
var
  i,i1: Integer;
begin
  Result := X;
  i1 := 1;
  for i := 1 to N do  
    i1 := i1*10;
  result := Round(Result*i1)/i1;
end;

/system/files/1_93.png

2. На странице отчета для текстового объекта прописать такой код:

[RoundTo(ds_ReportOpportunityOfferings."Amount">, 2)]

Вместо 2 указать до какого количества символов выполнять округление:

/system/files/2_54.png

Нравится

Поделиться

1 комментарий

Цікаве рішення

Але замість циклу

i1 := 1; 
for i := 1 to N do  
  i1 := i1*10; 

краще використати функцію Power(10, N). По ефективності результат повинен вийти не гіршим, а естетично виглядатиме краще

Показать все комментарии

Периодически, разрабатывая конфигурации, сталкиваемся с проблемами дробного числа в Jscript'е. Пример проблемы, на скриншоте:

Единым решением, пока, остается округление всюду, где только не уверены в правильности вычислений.
Какие будут соображения? Кто и как обходит данную проблему?

Нравится

Поделиться

11 комментариев

Так эти числа потом либо в датафилд ложаться, либо в отчете отображаются. И там и там они округлятся. Проблема только при отображении в сообщениях, там округление и используем.

В данном примере, система проверяет достаточно ли в данной партии продукта для отгрузки. Нужно: 0,6 единиц.
Доступно: 1,7 - 1,1 = 0,5999999999999999999

Выводит сообщение, что НЕ достаточно товаров на складе для отгрузки :confused:

--
www.it-sfera.com.ua

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

0.6 - (1.7 - 1,1) > eps

где еps достаточно малая ненулеавя величина. Берем eps = 1e-10. Пишем функцию сравнения

function IsGreat(a, b){
    return ((a - b) > eps)
}

ну и остальные функции сравнения чисел.

Когда начинал писать, идея казалась бредом, а сейчас даже нравится начинается :)

Я бы еще (a-b) по модулю взял, иначе работать не будет.

Идея интересная :biggrin:
Попробуем!

--
www.it-sfera.com.ua

"Попов Александр" написал:Я бы еще (a-b) по модулю взял, иначе работать не будет.

На самом деле для IsGreat работать будет - попробуйте на приведенном примере :) А вот для IsEqual и IsGreatOrEqual действительно нужен модуль.

Спасибо за уточнение! Но, цитата не моя :wink:

--
www.it-sfera.com.ua

Вы еще скажите что и мопед не Ваш :)
Сорри, Акелла промахнулся :)

С кем не бывает?!

--
www.it-sfera.com.ua

"Виталий Ковалишин aka samael" написал:С кем не бывает?!

Этот вопрос мне адресован? :)

Я же не со зла! :)

--
www.it-sfera.com.ua

Показать все комментарии

Доброе время суток!

Возникла у меня в одном проекте из-за 1 копейки реальная проблема… Кажется, что такое копейка? Сегодня у нас и на гривну не много можно купить, а тут копейка! «К чему бы это он?», - спросите Вы. Объясню подробно.

В проекте, в разделе [Счета], используется двойное налогообложение продукта: Цена + НДС 20% + ННР 0,5% (или 0,1%). Попробуем математически рассчитать (округляем до второго знака после запятой):
Сумма с налогами: 300 грн
НДС 20%:
300*20/(100+20+0,5) = 49,79253112033195020746887966805
(49 грн 79 коп)
ННР 0,5%:
300*0,5/(100+20+0,5) = 1,2448132780082987551867219917012
(1 грн 24 коп)

Если мы воспользуемся стандартной функцией Math.Round() или System.Round() ( http://community.terrasoft.ua/node/1847 )
В поле ННР 0,5% увидим 1 грн 24 коп, что и стоило ожидать!

Но, внимание, если следовать расчетам бухгалтера (со ссылкой на 1С), то должно быть 1 грн 25 коп!!!
Вот эта одна копейка и испортила всю идиллию интересного проекта. Какая здесь логика?
1,2448 => 1,245 => 1,25

Прошу прощения, но тогда нужно начинать с бесконечности… А это, согласитесь, многовато.

Что бы угодить клиенту, пришлось наложить заплатку на расчет налогов:

Math.round(100* Math.round( TaxAmount *1000)/1000) / 100

М-да-а, вот такая история…
А у Вас бывали похожие казусы?

--
γνῶθι σεαυτόν

Нравится

Поделиться

8 комментариев

Так может ошибка в 1С :) Почему от точности 4 к точности 2 ножно идти через точность 3?

Если бы я только знал ПОЧЕМУ! :)

--
γνῶθι σεαυτόν

Тайна веков :) Ну, как говорится жираф большой, ему виднее :)

Вообще, отсутствие единого стандарта на округление - это извечная головная боль.

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

При этом для бухгалтерии отклонение в 1 копейку - это свидетельство о возможном отклонение в миллион.

Копейка играет огромную роль в debt collection и составлении искового заявления. Если не сходятся суммы даже на копейку судья может отклонить дело по взысканию задолженности с неплательщика до предоставления "корректной информации"

Не знаю принципа расчета Вашей суммы в 1C и в бухгалтерии, почему получается итоговая сумма 1.25.
Предлагаю по своему опыту следующее решение проблемы - расчитывайте все налоги, а на последний налог отнесите сумму, равную разнице общей суммы налога и суммы уже расчитанных налогов. Недостающая копейка будет отнесена на последний налог.

Насколько мне известно в 1С бухгалтерии идет расчет сумм от цены без НДС. То есть на нее накручивается и НДС и налог на рекламу. Это соответствует методики выписки Налоговой накладной.
При попытке вести обратный расчет (от сумм с НДС) вполне может возникнуть данная проблема.

"Ковалишин Виталий aka samael" написал:1,2448 => 1,245 => 1,25
Что бы угодить клиенту, пришлось наложить заплатку на расчет налогов:
Math.round(100* Math.round( TaxAmount *1000)/1000) / 100

Это Вы созря. Могу почти гарантировать что 1С так не считает, разве что так написал какой-то безумный программист. А "Расчет налога на рекламу" как правило - это дописанные конфигурации.
Впрочем Вы сами можете посмотреть бизнесс-логику расчета в конфигурации 1С бухгалтерии. Она же есть открыта для просмотра.

Возможно, в общем Вы и правы, но в конкретном случае - другого варианта не было..

--
Cogito, ergo sum

Показать все комментарии