ubuntu--anfaenger
Anmeldungsdatum: 12. Oktober 2013
Beiträge: 1088
Wohnort: Belgien
|
Hallo, Ich habe ein kleines Programm geschrieben das Km/h in min/km Umwandelt und umgekehrt. Um das Berrechnen zu können muss ich einen double in einer ganz Zahl und Komma Zahl Zerlegen. Das Programm arbeitet richtig so lange die Km/h Zahl nicht zu Hoch wird. Ab zb: 27,7Km/h bekomme ich als Antwort 2,9min/km, Es muss aber 2,09min/km Herauskommen. Unter 27,7km/h Arbeitet das Programm richtig. Meine Frage ist wie kann ich das im Programm Umsetzen.Hier ein Stück von dem code der Probleme macht: 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
32
33
34
35 | #include<iostream>
#include<cmath>
#include<fstream>
#include<string>
using namespace std;
void kmh()
{
double kmh;
double x;
double ganz;
double t;
// fstream test;
while(cout << "Km/h: "){
cin>>kmh;
if(!cin.good()){cerr << "Falsche Eingabe\n"; return;}
x = 60/kmh; // in min Umwandeln
double f = modf(x, &ganz); // x in Ganzzahl u Komma Aufteilen wobei f der Komma Wert ist
t = f*60; // Der Komma Wert in min Umrechnen
t = (int)(t*100+0.5)/100; // double casten um nur 2Stellig auszugeben
// test.open("t.txt", ios::out | ios::app);
// test << kmh << "km/h= " << ganz << "," << t << "min/km" << '\n';
// test.close();
cout << kmh << "Km/h= " << ganz << "," << t << "min/km" << '\n';
}
}
int main()
{
kmh();
return 0;
}
|
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12829
|
ubuntu--anfaenger schrieb:
Um das Berrechnen zu können muss ich einen double in einer ganz Zahl und Komma Zahl Zerlegen.
Nee, wieso? Nutz doch die Möglichkeiten der Ausgabeformatierung, die die C++-Streams bieten. Genau dafür sind sie doch da.
|
ubuntu--anfaenger
(Themenstarter)
Anmeldungsdatum: 12. Oktober 2013
Beiträge: 1088
Wohnort: Belgien
|
Hallo rklm,
Nee, wieso? Nutz doch die Möglichkeiten der Ausgabeformatierung, die die C++-Streams bieten. Genau dafür sind sie doch da.
Hm ich weiss nicht genau wie Du das meinst,soll ich das mit setw() machen, aber dann wären ja die Ergebnisse unter 27,7km/h falsch. Ps: Ich bin kein prof. Programmierer, ich weiss noch nicht so richtig wie ich das in code umsetzen kann. lg,
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17552
Wohnort: Berlin
|
ubuntu--anfaenger schrieb:
Das Programm arbeitet richtig so lange die Km/h Zahl nicht zu Hoch wird.
Das kann eigentlich nicht die Ursache sein.
Ab zb: 27,7Km/h bekomme ich als Antwort 2,9min/km, Es muss aber 2,09min/km Herauskommen.
Eher wird es sein, dass bei 2stelligen Nachkommawerten die Ausgabe stimmt, also 10, 11, ... 99, bei einstelligen wie 1, 2, ... 9 aber die führende Null unter den Tisch fällt und aus x,09 x,9 wird.
|
woko1754
Anmeldungsdatum: 12. November 2008
Beiträge: 801
Wohnort: Lübeck
|
Baue in main das hier ein
setlocale(LC_NUMERIC,"de_DE.UTF8");
dann reicht ein
x = 60 / kmh;
printf("%.2f\n", x);
zur Ausgabe mit zwei Nachkommastellen. Wolfram
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12829
|
ubuntu--anfaenger schrieb: Hallo rklm,
Nee, wieso? Nutz doch die Möglichkeiten der Ausgabeformatierung, die die C++-Streams bieten. Genau dafür sind sie doch da.
Hm ich weiss nicht genau wie Du das meinst,soll ich das mit setw() machen, aber dann wären ja die Ergebnisse unter 27,7km/h falsch.
Nee. Statt Zeile 27 z.B. so: | cout << fixed << setprecision(1) << kmh << "Km/h= ";
cout << setprecision(2) << x << "min/km" << endl;
|
Den Rest der Variablen kannst Du Dir dann natürlich auch sparen. Und Du brauchst noch
|
ubuntu--anfaenger
(Themenstarter)
Anmeldungsdatum: 12. Oktober 2013
Beiträge: 1088
Wohnort: Belgien
|
user_unknown schrieb:
Eher wird es sein, dass bei 2stelligen Nachkommawerten die Ausgabe stimmt, also 10, 11, ... 99, bei einstelligen wie 1, 2, ... 9 aber die führende Null unter den Tisch fällt und aus x,09 x,9 wird.
Ja genau so ist es! Ich glaube ich habe eine ganz einfache Lösung dafür gefunden: if(t == 6 || t == 7 || t == 8 || t == 9) { cout << kmh << "Km/h= " << ganz << "," << "0" << t << "min/km" << '\n'; } else cout << kmh << "Km/h= " << ganz << "," << t << "min/km" << '\n'; 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
32
33
34 | #include<iostream>
#include<cmath>
#include<fstream>
#include<string>
using namespace std;
void kmh()
{
double kmh;
double x;
double ganz;
double t;
while(cout << "Km/h: "){
cin>>kmh;
if(!cin.good()){cerr << "Falsche Eingabe\n"; return;}
x = 60/kmh; // in min Umwandeln
double f = modf(x, &ganz); // x in Ganzzahl u Komma Aufteilen wobei f der Komma Wert ist
t = f*60; // Der Komma Wert in min Umrechnen
t = (int)(t*100+0.5)/100; // double casten um nur 2Stellig auszugeben
if(t == 6 || t == 7 || t == 8 || t == 9)
{ cout << kmh << "Km/h= " << ganz << "," << "0" << t << "min/km" << '\n'; }
else
cout << kmh << "Km/h= " << ganz << "," << t << "min/km" << '\n';
}
}
int main()
{
kmh();
return 0;
}
|
woko1754 schrieb:
Baue in main das hier ein
Das funktioniert auch, liefert aber falsche Ergebnisse da x alleine nicht reicht:x=60/12.7=4.72=4min+0.72*60=4min43sek rklm schrieb:
Nee. Statt Zeile 27 z.B. so:
Hm, ja ich versteh was Du meinst aber das liefert ja dann auch falsche Ergebnisse. Da ja das was hinter dem komma steht getrennt Verarbeitet werden muss.
|
NORACSA
Anmeldungsdatum: 31. Januar 2010
Beiträge: 180
|
if(t == 6 || t == 7 || t == 8 || t == 9)
Das kann man viel schöner als t >= 6(oder noch besser > 5), und nötigenfalls noch mit ⇐ 9, wobei das eigentlich nicht nötig ist, da die Zahl ja immer einstellig bleiben wird, umschreiben.
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12829
|
ubuntu--anfaenger schrieb:
rklm schrieb:
Nee. Statt Zeile 27 z.B. so:
Hm, ja ich versteh was Du meinst aber das liefert ja dann auch falsche Ergebnisse. Da ja das was hinter dem komma steht getrennt Verarbeitet werden muss.
Kannst Du das mal erklären? Du hast einen double , der den korrekten Wert enthält - inklusive Nachkommastellen. Und der wird mit diesen Nachkommastellen unter Berücksichtigung der angegebenen Weite ausgegeben. Warum sagst Du, dass da etwas "hinter dem Komma [...] getrennt verarbeitet werden muss"? Falls das Problem ist, dass die Formatierung nicht der passenden Locale entsprichst, fügst Du halt vor der Ausgabe folgendes ein: Das übernimmt die Locale aus der Umgebung. Dann kannst Du durch Setzen von LC_NUMERIC das Format beeinflussen: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 | $ locale
LANG=en_US.UTF-8
LANGUAGE=en_US
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC=de_DE.UTF-8
LC_TIME=de_DE.UTF-8
LC_COLLATE="en_US.UTF-8"
LC_MONETARY=de_DE.UTF-8
LC_MESSAGES="en_US.UTF-8"
LC_PAPER=de_DE.UTF-8
LC_NAME=de_DE.UTF-8
LC_ADDRESS=de_DE.UTF-8
LC_TELEPHONE=de_DE.UTF-8
LC_MEASUREMENT=de_DE.UTF-8
LC_IDENTIFICATION=de_DE.UTF-8
LC_ALL=
$ ./a.out
1.23457
1,23457
$ LC_NUMERIC=en_US.UTF-8 ./a.out
1.23457
1.23457
|
Hier noch das Testprogramm, dass die Ausgabe oben erzeugt hat: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | #include <locale>
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
const double x = 1.234567;
cout << x << endl;
cout.imbue(locale(""));
cout << x << endl;
return 0;
}
|
|
woko1754
Anmeldungsdatum: 12. November 2008
Beiträge: 801
Wohnort: Lübeck
|
Das nach dem Komma sollen wohl die Minuten sein. Unglückliche Darstellung. Üblich ist da das Hochkomma.
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12829
|
woko1754 schrieb: Das nach dem Komma sollen wohl die Minuten sein. Unglückliche Darstellung. Üblich ist da das Hochkomma.
Oh Mann! Ich denke, Du hast Recht. 👍 Der Kommentar in Zeile 21 ist allerdings irreführend, denn es geht ja darum, in Sekunden umzurechnen. Und die Ausgabe mit Komma als Trenner ist natürlich total irreführend. Man würde da eher 2:09 oder 2'9" erwarten. Tut mir leid, ubuntu--anfaenger, ich habe Dich wohl falsch verstanden. Du hast aber auch nicht explizit erwähnt, dass nach dem Komma Sekunden und nicht etwa Minutenbruchteile stehen sollen...
|
Dakuan
Anmeldungsdatum: 2. November 2004
Beiträge: 6345
Wohnort: Hamburg
|
Wenn man schon, warum auch immer, den Nachkommaanteil getrennt verarbeiten will, dann sollte man sich über die Wertigkeit der Stellen im klaren sein. Wenn es, wie hier, Hundertstel sind benötigt man zur Ausgabe 2 Stellen mit führenden Nullen, bei Tausendstel sind es 3 Stellen.
| cout.width(2);
cout.fill('0');
cout << ...
|
Ich habe sowas mal in C gemacht, bei der Umrechnung geografischer Koordinaten in traditioneller Schreibweise.
|
woko1754
Anmeldungsdatum: 12. November 2008
Beiträge: 801
Wohnort: Lübeck
|
Es gibt auch komfortable Formatierungsmöglichkeiten siehe time.h
|
ubuntu--anfaenger
(Themenstarter)
Anmeldungsdatum: 12. Oktober 2013
Beiträge: 1088
Wohnort: Belgien
|
Danke für die vielen Antworten, bitte Berücksichtigt das ich ein totaler Anfänger bin. NORACSA schrieb:
Das kann man viel schöner als t >= 6(oder noch besser > 5), und nötigenfalls noch mit ⇐ 9
Ok ich werde das gleich so versuchen umzuschreiben.
wobei das eigentlich nicht nötig ist, da die Zahl ja immer einstellig bleiben wird, umschreiben.
Nee eben nicht, die Zahl hinter dem Komma muss 2 Stellig sein und in sek Umgwewandelt werden. woko1754 schrieb:
Das nach dem Komma sollen wohl die Minuten sein. Unglückliche Darstellung. Üblich ist da das Hochkomma.
Nee das nach dem Komma sind die Sek. Nochmal die Formel als Beispiel zur Berrechnung: bei 18,7Km/h = 60/18,7 = 3,20 → jetzt muss der Teil hinter dem Komma auf sek Hochgerechnet werden und zu dem Teil vor dem Komma wieder Beigefügt werden 0,20*60 = 12 = 03min12sek pro km Wenn mann diese Formel Vereinfachen kann ohne das ich den double Wert kompl Zerlegen muss(modf) nur her damit, ich habe keine andere Möglichkeit gefunden um das zu Berrechnen. rklm schrieb:
Der Kommentar in Zeile 21 ist allerdings irreführend, denn es geht ja darum, in Sekunden umzurechnen.
Sorry Du hast Recht, das war keine Absicht..ich habe das falsch komentiert.
ich habe Dich wohl falsch verstanden. Du hast aber auch nicht explizit erwähnt, dass nach dem Komma Sekunden und nicht etwa Minutenbruchteile stehen sollen...
Nee war mein Fehler! 😬 Dakuan schrieb:
Wenn man schon, warum auch immer, den Nachkommaanteil getrennt verarbeiten will, dann sollte man sich über die Wertigkeit der Stellen im klaren sein. Wenn es, wie hier, Hundertstel sind benötigt man zur Ausgabe 2 Stellen mit führenden Nullen, bei Tausendstel sind es 3 Stellen.
Ja wenn Du eine andere Möglichkeit siehst den Nachkommateil nicht getrennt zu verarbeiten, ohne falsche Ausgaben zu produzieren nur her damit. woko1754 schrieb:
Es gibt auch komfortable Formatierungsmöglichkeiten siehe time.h
Vielen Dank werde ich mir heute Abend auch mal Anschauen.
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11179
Wohnort: München
|
ubuntu--anfaenger schrieb: Ja wenn Du eine andere Möglichkeit siehst den Nachkommateil nicht getrennt zu verarbeiten, ohne falsche Ausgaben zu produzieren nur her damit.
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121 | #include <chrono>
#include <cmath>
#include <ctime>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <string>
// see https://stackoverflow.com/a/42139394
template <class... Durations, class DurationIn>
std::tuple<Durations...> break_down_durations(DurationIn d) {
std::tuple<Durations...> retval;
using discard = int[];
(void)discard{0, (void(((std::get<Durations>(retval) =
std::chrono::duration_cast<Durations>(d)),
(d -= std::chrono::duration_cast<DurationIn>(
std::get<Durations>(retval))))),
0)...};
return retval;
}
auto put_local_time() {
std::time_t t = std::time(nullptr);
return std::put_time(std::localtime(&t), "%H:%M:%S %d.%m.%Y");
}
void put_duration(const std::chrono::milliseconds &duration,
std::ostream &out) {
char prev_fill;
using namespace std::chrono;
auto [hh, mm, ss, ms] =
break_down_durations<hours, minutes, seconds, milliseconds>(duration);
prev_fill = out.fill('0');
out.precision(2);
if (hh.count() > 0) {
out << std::setw(2) << hh.count() << "h ";
} else
out << " ";
if (mm.count() > 0) {
out << std::setw(2) << mm.count() << "min ";
} else
out << " ";
out << std::setw(2) << ss.count() << '.' << std::setw(3) << ms.count()
<< "s per kilometer";
out.fill(prev_fill);
}
void km_h(std::ostream &out_file) {
long double km_h;
while (std::cout << "km/h: ") {
std::cin >> km_h;
if (!std::cin.good()) {
std::cerr << "Falsche Eingabe" << std::endl;
return;
}
unsigned long long ms_km = 3600 * 1000 / km_h;
std::chrono::milliseconds ms_per_km(ms_km);
put_duration(ms_per_km, std::cout);
std::cout << std::endl;
out_file << km_h << "km/h = ";
put_duration(ms_per_km, out_file);
out_file << " per km " << put_local_time() << std::endl;
}
}
void time_km(std::ostream &out_file) {
double min_km;
while (std::cout << "min/km: ") {
std::cin >> min_km;
if (!std::cin.good()) {
std::cerr << "Falsche Eingabe\n";
return;
}
double speed_km_h = 60 / min_km;
std::cout.precision(2);
std::cout << std::fixed;
std::cout << min_km << " min/km = " << speed_km_h << " km/h" << '\n';
out_file << min_km << " min/km = " << speed_km_h << " km/h "
<< put_local_time() << '\n';
}
}
int main() {
std::locale mylocale("");
std::cout.imbue(mylocale);
std::cin.imbue(mylocale);
std::cout << "Temporechner: \n";
std::cout
<< "A für km/h in Zeit/km oder B für min/km in km/h (Q zum Beenden): ";
std::fstream out_file;
out_file.open("t.txt", std::ios::out | std::ios::app);
char einh = 'x';
std::cin >> einh;
if (!std::cin.good()) {
std::cerr << "Falsche Eingabe" << std::endl;
return 1;
}
switch (einh) {
case 'a':
case 'A':
km_h(out_file);
break;
case 'b':
case 'B':
time_km(out_file);
break;
case 'q':
case 'Q':
return 0;
default:
std::cout << "Sorry wir Unterstützen nur A, B und Q" << std::endl;
break;
}
out_file.close();
}
|
Das Programm muss mit dem Argument -std=c++17 für g++ kompiliert werden, damit die structured bindings möglich sind.
|