Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Auf einen standartisierten Wert aufrunden (https://www.delphipraxis.net/64286-auf-einen-standartisierten-wert-aufrunden.html)

rebellpk 1. Mär 2006 18:32


Auf einen standartisierten Wert aufrunden
 
Hallo Leute,
ich bin neu hier und schon komme ich mit einem Problem :wink:
Ich schreibe grad ein kleines Programm, bei dem ich einen bereits errechneten Wert auf den nächst höheren Wert (die Werte sind festgelegt) runden möchte.
Hier mal ein symbolisches Beispiel:

festgelegte Werte:
10
11
13
16
17

Aufgabe:
x + y = 13,2
Ergebnisausgabe soll aber 16 sein da der nächsthöhere mögliche Wert ist 16

Ich hoffe es ist verständlich was ich will :wink:

marabu 1. Mär 2006 18:51

Re: Auf einen standartisierten Wert aufrunden
 
Herzlich willkommen in der Delphi-PRAXiS.

Da deine Ergebnisse Float-Werte sind, welche auf einen Integer-Wert abgebildet werden sollen, brauchst du zuerst eine Funktion, die dir die kleinste Ganzzahl liefert, welche größer oder gleich deinem Ergebnis ist. Suche in der Delphi-Hilfe nach Ceil.

Dann ist es zweckmäßig, wenn die Bildwerte deiner Abbildung aufsteigend sortiert vorgehalten werden - wie du es schon zeigst. Da die Bildwerte nicht lückenlos sind, musst du dir eine eigene Ceil-Funktion schreiben, die den oben beschriebenen Wert durch Suchen in der geordneten Bildmenge ermittelt. Ein naiver Ansatz wäre die schrittweise Suche. Ein etwas professionellerer Ansatz ist die binäre Suche (binary search).

Freundliche Grüße vom marabu

rebellpk 1. Mär 2006 19:40

Re: Auf einen standartisierten Wert aufrunden
 
Das mit der Ceil-Funtion wäre geschaft...

Zitat:

Da die Bildwerte nicht lückenlos sind, musst du dir eine eigene Ceil-Funktion schreiben, die den oben beschriebenen Wert durch Suchen in der geordneten Bildmenge ermittelt.
Wie soll ich hier ran gehen?

marabu 1. Mär 2006 20:16

Re: Auf einen standartisierten Wert aufrunden
 
Ich habe dir zwei Wege aufgezeigt - am Bach lang oder über den Berg. Du musst dich nur entscheiden.

marabu

rebellpk 2. Mär 2006 12:26

Re: Auf einen standartisierten Wert aufrunden
 
Sorry, dafür muss ich aber erstmal laufen lernen...

Ich kenn mich noch nicht so gut mit Delphi aus.

Ich stelle mir das so vor:

Delphi-Quellcode:
var
StdWidst: array [0..23] of integer;
   StdWidst[0] = 10;
   StdWidst[1] = 11;
   StdWidst[2] = 12;
   StdWidst[3] = 13;
   StdWidst[4] = 15;
   StdWidst[5] = 16;
   StdWidst[6] = 18;
   StdWidst[7] = 20;
   StdWidst[8] = 22;
   StdWidst[9] = 24;
   StdWidst[10] = 27;
   StdWidst[11] = 30;
   StdWidst[12] = 33;
   StdWidst[13] = 36;
   StdWidst[14] = 39;
   StdWidst[15] = 43;
   StdWidst[16] = 47;
   StdWidst[17] = 51;
   StdWidst[18] = 56;
   StdWidst[19] = 62;
   StdWidst[20] = 68;
   StdWidst[21] = 75;
   StdWidst[22] = 82;
   StdWidst[23] = 91;
Weiß echt nicht wie ich das angehen soll...

Grishnak 2. Mär 2006 12:45

Re: Auf einen standartisierten Wert aufrunden
 
Ich würde im Array nach der ersten Zahl suchen, die größer als meine ungerundete Zahl ist (dazu sollte das Array als letzte Zahl einen "Stopper" erhalten "StdWidst[24]:=High(integer);"). Anschließend die Differenz zu dieser und zur nächstkleineren Zahl bestimmen. Dann von den beiden die Zahl nehmen, wo die Differenz am kleinsten ist.

rebellpk 2. Mär 2006 12:53

Re: Auf einen standartisierten Wert aufrunden
 
Ok, danke!
Aber so wie ich das oben auf geführt habe kann es ja schon nicht richtig sein.

[Fehler] Widerstand.pas(51): Bezeichner redefiniert: 'StdWidst'

wo liegt hier der Fehler?

Grishnak 2. Mär 2006 13:09

Re: Auf einen standartisierten Wert aufrunden
 
Delphi-Quellcode:
var
  StdWidst: array [0..23] of integer = (10, 11, 12, 13, 15 ... 91);
oder

Delphi-Quellcode:
var
  StdWidst: array [0..23] of integer;

...

procedure TForm1.FormCreate(Sender: TObject);
begin
  StdWidst[0]:=10;
  StdWidst[1]:=11;
  StdWidst[2]:=12;

...

  StdWidst[23]:=91;
end;

Amateurprofi 2. Mär 2006 13:34

Re: Auf einen standartisierten Wert aufrunden
 
Versuch es mal hiermit.
In Edit1 gibst Du Deinen Wert ein, wenn dur die Enter-Taste drrückst sollte der (evtl. nächsthöhere) Standardwert in Edit2 stehen.
Hab ich nicht vollständig getestet......

Gruß, Klaus

Delphi-Quellcode:
const StdWidst:array [0..23] of integer=(10,11,12,13,15,16,18,
         20,22,24,27,30,33,36,39,43,47,51,56,62,68,75,82,91);

FUNCTION FindValue(const data:array of integer; value:integer):integer;
var first,last,actual:integer;
begin
   first:=Low(data);
   last:=High(data);
   repeat
      actual:=(first+last) shr 1;
      result:=data[actual];
      if result<value then first:=actual+1
         else if result>value then last:=actual-1
            else exit;
   until first>last;
   if first<=High(data) then result:=data[first];
end;

procedure TMain.Edit1KeyPress(Sender: TObject; var Key: Char);
var v:extended; vc:integer;
begin
   if key=#13 then begin
      val(edit1.Text,v,vc);
      edit2.text:=IntToStr(FindValue(StdWidst,ceil(v)));
   end else begin
      edit2.text:='';
   end;
end;

rebellpk 2. Mär 2006 15:52

Re: Auf einen standartisierten Wert aufrunden
 
Danke Klaus!
Aber könnetest du mir das ganze schrittweise erklären?
Das wäre echt super... denn einfach den Q-Text kopieren und drin rum fuschen bringt mich ja nicht wirklich weiter :wink:

Amateurprofi 2. Mär 2006 18:35

Re: Auf einen standartisierten Wert aufrunden
 
Ja, erkläre ich gern.
Zuvor aber noch ein Hinweis:
Die Funktion FindValue ist eigentlich konzipiert zum Auffinden von Daten in
größeren Datenbeständen. Stelle Dir vor, Du hättest eine Datei mit sagen wir
2 Milliarden Einträgen und suchst einen bestimmten Eintrag.
Mit einer sequentiellen Suche müßtest Du dann im worst case 2 Milliarden Einträge
prüfen, was eine gewisse Zeit in Anspruch nimmt. FindValue würde maximal
31 Zugriffe brauchen um einen Datensatz zu finden, oder festzustellen, daß der gesuchte
Datensatz nicht existiert.
Voraussetzung für den Einsatz dieser Methode ist, daß die Daten aufsteigend sortiert
sind.
Für kleinere Datenmengen ist eine sequentielle Suche schneller, andererseits spielt dann
das Zeitverhalten keine Rolle.

Wie funktioniert das? :

Am Anfang der Routine wird first auf den ersten und last auf den letzten Eintrag
des Arrays gestellt. Irgendwo im Bereich first..last liegt der gesuchte Eintrag
(es sei denn er existiert nicht).
Dann beginnt in der repeat until Schleife die Suche:
actual wird in die Mitte zwischen first und last gestellt und result erhält den
an dieser Stelle liegenden Wert.
Wenn dieser Wert kleiner ist, als der gesuchte Wert, dann liegt der gesuchte Wert
offensichlich "hinter" actual, also wird first auf actual+1 gestellt.
Ist dieser größer als der gesuchte Wert, dann liegt der gesuchte Wert "vor" last,
also wird last auf actual-1 gestellt.
Die dritte Möglichkeit ist, daß result=gesuchter Wert ist, dann wird die Funktion
verlassen.
Dieses Spiel wird so lange wiederholt, bis first größer ist, als last. Da der
gesuchte Wert immer "bei" oder "hinter" first, und "bei" oder "vor" last liegt,
bedeutet first>last, daß der gesuchte Eintrag nicht existiert.
Wann tritt diese Abbruchbdingung ein?:
Genau dann, wenn first=last war (dann war first=actual=last) und entweder
first auf actual+1 oder last auf actual-1 gestellt wurde.
Was gilt für den Eintrag auf den jetzt first zeigt?:
Wir wissen :
Entweder wurde first auf actual+1 gestellt, weil data[actual]<gesuchter Wert war,
dann steht first jetzt auf dem nächsthöheren Wert.
Oder last wurde auf actual-1 gestellt, weil data[actual]>gesuchter Wert war, dann
steht first jetzt ebenfalls auf dem nächsthöheren Wert.
Dieser Wert (wenn first noch in den Bereich des Arrays zeigt) wird dann in result
gestellt.

Falls Du den nicht den nächsthöheren, sondern den nächstkleineren Wert haben
möchtest, muß die letzte Zeile der Funktion heißen
Delphi-Quellcode:
if last>=Low(data) then result:=data[last];
Als letztes noch :
Wenn der gesuchte Wert kleiner ist, als der erste Eintrag im Array, dann wird der
erste Eintag im Array zurückgegeben, andererseits, wenn der gesuchte Wert größer ist,
als der letzte Eintrag im Array, dann wird der letzte Eintrag im Array zurückgegeben.
Sinnvoll wäre also, den ersten Eintrag im Array auf 0 und den letzten Eintrag
(wie von Grishnak vorgeschlagen) auf maxint (=High(integer)) zu setzen.

marabu 2. Mär 2006 20:05

Re: Auf einen standartisierten Wert aufrunden
 
Hallo Leute,

ein paar Anmerkungen noch. Es handelt sich hier um eine E24 Widerstandsdekade. Naturgemäß fallen nicht alle R-Werte in die gewählte Dekade. Deshalb müssen die Ausgangswerte zuerst auf die Dekade normiert werden. Ist der gesuchte Wert größer als das Maximum der Dekade, dann ist das Minimum der nächst höheren Dekade der gewünschte Wert.

Die Abbildungsfunktion macht es erforderlich, dass, wird der gesuchte Wert nicht gefunden, der Nachfolger geliefert wird. Das ist dann genau der Wert mit dem Index "lower bound".

Werden trotz allem falsche Werte geliefert, dann liegt es an Rechenungenauigkeiten durch Verwendung von Fließkommazahlen.

Grüße vom marabu


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:14 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