1

i have the following code to round the currency

function MyRound(value :currency) : integer;

begin
  if value > 0 then
    result := Trunc(value + 0.5)
  else
    result := Trunc(value - 0.5);
end;

it worked well so far, my problem now is if i want to round a currency like 999999989000.40 it is giving negative value since Truc takes int and MyRound also returns int.

My possible solutions is to convert currency to string and get the string before . and convert the string back to currency. Is this a right approach? i am new to delpi so pls help me out.

dataol
  • 999
  • 3
  • 19
  • 42
Jeeva
  • 4,585
  • 2
  • 32
  • 56

4 Answers4

7

From my point of view, you have two options:

  1. You use the Round function, as David Heffernan pointed;
  2. You can use the SimpleRoundTo function, as described here. The advantage of SimpleRoundTo is that it receives parameters of Single, Double and Extended data types and they convert round very well numbers like those stated.

You don't need any type conversions. There are plenty of rounding functions already available to you. Just round the desired number.

Bogdan Doicin
  • 2,342
  • 5
  • 25
  • 34
  • 1
    How does `SimpleRoundTo(..., 0)` differ from `Round(...)`? – David Heffernan Feb 22 '13 at 15:14
  • @DavidHeffernan in this case, it doesn't. That's why I said that your solution gives the same result. However, it makes a difference if you want to round a number to a given precision. `Round(...)` is a particular case of `SimpleRoundTo(...,0)` – Bogdan Doicin Feb 22 '13 at 15:31
  • 1
    @DavidHeffernan: It doesn't use bankers' rounding. According to the documentation that Bogdan linked to "The result of this function depends on the current FPU rounding mode ... To round in "Banker's mode", use System.Math.RoundTo." – Marjan Venema Feb 22 '13 at 15:31
5

You are overcomplicating matters. You can simply use Round:

program Project1;
{$APPTYPE CONSOLE}

uses
  SysUtils;

var
  C: Currency;

begin
  C := 999999989000.4;
  Writeln(Round(C));
  C := 999999989000.5;
  Writeln(Round(C));
  C := 999999989000.6;
  Writeln(Round(C));
  C := 999999989001.4;
  Writeln(Round(C));
  C := 999999989001.5;
  Writeln(Round(C));
  C := 999999989001.6;
  Writeln(Round(C));
  Readln;
end.

which outputs

999999989000
999999989000
999999989001
999999989001
999999989002
999999989002

If you don't want banker's rounding, and you really do want your Trunc logic then you do need to write your own function. But the problem with your function is that it was truncating to 32 bit integer. Make the function return a 64 bit integer:

program Project1;
{$APPTYPE CONSOLE}

uses
  SysUtils, Math;

var
  C: Currency;

function MyRound(const Value: Currency): Int64;
begin
  if Value > 0 then
    result := Trunc(Value + 0.5)
  else
    result := Trunc(Value - 0.5);
end;

begin
  C := 999999989000.4;
  Writeln(MyRound(C));
  C := 999999989000.5;
  Writeln(MyRound(C));
  C := 999999989000.6;
  Writeln(MyRound(C));
  C := 999999989001.4;
  Writeln(MyRound(C));
  C := 999999989001.5;
  Writeln(MyRound(C));
  C := 999999989001.6;
  Writeln(MyRound(C));
  Readln;
end.
999999989000
999999989001
999999989001
999999989001
999999989002
999999989002
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • 6
    Doesn't round suffer from bankers' rounding where 2.5 goes to 2 and 3.5 goes to 4? (Or the other way round, can never remember). The 0.5 trick is the simplest way to work around that without messing with FPU settings? – Marjan Venema Feb 22 '13 at 12:31
  • 2
    @MarjanVenema Well, that's how `Round` works. If you want something different, then use something different. – David Heffernan Feb 22 '13 at 12:36
  • 6
    Well, that's how round works given the standard FPU settings. It is not how people expect round to work given basic math knowledge but no financial background. It certainly surprised me when I found out about it... – Marjan Venema Feb 22 '13 at 12:43
  • @MarjanVenema Unfortunately most people in high school are the taught *round to infinity* rule. This kind of rounding is not used in science or finance as it introduces a bias because 0.5 is always rounded up. The reason the FPU doesn't default to *infinity* rounding is because nobody who cares uses it. – Ian Boyd Dec 12 '18 at 20:32
  • 1
    I like Embarcadero's help page (up to date for Alexandria): "If X is exactly halfway between two integer numbers, the result is always the even number". https://docwiki.embarcadero.com/Libraries/Alexandria/en/System.Round No wonder, why they cannot attract new users. – Gabriel May 03 '22 at 07:20
  • docwiki.embarcadero.com/Libraries/Alexandria/en/System.Round – Gabriel May 03 '22 at 07:26
  • 1
    I don't like how the function is explained on Embarcadero's page. – Gabriel May 03 '22 at 07:30
1

Take a look at John Herbster's rounding routines. They offer nearly any type of rounding you might want, e.g.:

drNone,    {No rounding.}
drHalfEven,{Round to nearest or to even whole number. (a.k.a Bankers) }
drHalfPos, {Round to nearest or toward positive.}
drHalfNeg, {Round to nearest or toward negative.}
drHalfDown,{Round to nearest or toward zero.}
drHalfUp,  {Round to nearest or away from zero.}
drRndNeg,  {Round toward negative.                    (a.k.a. Floor) }
drRndPos,  {Round toward positive.                    (a.k.a. Ceil ) }
drRndDown, {Round toward zero.                        (a.k.a. Trunc) }
drRndUp);  {Round away from zero.}

I can't give you a link right now, but Google: decimal rounding John Herbster I think his latest rounding routines are in DecimalRounding_JH1.pas. His discussion of floating point rounding (somewhere on Embarcadero's website is a "must-read".

Max Williams
  • 821
  • 1
  • 7
  • 13
0

This is what I actually use (would love to hear if there is any problems with this approach!):

function RoundingFunction(X: Real): Int64;
begin
  Result := Trunc(SimpleRoundTo(X, 0));
end;
Leonardo Herrera
  • 8,388
  • 5
  • 36
  • 66