Forum: PC-Programmierung könnte mir jemand kurz über mein C Code schauen ?


von Lehrmann M. (ubimbo)


Lesenswert?

Servus zusammen,

wäre jemand von euch so nett und schaut kurz über meinen C-Code.
Irgendwas an meinen Berechnungen stimmt nicht.

Es geht um das Julianische Datum - der Algorithmus ist unter 
http://de.wikipedia.org/wiki/Julianisches_Datum#Berechnung_aus_dem_Kalenderdatum 
dargestellt.

Hier der Auszug:
1
 wenn Monat > 2 dann  Y = Jahr,   M = Monat
2
                  sonst Y = Jahr-1, M = Monat+12
3
   D = Tag 
4
   H = Stunde/24 + Minute/1440 + Sekunde/86400
5
    
6
   wenn TT.MM.YYYY >= 15.10.1582  
7
        dann Gregorianischer Kalender: A = Int(Y/100), B = 2 - A + Int(A/4)
8
         
9
   wenn TT.MM.YYYY <= 04.10.1582  
10
        dann Julianischer Kalender:                    B = 0
11
    
12
   JD = Int(365,25*(Y+4716)) + Int(30,6001*(M+1)) + D + H + B - 1524,5

mich interessiert außschlieslich die Berechnung nach dem 15.10.1582!

Mein Code:
1
# include <stdio.h>
2
3
double JD(int jahr_n, int monat_n, int tag_n, int stunde_n, int minute_n, int sekunde_n);
4
5
int main(){
6
  printf("%lf",JD(2010,3,25,16,30,0));
7
  getchar();
8
}
9
10
double JD(int jahr_n, int monat_n, int tag_n, int stunde_n, int minute_n, int sekunde_n){
11
  
12
  double H=0, A=0, B=0;
13
14
  if(monat_n<=2){
15
    jahr_n--;
16
    monat_n+=12;
17
  }
18
19
  H=(stunde_n/24)+(minute_n/1440)+(sekunde_n/86400);
20
  A=((int)(jahr_n/100));
21
  B=2-A+((int)(A/4));
22
  return(((int)(365.25*(jahr_n+4716))) + ((int)(30.6001*(monat_n+1))) + tag_n + stunde_n + B - 1524.5);
23
}


JD(2010,3,25,16,30,0) sollte den 25. März 2010, 16:30:00 Uhr darstellen.

Meine Berechnung gibt aus: 2.455.296,5

Es sollte herauskommen: 2.455.281

Sieht jemand einen Fehler ?

von Karl H. (kbuchegg)


Lesenswert?

Lehrmann Michael schrieb:

> Sieht jemand einen Fehler ?

Der Klassiker

  sekunde_n/86400

http://www.mikrocontroller.net/articles/FAQ#Datentypen_in_Operationen

von Karl H. (kbuchegg)


Lesenswert?

JD = Int(365,25*(Y+4716)) + Int(30,6001*(M+1)) + D + H + B - 1524,5

 return(((int)(365.25*(jahr_n+4716))) + ((int)(30.6001*(monat_n+1))) + 
tag_n + stunde_n + B - 1524.5);


In deinem C Code kommt H nicht vor, dafür aber stunde_n

von jl (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Der Klassiker
>
>   sekunde_n/86400

Klar ist das H schon mal 0 ist (wenn stunde_n [0..23]). Also richtig 
cast anwenden.

der fehler ist da:
Lehrmann Michael schrieb:
> return(((int)(365.25*(jahr_n+4716))) + ((int)(30.6001*(monat_n+1))) + tag_n + 
stunde_n + B - 1524.5);

aber die Formael sagt:
JD = Int(365,25*(Y+4716)) + Int(30,6001*(M+1)) + D + H + B - 1524,5

ersetze stunde_n durch H und beachte die Anmerkung von Karl heinz

von jl (Gast)


Lesenswert?

mist zu langsam :-)

von Lehrmann M. (ubimbo)


Lesenswert?

Oha omg. ich Depp und mein Type-Cast ...
Danke an euch beide =)

Klapp leider immernoned

