Entwickler-Ecke

Algorithmen, Optimierung und Assembler - Arithmetisches Mittel berechnen


Marco D. - Mo 01.05.06 17:19
Titel: Arithmetisches Mittel berechnen
Hallo,

ich schreibe derzeit an einem Zensuren-Analyse-Programm. Dazu muss ich einige Male das arithmetische Mittel aus z.B. '1,2,3,,4,5,6' berechnen. Dazu habe ich mir folgende Funktion geschrieben:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
function TForm1.ArithMittel(str:string) : integer;
var i:integer; temp:string;
begin
  if Length(str)>0 then
  begin
    temp:='';
    for i := 1 to length(str) do
    begin
      if not (str[i]=','then temp:=temp+str[i];
    end;
    result:=0;
    for i := 1 to Length(temp) do
    begin
      result:=result+strtoint(temp[i]);
    end;
    result:=result div length(temp);
  end;
end;

Jedoch scheinen manchmal falsche Zahlwerte rauszukommen. Kann man diese Funktion vereinfachen und nebenbei dafür sorgen, dass sie alles richtig macht?


der Berliner - Mo 01.05.06 18:29

Hallo, Also ich hab die Function mal Ausprobiert.
Die scheint doch aber richtig zu rechenen.

(1+2+3+4+5+6) DIV 6 = 3

ganz richtig währe narürlich 3,5
das liegt aber wohl am Div

gruß


Marco D. - Mo 01.05.06 18:33

Ja, eigentlich habe ich das Problem schon selber behoben:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
function TForm1.ArithMittel(str:string) : extended;
var i:integer; temp:string;
begin
  if Length(str)>0 then
  begin
    temp:='';
    for i := 1 to length(str) do
    begin
      if not (str[i]=','then temp:=temp+str[i];
    end;
    result:=0;
    for i := 1 to Length(temp) do
    begin
      result:=result+strtoint(temp[i]);
    end;
    result:=result / length(temp);
  end;
end;

Manchmal kommen bei der Zensuren-Analyse aber immer noch total sinnlose Ergebnisse heraus. Aber der Fehler liegt wohl woanders :-(


aim65 - Mo 01.05.06 18:39

Auch wenn die Ausgangsziffern vom Typ Integer sind, kann das Ergebnis ja einen Dezimalbruch darstellen. Daher mußt Du "result" als Floating Point deklarieren und in Zeile 16 folgendes korrigieren:

Delphi-Quelltext
1:
2:
3:
4:
function TForm1.ArithMittel(str:string) : double;  
.
.
    result:=result / length(temp);

Dann müssten Die Ergebnisse ok sein.
Man könnte z.B. die Source-Länge verkürzen, indem man jeden gefundenen Zahlenstring sofort in ein Integer umwandelt, aufaddiert, und dann durch Zahl der gefundenen Zifern teilt.


der Berliner - Mo 01.05.06 18:41

Hat er doch gemacht :D
siehe oben :D
gruß


Marco D. - Mo 01.05.06 18:44

user profile iconaim65 hat folgendes geschrieben:
Auch wenn die Ausgangsziffern vom Typ Integer sind, kann das Ergebnis ja einen Dezimalbruch darstellen. Daher mußt Du "result" als Floating Point deklarieren und in Zeile 16 folgendes korrigieren:

Delphi-Quelltext
1:
2:
3:
4:
function TForm1.ArithMittel(str:string) : double;  
.
.
    result:=result / length(temp);

Dann müssten Die Ergebnisse ok sein.

Was meinst du mit Ausgangsziffern? Habe ich nicht verstanden, was du mir damit sagen willst.
user profile iconaim65 hat folgendes geschrieben:
Man könnte z.B. die Source-Länge verkürzen, indem man jeden gefundenen Zahlenstring sofort in ein Integer umwandelt, aufaddiert, und dann durch Zahl der gefundenen Zifern teilt.

Gute Idee :zustimm: Das nehme ich in die To-Do-Liste mit auf, aber jetzt will ich erstmal an dem richtigen Berechnen der Ergebnisse arbeite.


aim65 - Mo 01.05.06 18:53

@ der Berliner
Hat sich einfach überschnitten :shock:

@ Marco D.
Mit Ausgangsziffern meinte ich Deine Zensuren im String:"1,4,2,3,..." usw.
Kann es sein, daß Du im Zensurenstring evtl. mal ein Komma vergessen hast und dann so was entstand: "1,3,44,,5,222..."? Dann käme natürlich Käse heraus. :wink:
Hab jedenfalls bisher nix Falsches in Deiner Funktion gefunden.


Marco D. - Mo 01.05.06 18:58

Ich schreibe mir erstmal eine Funktion, die überprüft, ob die Zensuren richtig eingegeben wurden (X,X,X,X).


aim65 - Mo 01.05.06 19:03

Hatte ich noch vergessen:
Ich würde auf gültige Zahlen testen. Das würde sicherstellen, daß auch ein Nicht-Kommazeichen unterdrückt wird.


Marco D. - Mo 01.05.06 19:06

Einfache vom ersten Zeichen an jedes zweite durchgehen, und prüfen ob es eine Zahl ist (wie könnte man das machen?)


Marco D. - Mo 01.05.06 19:16

Geht das auch einfacher als so:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
function IsValidMark (C:char) : boolean;
begin
  result:=false;
  if C='1' then result:=true
  else if C='2' then result:=true
  else if C='3' then result:=true
  else if C='4' then result:=true
  else if C='5' then result:=true
  else if C='6' then result:=true
  else result:=false;
end;


delfiphan - Mo 01.05.06 19:25


Delphi-Quelltext
1:
Result := C in ['1'..'6'];                    


aim65 - Mo 01.05.06 19:28

Nee, das wäre zu unsicher (z.B., wenn aus Versehen zwei Kommas kommen). Deine Rouitne ist schon ok. Hab jetzt kein Delphi offen, daher PseudoCode:

for n := 1 to length(str)
if not str[n] in ['1'..'6'] then Schmeiß-Raus
else ZahlenChar in Integer umwandeln, Counter erhöhen, Zahl aufaddieren

Ich weiß, sieht grausam aus, aber Du kriegst den Sinn wohl raus.
Kannst die Abfrage auch positiv machen, dann if und else-Inhalt vertauschen.


delfiphan - Mo 01.05.06 19:41


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
function calcAvg(S: String): Extended;
var
 I, Sum: Integer;
begin
 with TStringList.Create do
  try
   Delimiter := ',';
   DelimitedText := S;
   Sum := 0;
   for I := 0 to Count-1 do
    inc(Sum, StrToInt(Strings[I]));
   if Count = 0 then
    raise EInvalidOp.Create('Cannot calculate mean of an empty set.');
   Result := Sum/Count;
  finally
   Free;
  end;
end;

procedure TForm1.ButtonClick(Sender: TObject);
var
 Input: String;
begin
 Input := '1, 2, 3';
 try
  ShowMessage(Format('Der Mittelwert lautet %.1f',[calcAvg(Input)]));
 except
  on E:Exception do
    MessageDlg('Fehlerhafte Eingabe.', mtError, [mbOk], 0);
 end;
end;


Marco D. - Mo 01.05.06 19:41

Danke! Das klappt erstmal :zustimm: