C kleinsten wert aus schleifenergebnis ermitteln

TRBN

Cadet 2nd Year
Registriert
Nov. 2015
Beiträge
22
Hallo,
seid stunden bin ich nun am überlegen, wie ich das folgende Problem lösen kann. Aber leider komme ich zu keinem Ansatz.

Ich erzeuge mit der folgenden for-schleife diese Tabelle:
tabelle.PNG
Code:
    for (float schrittweite = x_min; schrittweite < x_max + x;) {
        float wegA_x0 = sqrt((pktA_y * pktA_y)+(schrittweite * schrittweite));
        float zeitA_x0 = wegA_x0 / v_s;
        float wegx0_B = sqrt(pow(pktB_x - schrittweite, 2) + pow(pktB_y, 2));
        float zeitx0_B = wegx0_B / v_m;
        float summeWeg = wegA_x0 + wegx0_B;
        float summeZeit = zeitA_x0 + zeitx0_B;
        printf(" %.2f\t\t| %.2f \t | %.2f\t| %.2f\t\t | %.2f\t| %.2f\t\t | %.2f\n", schrittweite,
                wegA_x0, zeitA_x0 + 10, wegx0_B, zeitx0_B, summeWeg, summeZeit);
        schrittweite = schrittweite + x;        
    }

Nun möchte ich die kleinste Zahl in der Spalte summeZeit mit einem X markieren.
Minimalwert, Maximalwert und Schrittweite kann man per Eingabe einstellen. Man weiß also nicht wie viele Zeilen zu untersuchen sind....

Kann mir jemand helfen wie ich die kleinste Zahl mit einem X markieren kann? Alles andere habe ich ohne große Probleme hinbekommen. Aber hierbei scheitere ich :(

Gruß Torben
 
Du musst dir alle Werte zwischenspeichern und dabei den kleinsten Wert merken.
In einem weiteren Schritt gibt du alles aus und schreibst ein "x" bei Übereinstimmung des Wertes dazu.
 
zwischenspeichern wie schon gesagt und Index gleich merken vom kleinsten Wert, ganz schnell getippt:
Code:
idx=0;
summeZeitMin=10000;
for (float schrittweite = x_min; schrittweite < x_max + x;) {
	...
	summeZeit[idx] = zeitA_x0 + zeitx0_B;
	if(summeZeit[idx]<summeZeitMin)summeZeitMin=summeZeit[idx]; idxMerk=idx;
    schrittweite = schrittweite + x;        
	idx++;
}
for(int i=0;i<idx;i++){
	        if(idxMerk==i){
				printf(" %.2f\t\t| %.2f \t | %.2f\t| %.2f\t\t | %.2f\t| %.2f\t\t | %.2f X \n", schrittweite,
					wegA_x0[idx], zeitA_x0[idx] + 10, wegx0_B[idx], zeitx0_B[idx], summeWeg[idx], summeZeit[idx]);
			}
			else{
			printf(" %.2f\t\t| %.2f \t | %.2f\t| %.2f\t\t | %.2f\t| %.2f\t\t | %.2f\n", schrittweite,
					wegA_x0[idx], zeitA_x0[idx] + 10, wegx0_B[idx], zeitx0_B[idx], summeWeg[idx], summeZeit[idx]);
			}

}

Gruß
 
Um den kleinsten Wert festzustellen muss man nun auch nicht alle Werte zwischen speichern. Zumindest ist es nicht optimal es so zu tun (bei kleinen Tabellen ist es zwar egal). Eine andere Möglichkeit wäre einfach in einer weiteren Schleife setzt du zunächst einen Wert "min" auf meinetwegen 9999999 und überprüfst nun in jedem Schleifendurchlauf, ob der aktuelle Tabellenwert kleiner ist als der Wert "min". Wenn ja überschreibst du den Wert "min" mit dem neuen Wert und machst mit dem nächsten Element weiter. Wenn der Wert größer war machst du nichts. Am Ende der Schleife hat man nun also den minimalen Wert ermittelt. Natürlich kann man auch relativ einfach sich dann die Reihe merken, in der man dann einfach das X hinzufügt.
 
Vielen Dank schon mal für eure Hilfe,
jetzt habe ich zwar schon mal ein X eingefügt.
Allerdings stimmt die Schrittweiten-Spalte noch nicht.
Meine Tabelle sieht momentan so aus:
Tabelle3.PNG


hier der Code-ausschitt dazu:
Code:
    printf("Schrittweite [m]| Weg A - x0 [m] | Zeit   [sec] | Weg B - x0 [m] | "
            "Zeit  [sec]  |Summe Weg A+B[m]| Summe Zeit A+B [sec]\n");
    printf("---------------------------------------------------------------------------------------------------------------------\n");
    int idx = 0;
    int summeZeitMin = 9999;
    int idxMerk;
    float wegA_x0[idx], zeitA_x0[idx], wegx0_B[idx], zeitx0_B[idx], summeWeg[idx], summeZeit[idx], schrittweite [idx];
    for (schrittweite[idx] = x_min; schrittweite[idx] < x_max + x;) {
        wegA_x0[idx] = sqrt((pktA_y * pktA_y)+(schrittweite[idx] * schrittweite[idx]));
        zeitA_x0[idx] = wegA_x0[idx] / v_s;
        wegx0_B[idx] = sqrt(pow(pktB_x - schrittweite[idx], 2) + pow(pktB_y, 2));
        zeitx0_B[idx] = wegx0_B[idx] / v_m;
        summeWeg[idx] = wegA_x0[idx] + wegx0_B[idx];
        summeZeit[idx] = zeitA_x0[idx] + zeitx0_B[idx];
        if (summeZeit[idx] < summeZeitMin) {
            summeZeitMin = summeZeit[idx];
            idxMerk = idx;
        }
        schrittweite [idx] = schrittweite[idx] + x;
        idx++;
    }

    /*Ausgabe*/
     for (int i = 0; i < idx; i++) {
        if (idxMerk == i) {
            printf(" %14.2f | %14.2f | %11.2f | %14.2f | %16.2f | %10.2f | %6.2f X \n", schrittweite[i],
                    wegA_x0[i], zeitA_x0[i] + 10, wegx0_B[i], zeitx0_B[i], summeWeg[i], summeZeit[i]);
        } else {
            printf(" %14.2f | %14.2f | %11.2f | %14.2f | %16.2f | %10.2f | %6.2f\n", schrittweite[i],
                    wegA_x0[i], zeitA_x0[i] + 10, wegx0_B[i], zeitx0_B[i], summeWeg[i], summeZeit[i]);
        }
    }

ich denke, dass ich die variable Schrittweite der Ausgabeschleife falsch übergebe?
ich komme allerdings nicht darauf wie es richtig geht. Aber vlt liegt mein Fehler auch wo anders?
 

Anhänge

  • tabelle2.PNG
    tabelle2.PNG
    33,4 KB · Aufrufe: 228
Eine andere Möglichkeit wäre einfach in einer weiteren Schleife setzt du zunächst einen Wert "min" auf meinetwegen 9999999
Nein, tut man nicht. Den setzt man auf einen Wert, der garantiert nicht kleiner ist als der kleinste Datenwert - also entweder auf den maximalen Wert, den der Datentyp annehmen kann, oder (noch besser) auf den ersten Datenwert. Alles andere wird einem früher oder später um die Ohren fliegen, wenn man doch mal mit anderen Eingabedaten arbeitet.
 
VikingGe schrieb:
Nein, tut man nicht. Den setzt man auf einen Wert, der garantiert nicht kleiner ist als der kleinste Datenwert - also entweder auf den maximalen Wert, den der Datentyp annehmen kann, oder (noch besser) auf den ersten Datenwert

Code:
   int size = (x_max + x - x_min) / x;

/edit nach 30 min copy/paste: Das ist imho nicht optimal mit Arrays zu machen, insbesodere in C. Daher anderer Vorschlag (extra-Funktion in 2 Modi - 1x Check 1 x Ausgabe):
Code:
#include<math.h>
#include<stdio.h>

float loop_min(float x_min, float x_max, float pktA_x, float pktA_y, float pktB_x, 
               float pktB_y, float v_s, float v_m, float x, float summeZeitMin, 
               int doPrint)
{
 for (float schrittweite = x_min; schrittweite<x_max + x; schrittweite += x) {
    float wegA_x0 = sqrt((pktA_y*pktA_y) + (schrittweite*schrittweite));
    float zeitA_x0 = wegA_x0 / v_s;
    float wegx0_B = sqrt( (pktB_x - schrittweite)*(pktB_x - schrittweite) 
                                       + pktB_y*pktB_y );
    float zeitx0_B = wegx0_B / v_m;
    float summeWeg = wegA_x0 + wegx0_B;
    float summeZeit = zeitA_x0 + zeitx0_B;
    if (doPrint) {
       char cflag = summeZeitMin == summeZeit ? 'X' : ' ';
       printf(" %.2f\t\t| %.2f \t | %.2f\t| %.2f\t\t | %.2f\t| %.2f\t\t | %.2f| %c\n",
              schrittweite, wegA_x0, zeitA_x0 + 10, wegx0_B, zeitx0_B,
              summeWeg, summeZeit, cflag);
    }
    else if (summeZeitMin > summeZeit)
       summeZeitMin = summeZeit;
 }
 return summeZeitMin;
}

int main()
{
 float x_min = 10, x_max = 15;
 float pktA_x = 0, pktA_y = -20;
 float pktB_x = 50, pktB_y = 30;
 float v_s = 3, v_m = 1.5, x = 1;

 /* ZMin bestimmen / doPrint = 0 / ZMin auf 1e13 */
 float ZMin=loop_min(x_min, x_max, pktA_x, pktA_y, pktB_x, pktB_y, v_s, v_m, x, 1e13, 0);
 /* ZMin mit ausgeben / doPrint = 1 */
 loop_min(x_min, x_max, pktA_x, pktA_y, pktB_x, pktB_y, v_s, v_m, x, ZMin, 1);

 return 0;
}
 
Zuletzt bearbeitet:
wie genau meinst du das mit dem ersten datenwert?
Angenommen, wir wollen das Minimum der Werte in einem Array ermitteln. Dann sähe eine mögliche Implementierung zum Beispiel so aus:

Code:
int min(int* numbers, size_t count) {
  int result = numbers[0];
  for (size_t i = 1; i < count; i++)
    result = numbers[i] < result ? numbers[i] : result;
  return result;
}

Also den "min"-Wert mit dem ersten Wert aus dem Array initialisieren, nicht mit irgendeiner Konstanten. Alternativ INT_MAX aus <limits.h> verwenden:

Code:
int min(int* numbers, size_t count) {
  int result = INT_MAX;
  for (size_t i = 0; i < count; i++)
    result = numbers[i] < result ? numbers[i] : result;
  return result;
}

Wobei beide Varianten ihre Einsatzgebiete haben. Variante 1 ist besonders dann sinnvoll, wenn du einen Typen ohne fest definierten Maximalwert hast, und Variante 2 dann, wenn du das Minimum auf leeren Eingabemengen als "Unendlich" definieren willst. Bei int ist weder das eine, noch das andere der Fall.

Aber Variante 2 ist in diesem Fall vielleicht doch die bessere (weil einfachere) Variante, auch wenn ich anfangs etwas anderes gesagt habe, weil dort nie ein illegaler Speicherzugriff entstehen kann (wenn count == 0). Das Ergebnis ist für den Fall dann nur eben nicht wirklich sinnvoll, aber das ist hier für die weitere Behandlung egal.

TL;DR: Sorge dafür, dass deine Funktionen auf allen möglichen Eingaben, die sinnvolle Voraussetzungen erfüllen, funktioniert. Die Voraussetzung, dass alle Werte kleiner als 9999 sein müssen, damit das Minimum am Ende stimmt, ist keine sinnvolle Voraussetzung.

Klar muss man den Fall count == 0 irgendwie vermeiden oder gesondert behandeln, aber das sollte man in beiden Fällen, weil das Minimum auf leeren Integer-Mengen gar nicht definiert ist.


Ich hätte da übrigens noch ein kleines Problem in deinem Code entdeckt:
Code:
int idx = 0;
[...]
float wegA_x0[idx] [...];
Du erstellst quasi Arrays mit der Länge 0, greifst danach aber auf Elemente aus diesen leeren Arrays zu. Das funktioniert nicht und das dürfte auch der Grund sein, warum deine Tabelle nicht stimmt.
 
Danke für den Code ohne Arrays. An sich verstehe ich auch jeden Teil vom Code.
Nur folgende Zeile verstehe ich nicht genau:
Code:
char cflag = summeZeitMin == summeZeit ? 'X' : ' ';
Wie genau lässt sich diese Zeile in "normaler Sprache" interpretieren?

Gruß
Torben
Ergänzung ()

Ich habe das Programm jetzt so umgebaut, dass Schrittweite, x_min und x_max vom Nutzer eingegeben werden und auf Plausibilität überprüft werden. Das klappt auch soweit alles.
Jetzt möchte ich dem Nutzer am Ende die Möglichkeit geben, das Programm neu zu starten. Dazu dachte ich mir, nutze ich eine do-while Schleife. Denn das Programm soll ja erst einmal ausgeführt werden, und dann erst soll der Nutzer entscheiden ob das Programm neugestartet werden soll.

Code:
float loop_min(...){
     ....
}

int main(int argc, char** argv) {
    ...
    //Initialisieren der Variablen
    ...

    char restart = 'n';
    do {
        printf("\t\tBAYWATCH\n\n");
        printf("Startpunkt = (%.2f|%.2f)\n", pktA_x, pktA_y);
        printf("Endpunkt = (%.2f|%.2f)\n", pktB_x, pktB_y);
       ...
        //Abfrage der fehlenden Daten
        ...

        ...
        //Ausgabe mit loop_min-funktion 
        printf("\nProgramm neu Starten? [j = ja | n = nein] ");
        scanf("%c",&restart);
        
    } while (restart == 'j');
    return (EXIT_SUCCESS);
}

Leider komme ich aber nicht zur Eingabe, da das Programm vorher schon beendet wird. Wo liegt jetzt schon wieder mein Denkfehler?
 
Zuletzt bearbeitet: ([B] Tag im Code funktioniert scheinbar nichht)
Die obige Zeile weist, wenn mich nicht alles täuscht, cflag das Ergebnis dieses if-Konstrukts zu.
D.h. wenn summeZeitMin und summeZeit gleich sind, wird cflag zu 'X', sonst zu ' ' (Leerzeichen)
 
Muss es eigentlich zwangsläufig Plain-C sein oder ist auch C++ erlaubt? Dann könnte man das ganze effektiver erledigen indem man die Standardlib mit einbindet.
 
In C++ muss man sich eigentlich nur mit Closures austoben, um das Problem mit wenig Code zu lösen.

Code:
template<typename Fn>
void processTable(ganz viele Parameter, const Fn& fn) {
  for (...) {  // Schleife, die die Zeilen generiert
    [...]
    fn(spalte1, ..., summeZeit, ..., spalten);
  }
}

// Minimum finden
float summeZeitMin = std::numeric_limits<float>::max();
processTable(..., [&summeZeitMin] (..., float summeZeit, ...) {
  summeZeitMin = std::min(summeZeitMin, summeZeit);
});

// Ausgabe
processTable(..., [summeZeitMin] (..., float summeZeit, ...) {
  std::cout << spalte1 << ... << summeZeit << ... << spalten << " | "
            << summeZeit == summeZeitMin ? "X" : " " << std::endl;
});

Im Grunde werden also in der processTable-Funktion die einzelnen Zeilen berechnet, aber was damit passieren soll, wird erst in der als Paramteter übergebenen Funktion definiert.

Ein C-Äquivalent wäre es, das ganze mit eine Funktionspointer + User-Pointer zu machen, der an die Funktion übergeben wird, das wird dann aber codemäßig extrem unschön.
 
Zuletzt bearbeitet:
Zurück
Oben