Nevíte-li si rady s jakýmkoliv matematickým problémem, toto místo je pro vás jako dělané.
Nástěnka
❗22. 8. 2021 (L) Přecházíme zpět na doménu forum.matweb.cz!
❗04.11.2016 (Jel.) Čtete, prosím, před vložení dotazu, děkuji!
❗23.10.2013 (Jel.) Zkuste před zadáním dotazu použít některý z online-nástrojů, konzultovat použití můžete v sekci CAS.
Nejste přihlášen(a). Přihlásit
Na vstupu je zadáno šest celých čísel, která představují dvě kalendářní data ve tvaru
Den1 Mesic1 Rok1
Den2 Mesic2 Rok2
Obě data jsou korektní, první z nich je v kalendáři dříve než druhé (tzn. je starší). Určete počet dní, který uplynul nebo uplyne mezi oběma daty. Při výpočtu počítejte s přestupnými roky. Výsledný počet dní se nemusí vejít do proměnné typu integer, použijte typ longint. Hodnotí se nejen správnost výsledků, ale i efektivita zvoleného postupu řešení.
Příklady:
- pro vstup 3 3 2011 5 3 2011 bude správným výsledkem číslo 2
- pro vstup 15 1 2000 15 1 2001 bude správným výsledkem číslo 366
- pro vstup 1 1 2000 1 1 2010 bude správným výsledkem číslo 3653
Offline
↑ ho77a:
Jednoduché odečítání, které komplikuje jen výskyt přestupných roků. Pro určení přestupného roku je celkem jednoduché pravidlo: Rok je přestupný, pokud je dělitelný 4 a není dělitelný 100 nebo pokud je dělitelný 400.
Myslím, že i zde se vztahuje pravidlo řešení příkladů, tedy měl bys zkusit napsat, k čemu jsi sám došel.
Offline
↑ ho77a:
(k té funkci - vřele doporučuji nešetřit závorkami)
První nápad:
1. Spočítej si, kolik celých let je mezi zadanými roky, tedy nepočítej "krajní". Např. mezi lety 1840 a 1845 jsou takové roky 4. Tedy vezmeš 365*4. Dále si tyto roky projdi a zjisti, který z nich je přestupný (prostor pro optimalizaci - skutečně je třeba procházet všechny roky?). (Další prostor pro časovou optimalizaci - je skutečně efektivní zadávat jednoduchou podmínku jako funkci? Ta režie s tím spojená...)
2. Spočítej si, kolik ti z prvního roku chybí dní do konce roku. Například můžeš mít v poli 12 integerů počet dní v měsíci. (prostor pro časovou optimalizaci - nedalo by se použít pole s 11 prvky, kde by bylo na 1. místě počet dní bez ledna, na druhém počet dní bez ledna a února,...). No a pokud máš zadaný leden nebo únor a je přestupný rok, přidej jeden den.
3. Spočítej si, kolik dní z posledního roku chybí do konce roku. Finta podobná jako bod 2.
4. Všechno sečti.
Offline
↑ ho77a:
To že vidíš Pascal poprvé asi nebude tak moc pravda viz. 13.11. #12
Offline
Program dnipocet (vstup, výstup);
používá
crt;
const
mesic: array [1. .. 12] celé číslo =
(31,29,31,30,31,30,31,31,30,31,30,31);
var
rokpoc, mespoc, denpoc, rokkon, Meskon, denkon: integer;
pocdnu: real;
r1, r2, r, konec: string;
i: integer;
begin
write ('Pocatecni rok =');
readln (rokpoc);
write ('Pocatecni mesic =');
readln (mespoc);
write ('Pocatecni den =');
readln (denpoc);
r2: = 'n';
pokud rokpoc / 4 = int (rokpoc / 4), pak r2: = 'a';
pokud rokpoc/100 = int (rokpoc/100), pak r2: = 'n';
pokud rokpoc/400 = int (rokpoc/400), pak r2: = 'a';
if ((denpoc = 29) a (mespoc = 2) a (r2 = 'n')), pak
začít
writeln ('MŘsc m Jen 28 dn');
goto 3;
end;
ale dál nevím
tedy aspon zatím nevím
Offline
↑ ho77a:
To bys ale už mohl zvládnout napsat program, který načte oba datumy a třeba je vypíše na obrazovku. Zatím se nic nepočítá.
Pro inspiraci třeba
Offline
↑ ho77a:
Tak tudy nejspíš ne, protože nevím, co chceš vůbec sdělit (zejm. to goto? kam? a obecně v Pascalu je goto fuj!). Napíšu ti v náznaku funkce na hrubou a neověřenou implementaci mého postupu:
Výpočet celých let:
function celeRoky(r1,r2:integer):longint;
var
r,i,j:integer;
d:longint;
begin
r:=r2-r1-1; /*počet celých let*/
if r>=1 then /*pokud je více než jeden rok mezi intervaly*/
begin
d:=365*r; /*počet dní za předpokladu, že jde o nepřestupné roky*/
/*nejprve příčtu všechny rodky dělitelné čtyřkou */
i:=4 - ((r1+1) mod 4); /*kdy bude první dělitelný čtyřkou*/
if r>=i then /*pokud se vejdeme do intervalu*/
begin
j:= (r-i) div 4; /*počet roků dělitelných čtyřmi*/
d:=d+j;
end;
/*--------*/
/*zcela stejným postupem odečteš roky dělitelné 100 a přičteš roky dělitelné 400*/
/*důkladně si rozmysli, proč*/
end
else begin
if r<=0 then d:=0; /*pokud jsou stejné nebo sousedící, není mezi nimi jeden celý rok*/
if r=1 then /*pokud je mezi roky jeden celý rok*/
begin
r:=r1+1; /*číslo toho roku*/
if ((r mod 4)=0) and ((r mod 100)<>0)) or ((r mod 400) = 0) then d:=366
else d:=365;
end;
end;
celeRoky:=d;
end;Podobně počítání dní do konce daného roku je jednoduché, pokud využiješ např. předpočítané pole dnů v měsíci bez zadaného:
const DnyDoKonce:array[1..12] of integer = {365,365-31,365-31-28......,31};
/*prostě pole dní daného měsíce plus dalších měsíců do konce roku*/
.....
function doKonceRoku(d,m,r:integer):integer;
var
a:integer;
begin
a:=DnyDoKonce[m] - d; /*počet dní do konce roku v ideálním případě - den vlastně říká, kolik dní už uplynulo*/
if jePrestupny(r) and ((m=1) or (m=2)) then a:=a+1;
/*v lednu i v únoru v přestupném roce zbývá do konce roku o den víc. Rozmysli se, jak to bude s 29.2.*/
doKonceRoku:=a;
end;Výpočet dní od začátku roku do daného data je zcela analogický. (pokud není něco syntakticky v pořádku, tak se omlouvám, ale Pascal jsem už dlouho nepoužíval...)
Offline
například takhle pomocí toho goto jsem myslel
program dnipocet (input,output);
uses
crt;
const
mesic:array[1..12] of integer =
(31,29,31,30,31,30,31,31,30,31,30,31);
label
1,2,3,4;
var
rokpoc,mespoc,denpoc,rokkon,meskon,denkon:integer;
pocdnu:real;
r1,r2,r,konec:string;
i:integer;
begin
2: clrscr;
write('Pocatecni rok = ');
readln(rokpoc);
write('Pocatecni mesic = ');
readln(mespoc);
3: write('Pocatecni den = ');
readln(denpoc);
r2:='n';
if rokpoc/4=int(rokpoc/4) then r2:='a';
if rokpoc/100=int(rokpoc/100) then r2:='n';
if rokpoc/400=int(rokpoc/400) then r2:='a';
if ((denpoc=29) and (mespoc=2) and (r2='n')) then
begin
writeln('MŘsˇc m jen 28 dnˇ');
goto 3;
end;
writeln;
write('Konecny rok = ');
readln(rokkon);
write('Konecny mesic = ');
readln(meskon);
4: write('Konecny den = ');
readln(denkon);
r2:='n';
if rokkon/4=int(rokkon/4) then r2:='a';
if rokkon/100=int(rokkon/100) then r2:='n';
if rokkon/400=int(rokkon/400) then r2:='a';
if (denkon=29) and (meskon=2) and (r2='n') then
begin
writeln('MŘsˇc m jen 28 dnˇ');
goto 4;
end;
pocdnu:=0;
if (rokkon=rokpoc) and (mespoc=meskon) then
begin
pocdnu:=pocdnu+(denkon-denpoc+1);
goto 1;
end;
if rokkon=rokpoc then
begin
for i:=mespoc+1 to meskon-1 do
begin
pocdnu:=pocdnu+mesic[i];
if i=2 then
begin
r1:='n';
if rokpoc/4=int(rokpoc/4) then r1:='a';
if rokpoc/100=int(rokpoc/100) then r1:='n';
if rokpoc/400=int(rokpoc/400) then r1:='a';
if r1='n' then pocdnu:=pocdnu-1;
end;
end;
end;
if rokpoc<rokkon then
begin
for i:=mespoc+1 to 12 do
begin
pocdnu:=pocdnu+mesic[i];
if i=2 then
begin
r1:='n';
if rokpoc/4=int(rokpoc/4) then r1:='a';
if rokpoc/100=int(rokpoc/100) then r1:='n';
if rokpoc/400=int(rokpoc/400) then r1:='a';
if r1='n' then pocdnu:=pocdnu-1;
end;
end;
for i:=1 to meskon-1 do
begin
pocdnu:=pocdnu+mesic[i];
if i=2 then
begin
r1:='n';
if rokkon/4=int(rokkon/4) then r1:='a';
if rokkon/100=int(rokkon/100) then r1:='n';
if rokkon/400=int(rokkon/400) then r1:='a';
if r1='n' then pocdnu:=pocdnu-1;
end;
end;
end;
if rokkon-rokpoc>=2 then
begin
for i:=rokpoc+1 to rokkon-1 do
begin
r1:='n';
if i/4=int(i/4) then r1:='a';
if i/100=int(i/100) then r1:='n';
if i/400=int(i/400) then r1:='a';
if r1='n' then pocdnu:=pocdnu+365;
if r1='a' then pocdnu:=pocdnu+366;
end;
end;
pocdnu:=pocdnu+(mesic[mespoc]-denpoc+1);
r1:='n';
if rokpoc/4=int(rokpoc/4) then r1:='a';
if rokpoc/100=int(rokpoc/100) then r1:='n';
if rokpoc/400=int(rokpoc/400) then r1:='a';
if (r1='n') and (mespoc=2) then pocdnu:=pocdnu-1;
pocdnu:=pocdnu+denkon;
1: writeln;
writeln('Pocet dnu = ',pocdnu:18:0);
write('Konec (a/n) ');
readln(konec);
if konec = 'n' then goto 2;
end.
Offline
↑ ho77a:
Protože jde o konstukci mimo strukturované programování. To vedle koncepčí nečistoty a horší přehlednosti zdrojového kódu vede k tomu, že přeložený program je méně efektivní.
Prakticky všechno jde nahradit stejně přehledně cykly. Například tvůj cyklus kontroly korektně zadaného data by bylo mnohem lepší řešit cyklem repeat-until. No a protože to použiješ 2x, byla by na místě procedura.
Vlastní cyklus by vypadal nějak takhle (v pseudokódu):
repeat
načti D,M,R
until (M in [1..12]) and ((D in [1..pocetDni[M]]) or (prestupny(M) and (D in [1..pocetDni[M]+1]));
Offline
Offline
↑ Honzc:
Také jsem si všiml:-) Tohle jsem doplnil jen jako ilustraci toho, že goto skutečně není pro většinu konstrukcí třeba (ale když jsem kdysi přecházel z ATARI BASICu, tak mi citelně chyběly konstrukce ON A GOTO a GOTO A). Byl bych prostě špatný učitel, nechávám se snadno "odlákat" od řešeného problému k tomu, co student také neumí...
Offline
no, tak jsem mrknul na net, popadnul jsem první vzořeček co se mi dostal pod ruku, a tady je nástřel výpočtu. pro uvedené tři případy v zadání funguje, aktuální juliánské datum podle netu taky souhlasí, jestli je to ale košer pro kdejaké datumy, jsem nezkoumal :-)
jak na to přes pole, nevím, ale třeba aspoň tohle bude k něčemu užitečné.
program julian;
var ju1,ju2:real;
function juli(d,m,r:integer):real;
const difka=1721118.5;
var i,f,g:real;
begin
if m<3 then
begin
f:=m+12; g:=r-1;
end;
if m>=3 then
begin
f:=m; g:=r;
end;
i:=d+int((153*f-457)/5);
i:=i+365*g+int(g/4)-int(g/100)+int(g/400)+difka;
juli:=i;
end;
begin
ju1:=juli(3,3,2011);
ju2:=juli(5,3,2011);
writeln(ju2-ju1);
end.
Offline
Tak kdysi jsem to mel u zkousky, kde jsem se zamotal v podminkach, tady to je pres 2 funkce a funguje to je tam osetrena podminka, kdyz je prestupny rok a je zadan 1. nebo druhy mesic, aby to nepocitalo den navic. Pokud jde o nacitani pres pole je to zalezitost pouze definici 1 nebo 2 poli a trochu to poupravit. Snizi to pocet promennych.
__________________________________________________________________________
Program Rozdil Dnu;
uses crt;
var
y,d1,d2,m1,m2,r1,r2,pdm1,pdm2:integer;
z,pdr1,pdr2:longint;
function rok(var x,y:integer):longint;
begin
z:=x*365+x div 4-x div 100+x div 400;
if y<3 then
if x mod 4=0 then
if x mod 100<>0 then
z:=z-1;
if y<3 then
if x mod 400=0 then
z:=z-1;
end;
function mesic(var x:integer):integer;
var
i:integer;
pocetdnu: array[1..11] of integer = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30);
begin
y:=0;
if x>1 then
for i:=1 to x-1 do
y:=y+pocetdnu[i];
end;
Begin
write('den1= ');
readln(d1);
write('mesic1= ');
readln(m1);
write('rok1= ');
readln(r1);
write('den2= ');
readln(d2);
write('mesic2= ');
readln(m2);
write('rok2= ');
readln(r2);
rok(r1,m1);
pdr1:=z;
rok(r2,m2);
pdr2:=z;
mesic(m1);
pdm1:=y;
mesic(m2);
pdm2:=y;
writeln('rozdil dnu je ',pdr2-pdr1+pdm2-pdm1+d2-d1);
readln;
End._____________________________________________________________________________
Offline