# Uhr, Winkel zwischen Zeigern



## Odin (23. November 2010)

Hallo,
ich habe eine Aufgabe bei deren Lösung ich etwas Hilfe benötigen könnte.
Kurz zur allgemeinen Aufgabe:
Ich soll ein Programm schreiben, das zu einer bestimmten Uhrzeit im (24-Stunden-Takt) berechnen soll, wie groß der kleinste Winkel zwischen dem Stunden- und dem Minutenzeiger ist. Uhrzeit soll über Kommandozeile eingegeben werden.
Das Habe ich auch alles hinbekommen, Programm leuft einwandfrei:


```
#include <iostream>
#include <cmath>

using namespace std;

int s;
int m;

int main () {
    cout << "Uhrzeit eingeben:" << endl;
    cout << "Stunden: ";
    cin >> s;
    cout << "Minuten: ";
    cin >> m;
       
    int i = 360;
    int ws;
    int wm;
    int winkel;
    
    ws = (s * 30 + m * 1/2);
    wm = m * 6;
    winkel = ws - wm;   
    
    cout << "Der Winkel zwischen den Zeigern betraegt: " << winkel << " " << "Grad";
}
```

Wie gesagt, funktioniert einwandfrei. Es gibt allerdings ein kleines Problem: Das Programm funktioniert NUR, wenn ich die Uhrzeiten im 12-Stunden-Takt angebe (urzeit 0 - 12, anstatt 0 - 24). Gebe ich z.B. 20:18 ein, kommt das falsche Ergebnis raus, bei 8:18 das Richtige. 

Meine Frage:
Wie mache ich das das auch mit den uhrzeiten von 13 - 24 uhr geht? Ist ja schließlich die Aufgabenstellung! Ich habe mir gedacht, man könnte dem Programm vllt sagen, das wenn die eingegebene Zahl größer als 12 ist, das der dann die Zahlen ersetzen soll, also 13 mit 1, 14 mit 2 ersetzen usw....
Wenn ich das mit lauter if-Schleifen mache, berechnet der das Ergebnis falsch! Auserdem sieht es sehr unschön aus:


```
#include <iostream>
#include <cmath>

using namespace std;

int s;
int m;

int main () {
    cout << "Uhrzeit eingeben:" << endl;
    cout << "Stunden: ";
    cin >> s;
    cout << "Minuten: ";
    cin >> m;
    
    if (s==13);
    s = 1;
    
    if (s==14);
    s = 2;
    
    if (s==15);
    s = 3;
    
    if (s==16);
    s = 4;
    
    if (s==17);
    s = 5;
    
    if (s==18);
    s = 6;
    
    if (s==19);
    s = 7;
    
    if (s==20);
    s = 8;
    
    if (s==21);
    s = 9;
    
    if (s==22);
    s = 10;
    
    if (s==23);
    s = 11;
    
    if (s==24);
    s = 12;
    
    int i = 360;
    int ws;
    int wm;
    int winkel;
    
    ws = (s * 30 + m * 1/2);
    wm = m * 6;
    winkel = ws - wm;   
    
    cout << "Der Winkel zwischen den Zeigern betraegt: " << winkel << " " << "Grad";
}
```

Wenn ich 8:18 Uhr eingebe, muss normalerweise der Winkel 141 rauskommen, es kommt aber (wenn die ifschleifen dabei sind) 261 raus, 

Weis jemand wie man dieses Problem besser und vorallem richtig lösen könnte?
Danke schonmal.

Gruß


----------



## sheel (23. November 2010)

So auf Anhieb kann ich nicht erkennen, warum ein falscher Winkel rauskommt, aber:

Die zwölf if sind wirklich unnötig
Schau mal:

```
while(s>=12)
    s-=12;
```
Wenn s größer gleich 12 ist, wird von s 12 abgezogen...
Das while statt dem if sorgt auch dafür, dass 24:00 zu 0:00 wird.

Übrigens: if ist keine Schleife, sondern eine Bedingung. Schleifen wiederholen sich. while, do-while, for.


----------



## RudolfG (23. November 2010)

sheel hat gesagt.:


> So auf Anhieb kann ich nicht erkennen, warum ein falscher Winkel rauskommt, aber:



Das ; hinter jedem if (); dürfte diese Fehler verursachen (würde ich mal ohne testen behaupten!).



sheel hat gesagt.:


> Die zwölf if sind wirklich unnötig
> Schau mal:
> 
> ```
> ...



Aber auch, dass es keine 12 Uhr geben kann  Deswegen würde ich hier die if-Variante nehmen


```
if (s > 12)
   s -= 12;
```

Gruß
Rudolf


----------



## sheel (24. November 2010)

RudolfG hat gesagt.:


> Das ; hinter jedem if (); dürfte diese Fehler verursachen (würde ich mal ohne testen behaupten!).


Hehe...das hab ich übersehen 



RudolfG hat gesagt.:


> Aber auch, dass es keine 12 Uhr geben kann  Deswegen würde ich hier die if-Variante nehmen


Dann würde s*30 aber 360 ergeben, damit nicht gerade den kleinsten Winkel...

Hier wäre zumindest eine funktionierende Variante (ja um Mitternacht ist mir immer langweilig  )

```
#include <stdio.h>

int main()
{
	int s,m;long double w;
	printf("Uhrzeit (hh:mm) eingeben:\n");
	scanf("%d:%d",&s,&m);
	if(!((s==24&&m==0)||(s>=0&&s<24&&m>=0&&m<60)))
	{
		printf("Falsche Eingabe.\n");
		return 1;
	}
	s=(s%12)*30-m*6;
	w=((long double)m)/2+(long double)s;
	printf("%.2lf Grad.\n",(w<0)?(-w):w);
	return 0;
}
```

edit:Oder so  

```
#include <stdio.h>
int main(){int s,m;scanf("%d:%d",&s,&m);s=(s%12)*30-m*6;long double w;=((long double)m)/2+(long double)s;printf("%.2lf",(w<0)?(-w):w);}
```

Gruß


----------



## RudolfG (24. November 2010)

sheel hat gesagt.:


> Dann würde s*30 aber 360 ergeben, damit nicht gerade den kleinsten Winkel...



Stimmt, hast Recht da macht das mit der while-Schleife mehr sinn  (obwohl das Resultat, wenn es gezeichnet werden soll, das gleiche währe )




sheel hat gesagt.:


> Hier wäre zumindest eine funktionierende Variante (ja um Mitternacht ist mir immer langweilig  )
> 
> ```
> #include <stdio.h>
> ...


 
Wenn der Odin das jetzt auch noch versteht (besonders die ?:- if-Notation) dann passt jetzt alles 

Gruß
RudolfG


----------



## Odin (24. November 2010)

Vielen Dank für die schnelle und kompetente Hilfe!
An das

```
if (s > 12)
```
hatte ich auch schon gedacht, nur war ich mir nicht sicher, was ich dadrunter schreiben soll. Jetzt wo ichs sehe ist das eigentlich klar. Dankeschön.

Aber ihr habt recht, dann bekommt man nicht immer den kleinsten Winkel raus. Dummerweise sind bei dem Code von sheel einige Befehle, die wir noch nicht in der Vorlesung hatten, wodurch ich mich da erstmal kurz versuchen muss reinzudenken um zu schauen ob ichs denn verstehe. Auserdem weis ich nicht in wie fern der Prof die Lösung akzeptiert, wenn da ganz andere Befehle drin stehen, wie er uns beigebracht hat.

Gruß
Odin


----------



## Odin (24. November 2010)

Ok, da ich den Code nur zum Teil verstanden habe, habe ich mich an einer eigenen Verbesserung versucht. Jetzt scheint alles zu klappen, nur mit ein paar einzelnen Uhrzeiten hat das Programm noch Probleme. z.b. kann es nicht sein, das bei 11:00 Uhr 150 Grad raus kommen!
Hier mein Abgeänderter Code:

```
#include <iostream>
#include <cmath>

using namespace std;

int s;
int m;

int main () {
    cout << "Uhrzeit eingeben:" << endl;
    cout << "Stunden: ";
    cin >> s;
    cout << "Minuten: ";
    cin >> m;
    
    if (s > 12)
    s -= 12;
    
    int i = 360;
    int ws;
    int wm;
    int winkel;
    
    if(s == 12 || s == 24) {
        cout << "Falsche Eingabe." << endl;
        return 1;
    }
    else {

    
    ws = (s * 30 + m * 1/2);
    wm = m * 6;
    winkel = ws - wm;
    
    if (winkel > 180)
    winkel -= 180;
    
    if (winkel < 0)
    winkel = winkel *(-1);
    
    cout << "Der Winkel zwischen den Zeigern betraegt: " << winkel << " " << "Grad";
    return 0;
    }

}
```

Da bei einigen Rechnungen mit 0 Uhr minus Zahlen raus kamen, hab ich diese einfach in Positive Zahlen umgewandelt. 

```
if (winkel < 0)
    winkel = winkel *(-1);
```
Das mit dem, das nur die kleinen Winkel genommen werden sollen, hab ich versucht so ähnlich zu lösen, wie das Problem mit dem 12- und 24-Stunden-Takt. 

```
if (winkel > 180)
    winkel -= 180;
```
Auserdem habe ich versucht das Problem mit 12 und 24 Uhr zu lösen.

```
if(s == 12 || s == 24) {
        cout << "Falsche Eingabe." << endl;
        return 1;
    }
    else {
    ....
    }
```

Auserdem @ sheel:
Ich habe deinen Code mal ausprobiert, der gehtn icht. Da kommt, egal was man eintippt, -0,00 Grad heraus.

Gruß
Odin


----------



## sheel (24. November 2010)

Welchen Compiler/Betriebssystem verwendest du denn?
Bei mir funktioniert mein Code einwandfrei.

Zu deinem:
1) Bei dir wäre 12 Uhr eine ungültige Eingabe.
12 ist nicht >12, also wird das erste if nichtgemacht, und dann sgast du bei 12 oder 24 Ungültig. Warum das?

2) Die Prüfung auf die ungültige Eingabe solltest du vor dem minus-12-rechnen machen.
Und nur prüfen, ob die Minuten zwischen 0 und 60 und die Stunden von 0 bis 24 sind.
Nicht 12 als ungültig erklären.

3) Du hast ein int i (=360). Warum? Du verwendest es nie.

4) Wenn du die vorigen Beiträge gelesen hättest, wüsstest du, dass statt

```
if(s>12) s-=12;
```
das hingehört:

```
while(s>=12) s-=12;
```
Das >=, weil 12 den gleichen Winkel wie 0 ergibt und deshalb 12 auch auf 0 hintergerechnet werden sollte.
Ist für die Winkelberechnung nur hilfreich.
Und das while, damit auch 24 nicht nur auf 12, sondern auch auf 0 zurückgerechnet wird.
Und statt dem Teil könntest du auch einfach

```
s%=12;
```
 machen.
% (Modulo) macht praktisch eine Division (hier durch 12), nimmt aber nicht das Ergebnis sondern den Rest.
Also bleibt auch nur irgendwas von 0 bis 11 übrig.

5) ie Reiehnfolge der letzten beiden ifs ändern.

7) Statt

```
winkel=winkel*(-1)
```
würde das auch reichen:

```
winkel=-winkel
```

8) Beim >180... solltest du eher
winkel=360-winkel rechnen

Gruß


----------



## Trulleberg (24. November 2010)

sheel hat gesagt.:


> ```
> ...
> int s,m;long double w;
> ...
> ...



Die printf-Formatvorgabe für long double ist Lf und nicht lf.


----------



## sheel (24. November 2010)

Sagt wer?
http://msdn.microsoft.com/en-us/library/tcxf1dw6(v=VS.71).aspx


----------



## Odin (24. November 2010)

@ sheel:
Ich benutze Windows und als Compiler MinGW, das hat uns unser Prof. vorgeschlagen. 
Oh das int i = 360 ist noch fälschlicher weise von einem anderen Versuch da, hab vergessen das zu löschen.
Ich hab die vorigen Beiträge gelesen, aber ich hab sowohl die if- als auch die while-Variante versucht, und keinen unterschied feststellen können.
Ok habe alle änderungen vorgenommen die du mir geraten hast. Jetzt schein alles reibungslos zu Funktionieren. Dankeschön

Gruß 
Odin


----------



## sheel (24. November 2010)

Das mit dem if und while macht nur bei 12 bzw. 24 Uhr einen Unterschied.

Aber schön, dass es funktioniert 

Gruß


----------



## Trulleberg (24. November 2010)

Sagen seit 1989 beide C Standards.


----------



## sheel (24. November 2010)

Dann hält sich MS eben nicht daran.
Sie schreiben ja extra "lowercase L" dazu...

Aber Odin genau wie ich unter Windows arbeitet, dürfte es für ihn kein Problem sein.

Gruß

PS: Loki lässt grüßen


----------



## deepthroat (25. November 2010)

Hi.





sheel hat gesagt.:


> Dann hält sich MS eben nicht daran.
> Sie schreiben ja extra "lowercase L" dazu...


Die Tabelle die du verlinkt hast enthält ja nicht mal eine Aussage zu double, geschweige denn long double.

Siehe den Kommentar hier: http://msdn.microsoft.com/en-us/library/tcxf1dw6(v=VS.100).aspx#1


sheel hat gesagt.:


> Aber Odin genau wie ich unter Windows arbeitet, dürfte es für ihn kein Problem sein.


Was hat das mit dem Betriebssystem zu tun? Auch unter Windows gibt es nicht nur einen Compiler.

Der MSVC Compiler unterstützt keine erweiterte Präzision bei long double. D.h. double und long double sind im Grunde dasselbe (8 Byte groß) - deshalb macht es auch keinen Unterschied %lf bzw. %LF zu verwenden, aber das ist mehr oder weniger pures Glück.

Der MinGW GCC unterstützt long double (12 Byte) - auch unter Windows.

Gruß


----------

