I wrote a function to try and determine the average of all the values entered into an array however it keeps spitting out a value of around 50. There is an easy way around this but I'd really like to know what I'm going wrong. Bear in mind that I'm still learning Delphi so I still have a lot to learn.
I was trying to write a function that takes an array and determines the Average of all the values in the array by adding them all together and dividing the end product by the number of values in the array.
Function Average(x : array of Integer; var y : Integer): Real;
var
e : Integer;
fTotal : Real;
begin
//Initializing the variable
fTotal := 0;
Result := 0;
//Adding values to fTotal
for e := 1 to y do
begin
fTotal := fTotal + x[e];
end;
//Determining Average
fTotal := fTotal / y;
//Assigning Average to Result
Result := fTotal;
//End of Function
end;
x is the array from which the values are gotten. y is the amount of values stored in the array.
upon running the code however I have found that no matter what the values in the array are the result of the function always seems to be around 50.
I tried using these values.
arrVal : array[1..50] of integer;
var
iCount : Integer;
fAverage : Real;
begin
arrVal[1] := 70;
arrVal[2] := 80;
arrVal[3] := 90;
iCount := 3; //The amount of values in the array
fAverage := Average(arrVal, iCount);
I ran the code and the function gave me the value of 50. I tested the values and the actual average is 80.
You have declared
function Average(x: array of Integer; var y: Integer): Real;
First, x
is here an open array parameter. It's a "magical" kind of parameter that will accept a static array, a dynamic array, or an open array literal.
In any case, it contains information about the length of the array, so you don't need your y
parameter at all, so you should remove it. (And even if this was not the case, you should not have used var
for it.)
Also, you need to use const x: array of Integer
for performance reasons -- and not to risk a stack overflow.
Inside the body of the function, the indices of x
range from Low(x)
to High(x)
, and the length of x
is Length(x)
.
In this case, when x
is an open array parameter, it is guaranteed that Low(x) = 0
. And High(x) = Length(x) - 1
, so if x
is empty, High(x) = -1
making a loop like for var i := 0 to High(x) do
perform no iterations.
So, you should write
function Average(const X: array of Integer): Double;
begin
if Length(X) = 0 then
raise Exception.Create('Cannot compute average of empty array.');
Result := 0;
for var i := 0 to High(X) do
Result := Result + X[i];
Result := Result / Length(X);
end;
The Length(X) = 0
check is done for purely mathematical reasons: A list of zero numbers doesn't have an average. (But the sum of such a list is 0
and the product is 1
.)
In fact, you can even use a for in
loop:
function Average(const X: array of Integer): Double;
begin
if Length(X) = 0 then
raise Exception.Create('Cannot compute average of empty array.');
Result := 0;
for var a in X do
Result := Result + a;
Result := Result / Length(X);
end;
In theory, the Result
variable may overflow during the computation. To avoid this, you can do instead
function Average(const X: array of Integer): Double;
begin
if Length(X) = 0 then
raise Exception.Create('Cannot compute average of empty array.');
Result := 0;
const F = 1 / Length(X);
for var a in X do
Result := Result + F * a;
end;
And in practice, there's hardly any need to reinvent the wheel (the Math
unit):
function Average(const X: array of Integer): Double;
begin
Result := SumInt(X) / Length(X);
end;