Бухгалтерское округление

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Бухгалтерское округление

Сообщение krab » 23.07.2010 12:41:45

Как выполнить бухгалтерское округление в Lazarus?
krab
постоялец
 
Сообщения: 108
Зарегистрирован: 17.02.2010 18:23:08

Re: Бухгалтерское округление

Сообщение alex_rain » 23.07.2010 14:46:29

Так же, как и в Delphi:
Бухгалтерское - с помощью Round,
Математическое - с помощью Trunc, например так:
Код: Выделить всё
function RoundDoubleDigit(Value: Double; Digit: Integer): Double;
var
  Factor: Double;
begin
  Factor := Exp(Digit * Ln(10));
  if Value < 0 then
    Result := Trunc(Value * Factor - 0.5) / Factor
  else
    Result := Trunc(Value * Factor + 0.5) / Factor;
end;


Lazarus 0.9.29 FPC 2.5.1 Win32

Добавлено спустя 1 час 1 минуту 30 секунд:
Пример бухгалтерского округления:
Код: Выделить всё
function BuhDoubleDigit(Value: Double; Digit: Integer): Double;
var
  Factor: Double;
begin
  Factor := Exp(Digit * Ln(10));
  Value := Value * Factor;
  Result := Round(Value) / Factor;
end;


Lazarus 0.9.29 FPC 2.5.1 Win32
alex_rain
новенький
 
Сообщения: 26
Зарегистрирован: 12.02.2010 06:56:32
Откуда: Russia

Re: Бухгалтерское округление

Сообщение VirtUX » 27.08.2010 12:25:30

alex_rain писал(а):BuhDoubleDigit

Не всегда округляет 5 в большую сторону! Как это побороть?
Аватара пользователя
VirtUX
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта

Re: Бухгалтерское округление

Сообщение Vadim » 27.08.2010 12:49:15

А если использовать тип Currency?
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Re: Бухгалтерское округление

Сообщение Nik » 27.08.2010 13:37:10

Взято из DelphiWorld:

Код: Выделить всё
function RoundCurrency(value: currency): currency;
var
  x, y: Double;
begin
  x := int(value * 100);
  y := Frac(value * 100);
  if y >= 0.5 then
    x := x + 1;
  result := x / 100;
end;


Когда-то писал похожую функцию, но с ходу не нашёл на свалке старых исходников.
Аватара пользователя
Nik
энтузиаст
 
Сообщения: 573
Зарегистрирован: 04.02.2006 00:08:09
Откуда: Киров

Re: Бухгалтерское округление

Сообщение VirtUX » 27.08.2010 15:11:58

Vadim писал(а):А если использовать тип Currency?

В Currency только 4 знака после запятой, а мне нужно 15 знаков и возможность округлить до любого знака.

Добавлено спустя 2 минуты 51 секунду:
Вот:
Код: Выделить всё
function RoundN(X: Double; CountDlim: SmallInt): Double;
var
  delim: int64 =1;
  cd: Byte;
  td: Double;
begin
  if CountDlim < 0 then Exit;

  if CountDlim > 14 then cd := 15 else cd := CountDlim;

  if cd > 0 then delim:= 10**cd;

  td := X * delim;

  if frac(td) < 0.5 then Result := trunc(td) / delim
  else Result := ceil(td) / delim;
end;             

Но даже при этом раскладе 1.005 (при округлении до 2-х знаков) округляется в меньшую. 1 вместо 1.01
Отредактировал

Добавлено спустя 11 минут 19 секунд:
А после 11 знаков начинается полная ахинея :(
Аватара пользователя
VirtUX
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта

Re: Бухгалтерское округление

Сообщение Vadim » 27.08.2010 15:37:56

VirtUX писал(а):а мне нужно 15 знаков

Ого!!! Уважаю... :)
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Re: Бухгалтерское округление

Сообщение alex_rain » 30.08.2010 03:34:27

Не всегда округляет 5 в большую сторону! Как это побороть?

Но даже при этом раскладе 1.005 (при округлении до 2-х знаков) округляется в меньшую. 1 вместо 1.01

Бухгалтерское (банковское) округление работает таким образом:
Все числа, у которых «отбрасываемая» цифра не равна 5, округляются по правилам математического округления.
А другие по следующему правилу:
– если цифра, которая стоит перед цифрой 5, четная, то округление осуществляется в меньшую сторону,
– если цифра, которая стоит перед цифрой 5, нечетная, то округление осуществляется в большую сторону.

Цитата из Википедии:
Банковское округление (англ. banker's rounding) — округление для этого случая происходит к ближайшему чётному. Это позволяет устранить систематическую ошибку округления при суммировании большого количества чисел. То есть, 2,5 → 2, 3,5 → 4.
alex_rain
новенький
 
Сообщения: 26
Зарегистрирован: 12.02.2010 06:56:32
Откуда: Russia

Re: Бухгалтерское округление

Сообщение Astralis » 30.08.2010 22:11:42

Если цель состоит только в избавлении систематической ошибки округления при большом количестве суммирования (и других систематических ошибках), то лучший вариант - использовать рандомное округление
Код: Выделить всё
rndround(x) = x-floor(x)<random ? ceil(x) : floor(x)

многие алгоритмы динамического программирования, требующие дискретизации используют именно такое округление.
Аватара пользователя
Astralis
новенький
 
Сообщения: 45
Зарегистрирован: 06.06.2007 20:33:05
Откуда: Tvercity-Annet

Re: Бухгалтерское округление

Сообщение VirtUX » 31.08.2010 12:12:49

Лично я, решил не заморачиваться. Т.к. ни Float, ни Double, ни Currency не дают возможности использовать в полной мере многорязрядность. GMP тоже странновато себя ведет. Решил отложить на попозже, чтоб написать свой модуль по работе с БОЛЬШИМИ числами - может через годик, два.
Аватара пользователя
VirtUX
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: Yandex [Bot] и гости: 57

Рейтинг@Mail.ru