hier mein neuer Code:
1
# include <stdio.h>
2
3
double JD(int jahr_n, int monat_n, int tag_n, int stunde_n, int minute_n, int sekunde_n);
4
5
int main(){
6
  printf("\n%lf",JD(2010,3,25,16,30,0));
7
  getchar();
8
}
9
10
double JD(int jahr_n, int monat_n, int tag_n, int stunde_n, int minute_n, int sekunde_n){
11
  
12
  double H=0, A=0, B=0;
13
14
  if(monat_n<=2){
15
    jahr_n--;
16
    monat_n+=12;
17
  }
18
19
  H=((double)stunde_n/24)+((double)minute_n/1440)+((double)sekunde_n/86400);
20
  A=((int)((double)jahr_n/100));
21
  B=2-A+((int)((double)A/4));
22
  return(((int)(365.25*((double)jahr_n+4716))) + ((int)(30.6001*((double)monat_n+1))) + (double)tag_n + H + B - (double)1524.5);
23
}

Bis auf die Nachkommastelle stimmt's jetzt ...

Ich habs bissle übertrieben aber ich find keinen Fehelr mehr !

von didadu (Gast)


Lesenswert?

bindet der double stärker an die sekunde oder der /    ?

von Lehrmann M. (ubimbo)


Lesenswert?

double geht für sekunden_n - aber wenn eines von beiden double ist (in 
diesem fall die sekunden_n dann ist das Ergebnis vom Typ der 
höchstwertige (also double).

H ist auch ein double wenn ich einen printf("%lf",H); mache!

von didadu (Gast)


Lesenswert?

Die Frage ist, ob die der Integer Sekunden ERST durch den 86400 Integer 
geteilt werden (dann ist das Ergebnis IMMER 0) oder ob sie ERST auf den 
double gecastet und DANACH geteilt werden, NUR dann bleibt nämlich von 
den Sekunden ein Wert zwischen 0 und 1 übrig.

Diese Frage betrifft die ganze Kette, die zum H führt.

von Lehrmann M. (ubimbo)


Lesenswert?

H ist ein double !

0.687500 kommt raus.

Von daher steht es außer Zweifel, dass diese Zeile zumindest im Hinblick 
auf diese Problem korrekt ist. ODER?

von didadu (Gast)


Lesenswert?

Ok, dann bindet der cast stärker als die Division.
Das wollte ich wissen.
Danke für die Info.

von Lehrmann M. (ubimbo)


Lesenswert?


von didadu (Gast)


Lesenswert?

Nee, das, was ich meinte, steht da nicht!

Dein Test hat es für Deinen Programmierfall ergeben und mich aufgeklärt, 
ok.

Aber da Du meinst, dass das da, was ich wissen wollte, da steht, obwohl 
es da nicht steht, solltest Du Dich vielleicht mal allgemein mit der 
Priorität von Operatoren befassen. Also die Frage von Punktrechnung vor 
Strichrechnung, aber ausgedehnt auf alle Operatoren. Da kommt's nämlich 
wirklich auf die Feinheiten an, weil man sonst fiese Fehler übersehen 
könnte.

von Karl H. (kbuchegg)


Lesenswert?

Ansonsten kann man immer noch zu Plan B greifen
1
  H =  stunde_n / 24.0 +
2
       minute_n / 1440.0 +
3
       sekunde_n / 86400.0;

Da jetzt die Konstanten mit Sicherheit double sind, bleibt nichts 
anderes übrig als die Divisionen auch als Gleitkommadivisionenen 
auszuführen.
Und übersichtlicher ist es IMHO auch.

von Karl H. (kbuchegg)


Lesenswert?

> Bis auf die Nachkommastelle stimmt's jetzt ...

Kannst du das einmal näher beziffern?

Da der Nachkommaanteil im julianischen Datum die Tageszeit kodiert, kann 
eine Angabe von

JD(2010,3,25,16,30,0) sollte den 25. März 2010, 16:30:00 Uhr darstellen.

kein julianisches Datum mit einem Nachkommaanteil von .0 ergeben.

xxx.0 wäre Mittag. Halb 5 Uhr Nachmittags ist ein bischen mehr als ein 
Sechstel Tag. Deine Nachkommastelle müsste also ein wenig größer als 
xxx.1666 sein

(Das ist ganz klar ein Fehler in Wikipedia. Ich hab ihn korrigiert. 
Hätte dir eigentlich auch auffallen müssen :-)

(Und bitte: gewöhn dir den Unsinn mit den Tausenderpunkten wieder ab. 
Die Verwechslungsgefahr mit einem Dezimalpunkt ist einfach viel zu groß! 
Kaufleute brauchen diese Punkte, Techniker benutzen im Zweifelsfall 
Exponenten oder schreiben die Zahl einfach so hin)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.