Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi durchschnittszeit ermitteln (https://www.delphipraxis.net/152112-durchschnittszeit-ermitteln.html)

arest 11. Jun 2010 12:58

durchschnittszeit ermitteln
 
Hallo an alle,
ich bin gerade dabei mir eine Stoppuhr zu programmieren. Die läuft bis jetzt auch ganz wunderbar. Als zusätzliches Feature hatte ich nun geplant, dass man eine Durchschnittszeit ausrechnen lassen kann. Dabei möchte ich aus 10 Durchläufen den Durchschnitt ermitteln. Meine Überlegung war jetzt, dass man im Falle einer Aktivierung (z.b. über eine Checkbox) der Option "Durchschnitt ermitteln" damit beginnt zehn Variablen mit den entsprechenden Werten zu füllen. Diese Werte sollen dann durch die Anzahl der bereits gefüllten Variablen geteilt werden... Soweit denk ich absolut logisch?

Ich geb euch hier jetzt erstmal den Code, mit dem ich die Zeit stoppe:

Delphi-Quellcode:
procedure TForm1.StartClock;
begin
  ClockStarted := True;
  TimeStarted := GetTickCount;
  repeat
    TimeElapsed := GetTickCount-TimeStarted;
    Label1.Caption := TicksToTime(TimeStopped+TimeElapsed);
    application.ProcessMessages; // damit sich das Programm nicht "aufhängt"
    if application.Terminated then // Falls die Anwendung inzwischen beendet wurde
      exit;
    sleep(1); // 100% CPU-Auslastung vermeiden
  until not ClockStarted;
end;


procedure TForm1.StoppClock;
begin
  ClockStarted := False;
  TimeStopped := getTickcount-TimeStarted + TimeStopped;
  Label1.Caption := TicksToTime(TimeStopped);
end;


function TicksToTime(TickCount: cardinal): string;
begin
  result := Format('%.2d:%.2d:%.2d',
    [TickCount div 1000 div 60,  // Minuten
     TickCount div 1000 mod 60,  // Sekunden
     TickCount mod 1000 div 10]); // Hundertstel
end;
Wie ihr seht, fülle ich in dem Fall noch keine Variable um die gestoppte Zeit anzuzeigen, sondern lasse es einfach nur ein einem Label anzeigen. Mein Problem ist nämlich, dass ich nicht sicher bin, welche Art von Variable ich am besten nehme.. Falls jemand lust hat ein wenig zu coden, dann freue ich mich über fertige Codezeilen :P Hab mit der SuchFunktion leider keine entsprechenden Ergebnisse gefunden :(

Mit besten Grüßen

jfheins 11. Jun 2010 13:01

AW: durchschnittszeit ermitteln
 
Eine Variable "Avg" für den bisherigen Durchschnitt und eine Variable "n" für die Anzhal der Zeiten, die bisher eingeflossen sind.

Wenn eine Zeit dazukommt, kannst du einfach sowas machen:

Avg := (Avg * n + Time)/(n+1)
n := n + 1;

arest 11. Jun 2010 13:15

AW: durchschnittszeit ermitteln
 
welche art von variable sollte ich denn nehmen für avg?

mkinzler 11. Jun 2010 13:20

AW: durchschnittszeit ermitteln
 
Kommt darauf an, welchen Typ die Werte habe von denen du den Durchschnitt ermittelst.

In diesem Fall TTime

himitsu 11. Jun 2010 13:25

AW: durchschnittszeit ermitteln
 
TTime?
für AVG Single oder Double.


Und falls man es anders speichert, z.B. Integer, Cardinal oder Int64:

Cardinal = maximal 49,7 Tage

Delphi-Quellcode:
var Sum, Count: Cardinal;

// Neues hinzufügen
Inc(Sum, TimeElapsed );
Inc(Count);

// für's Anzeigen
Avg := Sum div Count;

shmia 11. Jun 2010 13:56

AW: durchschnittszeit ermitteln
 
Hier mal eine Klasse, die aufgrund der Formel aus Betrag#2 arbeitet.
Wenn man einen Durchschnitt berechnet, dann kommt als Datentyp eigentlich nur ein Fliesskommatyp in Frage.
Delphi-Quellcode:
type
  TDurchschnitt = class(TObject)
  private
    FAvg : Extended;
    FCount : Integer;
    function GetAverage: Extended;
    function GetCount: Integer;

  public
    procedure AddValue(value:Extended);
    procedure RemoveValue(value:Extended);
    procedure Clear;

    property Average:Extended read GetAverage;
    property Count:Integer read GetCount;
  end;

procedure TDurchschnitt.AddValue(value: Extended);
begin
   FAvg := (FAvg * FCount + Value)/(Count+1);
   Inc(FCount);
end;

procedure TDurchschnitt.RemoveValue(value: Extended);
begin
   if FCount > 1 then
   begin
      FAvg := (FAvg * FCount - Value)/(Count-1);
      Dec(FCount);
   end
   else
      Clear;
end;


procedure TDurchschnitt.Clear;
begin
   FAvg := 0.0;
   FCount := 0;
end;

function TDurchschnitt.GetAverage: Extended;
begin
   Result := FAvg;
end;

function TDurchschnitt.GetCount: Integer;
begin
   Result := FCount;
end;

arest 11. Jun 2010 23:41

AW: durchschnittszeit ermitteln
 
hmmmm, ich muss leider sagen, dass mir die antworten nur sehr begrenz weitergeholfen haben... :( jemand der wirklich plan vom programmieren hat, der kann damit sicher einiges anfangen, aber da ich ziemlicher rookie bin......
vielleicht erbarmt sich irgendein großherziger mensch einen auf meinen code angepassten teil für mich zu posten?! ich leg einfach mal den rest vom code mit offen:
Delphi-Quellcode:

function TicksToTime(TickCount: cardinal): string;
begin
  result := Format('%.2d:%.2d:%.2d',
    [TickCount div 1000 div 60,  // Minuten
     TickCount div 1000 mod 60,  // Sekunden
     TickCount mod 1000 div 10]); // Hundertstel
end;

procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
  if ClockStarted then
    StoppClock
  else
    StartClock;

end;

procedure TForm1.SpeedButton3Click(Sender: TObject);
begin
  ResetClock;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  ClockStarted := False;
  TimeStarted := 0;
  TimeStopped := 0;
end;

procedure TForm1.ResetClock;
begin
  StoppClock;
  TimeStopped := 0;
  Label1.Caption := TicksToTime(0); // = '00:00:00'
end;

procedure TForm1.StartClock;
begin
  ClockStarted := True;
  TimeStarted := GetTickCount;
  repeat
    TimeElapsed := GetTickCount-TimeStarted;
    Label1.Caption := TicksToTime(TimeStopped+TimeElapsed);
    application.ProcessMessages; // damit sich das Programm nicht "aufhängt"
    if application.Terminated then // Falls die Anwendung inzwischen beendet wurde
      exit;
    sleep(1); // 100% CPU-Auslastung vermeiden
  until not ClockStarted;
end;

procedure TForm1.StoppClock;
begin
  ClockStarted := False;
  TimeStopped := getTickcount-TimeStarted + TimeStopped;
  Label1.Caption:= TicksToTime(TimeStopped);
end;
die abfrage sollte nun sein: wenn checkbox aktiv, dann.... variablen der reihe nach füllen und gleichzeitig den durchschnitt ermitteln. andernfalls variablen nicht belegen, bzw. sobald unchecked, dann leeren. (die abfrage schaff ich grade noch selbst^^ nur den darin enthaltenen inhalt dann leider nicht mehr so ganz :/ )

danke schon mal für alle weiterführenden antworten!

arest 13. Jun 2010 14:49

AW: durchschnittszeit ermitteln
 
Delphi-Quellcode:
procedure TForm1.ResetClock;
begin
  if Label1.Caption <> '00:00:00'
  then begin
          ClockStarted := False;
          TimeStopped := getTickcount-TimeStarted + TimeStopped;
          TimeStopped := 0;
          Label1.Caption := TicksToTime(0); // = '00:00:00'
          if RadioButton1.Checked=true
          then begin
                 inc(n);
                 if n>10
                 then begin
                         antwort:=form3.ShowModal;
                         if antwort=mrok
                         then begin
                                 n:=1;
                              end
                         else begin
                                 //asdf
                              end;
                      end
               end

       end

end;

procedure TForm1.StartClock;
begin
  ClockStarted := True;
  TimeStarted := GetTickCount;
  repeat
    TimeElapsed := GetTickCount-TimeStarted;
    Label1.Caption := TicksToTime(TimeStopped+TimeElapsed);
    application.ProcessMessages; // damit sich das Programm nicht "aufhängt"
    if application.Terminated then // Falls die Anwendung inzwischen beendet wurde
      exit;
    sleep(1); // 100% CPU-Auslastung vermeiden
  until not ClockStarted;
end;

so ich habe dann mal ein wenig dran rumgebastelt.. es läuft soweit erstmal, dass er schritt für schritt die einzelnen captions füllt, aber wenn ich es als variablen haben möchte, gibts immer probleme :(

im code zu sehen, dass ich immer erst beim reset der uhr den zähler n erhöhe, damit die zeit, wenn ich nur pausiere und dann weiter laufen lasse weiterhin im gleichen label landet und nicht als nächste zeit für den zu ermittelnden durchschnitt ist... die abfrage prüft dann, ob die bereits zehn gefüllten zeiten überschrieben werden sollen, eigentlich unwichtig für mein problem!
beim startclock hab ich auch keinerlei probleme.. es hängt immer beim stopclock! da taucht immer ein runtime error auf :/ ich hatte es vorher mal probiert einfach nur in labels zu füllen, damit ich zumindest erst mal alle zeiten habe.. später wollte ich die dann in variablen umwandeln (im ansatz eigentlich falsch, ist mir klar....) zum test hats erst mal geklappt... das sah dann so aus:

Delphi-Quellcode:
if n=1
then Label14.Caption:=Label1.Caption;
if n=2
then Label15.Caption:=Label1.Caption;
und so weiter.. abgeändert habe ich es dann in folgendes:

Delphi-Quellcode:
procedure TForm1.StoppClock;
begin
  ClockStarted := False;
  TimeStopped := getTickcount-TimeStarted + TimeStopped;
  Label1.Caption:= TicksToTime(TimeStopped);
  if RadioButton1.Checked=true
  then begin
          if n=1
          then zeit1:=StrToTime(Label1.Caption);
               Label14.Caption:=TimeToStr(zeit1);
          if n=2
          then zeit2:=StrToTime(Label1.Caption);
               Label15.Caption:=TimeToStr(zeit2);
          if n=3
          then zeit3:=StrToTime(Label1.Caption);
               Label16.Caption:=TimeToStr(zeit3);
          if n=4
          then zeit4:=StrToTime(Label1.Caption);
               Label17.Caption:=TimeToStr(zeit4);
          if n=5
          then zeit5:=StrToTime(Label1.Caption);
               Label18.Caption:=TimeToStr(zeit5);
          if n=6
          then zeit6:=StrToTime(Label1.Caption);
               Label19.Caption:=TimeToStr(zeit6);
          if n=7
          then zeit7:=StrToTime(Label1.Caption);
               Label20.Caption:=TimeToStr(zeit7);
          if n=8
          then zeit8:=StrToTime(Label1.Caption);
               Label21.Caption:=TimeToStr(zeit8);
          if n=9
          then zeit9:=StrToTime(Label1.Caption);
               Label22.Caption:=TimeToStr(zeit9);
          if n=10
          then zeit10:=StrToTime(Label1.Caption);
               Label23.Caption:=TimeToStr(zeit10);


       //   schnitt:=((zeit1 + zeit2+ zeit3 + zeit4 + zeit5 + zeit6 + zeit7 + zeit8 + zeit9 + zeit10) div n);
       //   Label25.Caption:=TimeToStr(schnitt);
        end
end;
das problem ist, dass er mir dabei jedes mal direkt rausspringt... wo ist der fehler?

arest 13. Jun 2010 14:53

AW: durchschnittszeit ermitteln
 
vergessen zu sagen hab ich...
zeit1-zeit10 sind ttime weswegen er als fehler immer ausspuckt ".... '00:32:19' ist keine gültige Uhrzeit ...."

xZise 13. Jun 2010 15:51

AW: durchschnittszeit ermitteln
 
Du weißt aber schon, dass deine Einrückung – wie soll ich sagen – problematisch ist? Und zwar die Zeilen unter den then werden immer ausgeführt:

So sieht es ungefähr der Compiler:
Zitat:

Zitat von arest (Beitrag 1028526)
Delphi-Quellcode:
if n=1 then zeit1:=StrToTime(Label1.Caption);
Label14.Caption:=TimeToStr(zeit1);
[...]

Ich habe nur einen Zeilenumbruch entfernt und alle Einrückungen entfernt, d.h. die Funktionalität wurde nicht geändert. Was liest du eigentlich aus Label1 aus?

MfG
Fabian

arest 14. Jun 2010 00:32

AW: durchschnittszeit ermitteln
 
okay, ich habe jetzt meine probleme annähernd in den griff bekommen^^ die lösung verläuft im ansatz nicht ideal, aber in diesem fall ist es mir inzwischen egal!

mein problem jetzt, ich habe 10 zeiten in string-variablen gespeichert. so kann ich sie natürlich nicht verrechnen um meinen schnitt rauszubekommen.. die strings sind alle im format 'mm:ss:zz' ich hab im forum schon rausgefunden, dass es mit hilfe von StrToTime und FormatSettings die möglichkeit gibt, dass ich diese variablen in zeiten umwandle, was ich erstens nicht ganz hinbekomme, da mir nicht klar ist, wie das mit formatsettings genau geht und zweitens ist dann die frage, ob ich damit überhaupt einen durchschnitt ermitteln könnte?

denke einfache frage -> wie wandel ich die 10strings in passende variablen um, und wie verrechne ich sie dann miteinander?!

thkerkmann 14. Jun 2010 07:36

AW: durchschnittszeit ermitteln
 
Dein Ansatz sollte genau andersherum sein.

Verwende TTime variablen für die ganze Stoppuhrgeschichte, und nur für die Anzeige verwendest du Labels und die entsprechenden Umwandlungsfunktionen. Dann hast du auch keine Probleme.

Gruss

xZise 14. Jun 2010 08:23

AW: durchschnittszeit ermitteln
 
Als Ergänzung zu Vorposter:
Vermeide einen String oder gar eine Komponente als Zwischenspeicher zu benutzen sondern speichere selber in einer Variable zwischen.

MfG
Fabian

David Martens 14. Jun 2010 20:05

AW: durchschnittszeit ermitteln
 
Also wenn du nicht auf deine 10 Durchläufe pochst dann mach es doch einfach so:

Delphi-Quellcode:
type
  TForm1 = class(TForm)
    btnStart: TButton;
    btnStop: TButton;
    lbl1: TLabel;
    lblZeit: TLabel;
    lbl2: TLabel;
    lbl3: TLabel;
    lblDurchschnitt: TLabel;
    Timer1: TTimer;
    procedure btnStartClick(Sender: TObject);
    procedure btnStopClick(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    fZeit,                      // Variable für die aktuelle Stopuhr
    fZeitCumulativ : extended;  // Variable für die aufaddierten Stopzeiten
    iCount : integer;           // Variable für Anzahl der Stopzeiten
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.btnStartClick(Sender: TObject);
begin
  // Stopuhr startet bei 0 :)
  fZeit := 0;

  // Zeit anzeigen
  lblZeit.Caption := FormatDateTime('hh:nn:ss zzz', fZeit);

  // Timer/Stopuhr starten
  Timer1.Enabled := true;
end;

procedure TForm1.btnStopClick(Sender: TObject);
begin
  // Timer/Stopuhr anhalten
  Timer1.Enabled := false;

  // Zeit zu den Stopzeiten addieren und Anzahl hochsetzen
  fZeitCumulativ := fZeitCumulativ + fZeit;
  inc(iCount);

  // Durchschnitt anzeigen
  lblDurchschnitt.Caption := FormatDateTime('hh:nn:ss zzz', fZeitCumulativ / iCount);

  lbl3.Caption := 'von ' + IntToStr(iCount);
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  // nächsten Zeitpunkt berechnen
  // Timer1.Interval / 1000 gewärleistet immer die richtige Schrittweite egal was im Timer eigestellt ist
  fZeit := fZeit + Timer1.Interval / 1000 / 86400;

  // Zeit anzeigen
  lblZeit.Caption := FormatDateTime('hh:nn:ss zzz', fZeit);
end;
mit folgender .dfm

Delphi-Quellcode:
object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 125
  ClientWidth = 231
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object lbl1: TLabel
    Left = 8
    Top = 8
    Width = 22
    Height = 13
    Caption = 'Zeit:'
  end
  object lblZeit: TLabel
    Left = 16
    Top = 24
    Width = 3
    Height = 13
  end
  object lbl2: TLabel
    Left = 112
    Top = 8
    Width = 64
    Height = 13
    Caption = 'Durchschnitt:'
  end
  object lblDurchschnitt: TLabel
    Left = 120
    Top = 24
    Width = 3
    Height = 13
  end
  object lbl3: TLabel
    Left = 182
    Top = 8
    Width = 21
    Height = 13
    Caption = 'von '
  end
  object btnStart: TButton
    Left = 8
    Top = 56
    Width = 75
    Height = 25
    Caption = 'Start'
    TabOrder = 0
    OnClick = btnStartClick
  end
  object btnStop: TButton
    Left = 8
    Top = 87
    Width = 75
    Height = 25
    Caption = 'Stop'
    TabOrder = 1
    OnClick = btnStopClick
  end
  object Timer1: TTimer
    Enabled = False
    Interval = 10
    OnTimer = Timer1Timer
    Left = 104
    Top = 56
  end
end


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:26 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz