2004. november 13., szombat
Rounding numbers in different ways
Problem/Question/Abstract:
How can I round a number "normally"? Can I round the thousands? Can I round the third digit after the decimal point?
Answer:
Integer rounding
The Round function that comes with Delphi performs what is called "banker's rounding", meaning that a number with a fractional part of 0.5 is rounded sometimes up and sometimes down, always towards the nearest even number. This means that for example Round(3.5) gives 4 while Round(2.5) gives 2. Here goes a set of functions for rounding numbers, including RoundN which rounds a number "normally" (i.e. RoundN(3.5) is 4 and RoundN(2.5) is 3).
function Sgn(X: Extended): Integer;
// Returns -1, 0 or 1 according to the
// sign of the argument
begin
if X < 0 then
Result := -1
else if X = 0 then
Result := 0
else
Result := 1;
end;
function RoundUp(X: Extended): Extended;
// Returns the first integer greater than or
// equal to a given number in absolute value
// (sign is preserved).
// RoundUp(3.3) = 4 RoundUp(-3.3) = -4
begin
Result := Int(X) + Sgn(Frac(X));
end;
function RoundDn(X: Extended): Extended;
// Returns the first integer less than or
// equal to a given number in absolute
// value (sign is preserved).
// RoundDn(3.7) = 3 RoundDn(-3.7) = -3
begin
Result := Int(X);
end;
function RoundN(X: Extended): Extended;
// Rounds a number "normally": if the fractional
// part is >= 0.5 the number is rounded up (see RoundUp)
// Otherwise, if the fractional part is < 0.5, the
// number is rounded down (see RoundDn).
// RoundN(3.5) = 4 RoundN(-3.5) = -4
// RoundN(3.1) = 3 RoundN(-3.1) = -3
begin
(*
if Abs(Frac(X)) >= 0.5 then
Result := RoundUp(X)
else
Result := RoundDn(X);
*)
Result := Int(X) + Int(Frac(X) * 2);
end;
function Fix(X: Extended): Extended;
// Returns the first integer less than or
// equal to a given number.
// Int(3.7) = 3 Int(-3.7) = -3
// Fix(3.7) = 3 Fix(-3.1) = -4
begin
if (X >= 0) or (Frac(X) = 0) then
Result := Int(X)
else
Result := Int(X) - 1;
end;
function RoundDnX(X: Extended): Extended;
// Returns the first integer less than or
// equal to a given number.
// RoundDnX(3.7) = 3 RoundDnX(-3.7) = -3
// RoundDnX(3.7) = 3 RoundDnX(-3.1) = -4
begin
Result := Fix(X);
end;
function RoundUpX(X: Extended): Extended;
// Returns the first integer greater than or
// equal to a given number.
// RoundUpX(3.1) = 4 RoundUpX(-3.7) = -3
begin
Result := Fix(X) + Abs(Sgn(Frac(X)))
end;
function RoundX(X: Extended): Extended;
// Rounds a number "normally", but taking the sign into
// account: if the fractional part is >= 0.5 the number
// is rounded up (see RoundUpX)
// Otherwise, if the fractional part is < 0.5, the
// number is rounded down (see RoundDnX).
// RoundX(3.5) = 4 RoundX(-3.5) = -3
begin
(*
if Abs(Frac(X)) >= 0.5 then
Result := RoundUpX(X)
else
Result := RoundDnX(X);
*)
Result := Fix(X + 0.5);
end;
Rounding to a decimal digit
The functions we've just presented above always round to the last integer digit, but sometimes we need to round for example to the second decimal or to the thousands, millions or billions. You can overload the RoundN function with this version that takes an extra parameter to indicate the digit to be round:
function RoundN(x: Extended; d: Integer): Extended;
// RoundN(123.456, 0) = 123.00
// RoundN(123.456, 2) = 123.46
// RoundN(123456, -3) = 123000
const
t: array[0..12] of int64 = (1, 10, 100, 1000, 10000, 100000,
1000000, 10000000, 100000000, 1000000000, 10000000000,
100000000000, 1000000000000);
begin
if Abs(d) > 12 then
raise ERangeError.Create('RoundN: Value must be in -12..12');
if d = 0 then
Result := Int(x) + Int(Frac(x) * 2)
else if d > 0 then
begin
x := x * t[d];
Result := (Int(x) + Int(Frac(x) * 2)) / t[d];
end
else
begin // d < 0
x := x / t[-d];
Result := (Int(x) + Int(Frac(x) * 2)) * t[-d];
end;
end;
Copyright (c) 2001 Ernesto De Spirito
Visit: http://www.latiumsoftware.com/delphi-newsletter.php
Feliratkozás:
Megjegyzések küldése (Atom)
Nincsenek megjegyzések:
Megjegyzés küldése