Difference between two dates in Pascal - pascal

This program is supposed to find the difference between two dates but it has a bug and I can't find it.
It keeps returning a big number - please help
Program tp4;
Type
dt = Record
jour : Integer;
mois : Integer;
annee : Integer;
End;
Var
date : dt ;
y,x,i,s : Integer;
Begin
x := 0;
s := 0;
For y:=1 To 2 Do
//2 dates
Begin
Writeln('Entrez un date : jour mois année ');
Readln( date.jour, date.mois, date.annee);
While ((date.jour<=0) Or (date.jour>31) Or (date.mois>12) Or (date.annee<=0) ) Do
//verfication loop
Begin
Writeln('Entrez une date valide : jour mois année ');
Readln(date.jour ,date.mois ,date.annee);
End;
s := s+date.jour ;
For i:= 1 To date.mois-1 Do
Case i Of
3,5,7,8,10,12,1 : s := s+31;
4,6,9,11 : s := s +30;
2 : If ((date.annee Mod 100)=0) And ((date.annee Mod 400) = 0 ) Then //convert months to days
s := s+29
Else If date.annee Mod 4 = 0 Then
s := s+29
Else s := s+28;
End; //Convert years to days
For i:= 1 To date.annee Do
If (i Mod 100 = 0) And (i Mod 400 = 0) Then s := s+366
Else If (i Mod 4 =0) Then s := s+366
Else s := s+365;
x:=s-x ;
End;
If (x)<=0 Then
Writeln('la difference est :',-x)
Else Writeln('la difference est :',x);
Readln;
End.
**input**
12 03 2019
13 03 2019
**output**
737510

I think the error was somewhere in s and x (x:=s-x; etc.), I did refactoring:
Program tp4;
Type dt = Record
jour : Integer;
mois : Integer;
annee : Integer;
End;
Type
arrayDate = array[1..2] of dt;
Var
y,i,f,s : Integer;
arrDate: arrayDate;
function Leap (Y : Word): Boolean;
Begin
If (Y Mod 4) <> 0 Then Leap := FALSE
Else If (Y Mod 100) <> 0 Then Leap := TRUE
Else Leap := (Y Mod 400) = 0;
End;
function Lenght (date: dt) : Integer;
Begin
Lenght := 0;
Lenght := Lenght + date.jour;
For i := 1 To date.mois Do
Case i Of
3, 5, 7, 8, 10, 12, 1 : Lenght := Lenght + 31;
4, 6, 9, 11 : Lenght := Lenght + 30;
2 : If Leap (date.annee) Then Lenght := Lenght + 29 Else Lenght:= Lenght + 28;
End;
For i := 1 To date.annee Do //Convert years to days
If Leap (i) Then Lenght := Lenght + 366 Else Lenght := Lenght + 365;
End;
Begin
For y := 1 To 2 Do //2 dates
Begin Writeln ('Entrez un date : jour mois année ');
Readln (arrDate[y].jour, arrDate[y].mois, arrDate[y].annee);
While ((arrDate[y].jour <= 0)
Or (arrDate[y].jour > 31)
Or (arrDate[y].mois > 12)
Or (arrDate[y].annee <= 0)) Do //verfication loop
Begin
Writeln ('Entrez une date valide : jour mois année ');
Readln (arrDate[y].jour, arrDate[y].mois, arrDate[y].annee);
End;
End;
f := Lenght(arrDate[1]);
s := Lenght(arrDate[2]);
Writeln ('la difference est :', Abs(s - f)); // absolute |s-f|
Readln;
End.

You are using the For y ... loop to request input and to calculate number of days for each input. Within the loop, the s variable is the days counter.
The error you do is that you zero s bfore the For y ... loop and not at the beginning of the loop. Therefore, the second time you request a date, s still has the value from the first date, on top of which you then start to calculate the days for the second date.
The correction is of course to move s := 0; to the beginning of the For y ... loop,
or change the first assignment of s from
s := s + date.jour;
to
s := date.jour;

Finding the difference between two dates 6,000 years apart in a loop? And (ab)using the name of a standard function "Length"? Ouch!
Try this:
//----------------------------------------------------------------------
// Convert a date to its Julian Day Number
//----------------------------------------------------------------------
procedure cj(dd, mm, yyyy: longint; var jdn, dow: longint);
var
cj_y,
cj_c,
cj_x,
cj_y: double;
begin
if dd = 0 then
begin
jdn:= -1
dow:= -1;
end
else
begin
cj_y:= yyyy + (mm - 2.85) / 12;
cj_c:= 0.75 * trunc(cj_y * 0.01);
cj_x:= frac(cj_y);
cj_y:= trunc(cj_y);
jdn:= trunc(
trunc(
trunc(367 * cj_x) + 367 * (cj_y) -
1.75 * cj_y + dd) - cj_c) +
1721115.0;
dow:= jdn mod 7;
end;
end; {cj}
Formula as given is valid for days after 1582-10-15, a small tweak will allow dates going back to 0000-03-01.
Follow the link in https://groups.google.com/g/comp.lang.pascal.borland/c/itwgcfYpLEU which I posted in August 1998 in comp.lang.pascal.borland for explanations.

Related

Pascal print numbers alternately

I have a task to print each number from the input alternately, firstly numbers with even indexes, then numbers with odd indexes. I have solved it, but only for one line of numbers, but I have to read n lines of numbers.
Expected input:
2
3 5 7 2
4 2 1 4 3
Expected output:
7 5 2
1 3 2 4
Where 2 is number of lines, 3 and 4 are numbers of numbers, 5, 7, 2 and 2, 1 , 4, 3 are these numbers.
Program numbers;
Uses crt;
var k,n,x,i,j: integer;
var tab : Array[1..1000] of integer;
var tab1 : Array[1..1000] of integer;
var tab2 : Array[1..1000] of integer;
begin
clrscr;
readln(k);
for i:=1 to k do
begin
read(n);
for j:=1 to n do
begin
read(tab[j]);
if(j mod 2 = 0) then
tab1[j]:=tab[j]
else
begin
tab2[j]:=tab[j];
end;
end;
end;
for j:=1 to n do
if tab1[j]<>0 then write(tab1[j], ' ');
for j:=1 to n do
if tab2[j]<>0 then write(tab2[j], ' ');
end.
Let's clean up the formatting, and use a record to keep track of each "line" of input.
program numbers;
uses
crt;
type
TLine = record
count : integer;
numbers : array[1..1000] of integer
end;
var
numLines, i, j : integer;
lines : Array[1..1000] of TLine;
begin
clrscr;
readln(numLines);
for i := 1 to numLines do
begin
read(lines[i].count);
for j := 1 to lines[i].count do
read(lines[i].numbers[j])
end
end.
We can read each line in. Now, how do we print the odd and even indices together? Well, we could do math on each index, or we could just increment by 2 instead of 1 using a while loop.
program numbers;
uses
crt;
type
TLine = record
count : integer;
numbers : array[1..1000] of integer
end;
var
numLines, i, j : integer;
lines : Array[1..1000] of TLine;
begin
clrscr;
readln(numLines);
// Read in lines.
for i := 1 to numLines do
begin
read(lines[i].count);
for j := 1 to lines[i].count do
read(lines[i].numbers[j])
end;
// Print out lines.
for i := 1 to numLines do
begin
j := 1;
while j <= lines[i].count do
begin
write(lines[i].numbers[j], ' ');
j := j + 2
end;
j := 2;
while j <= lines[i].count do
begin
write(lines[i].numbers[j], ' ');
j := j + 2
end;
writeln
end
end.
Now if we run this:
2
3 4 5 6
4 6 2 4 1
4 6 5
6 4 2 1
One thing we can note is that the following loop is the same for both odd and even indexes, except for the start index.
while j <= lines[i].count do
begin
write(lines[i].numbers[j], ' ');
j := j + 2
end;
This is a perfect place to use a procedure. Let's call it PrintEveryOther and have it take an index to start from and a line to print.
program numbers;
uses
crt;
type
TLine = record
count : integer;
numbers : array[1..1000] of integer
end;
var
numLines, i, j : integer;
lines : Array[1..1000] of TLine;
procedure PrintEveryOther(start : integer; line :TLine);
var
i : integer;
begin
i := start;
while i <= line.count do
begin
write(line.numbers[i], ' ');
i := i + 2
end
end;
begin
clrscr;
readln(numLines);
for i := 1 to numLines do
begin
read(lines[i].count);
for j := 1 to lines[i].count do
read(lines[i].numbers[j])
end;
for i := 1 to numLines do
begin
PrintEveryOther(1, lines[i]);
PrintEveryOther(2, lines[i]);
writeln
end
end.

Get the minimum amount of degrees recorded in a day

I need to make a program that gets the minimum amount of degrees recorded in a day at what hour, I made the program, I am getting the correct hour at which the min amount of degrees were recorded but I am not getting the correct amount of degrees
Program P1;
Type
Hour = 0..23;
Degrees = -40..40;
Temperature = array [Hour] of Degrees;
var
t : Temperature;
i, min_t, max_t, hour_t_min, hour_t_max : integer;
procedure test;
begin
for i := 0 to 23 do
begin
writeln('Enter the temperature at hour ', i);
readln(t[i]);
min_t := t[0];
if min_t > t[i] then
begin
min_t := t[i];
ora_t_min := i;
end;
if max_t < t[i] then
begin
max_t := t[i];
ora_t_max := i;
end;
end;
writeln('temp min ', min_t, ' at hour ', hour_t_min);
writeln('temp max ', max_t, ' at hour ', hour_t_max);
end; {procedure}
begin { main }
test;
end.
Min_t (and max_t) should be initialized outside and before the loop.
You are assigning min_t:=t[0] in each loop, this is wrong, and max_t is not being initialized. Also, I think this is a typo, ora_t_min and ora_t_max should be changed to hour_t_min and hour_t_max:
Something like this:
min_t := 40;
max_t := -40;
for i := 0 to 23 do
begin
writeln('Enter the temperature at hour ', i);
readln(t[i]);
if min_t > t[i] then begin min_t := t[i]; hour_t_min := i; end;
if max_t < t[i] then begin max_t := t[i]; hour_t_max := i; end;
end;
writeln('temp min ', min_t, ' at hour ', hour_t_min);
writeln('temp max ', max_t, ' at hour ', hour_t_max);
end;

Read integers from a string

I'm learning algorithms and I'm trying to make an algorithm that extracts numbers lets say n in [1..100] from a string. Hopefully I get an easier algorithm.
I tried the following :
procedure ReadQuery(var t : tab); // t is an array of Integer.
var
x,v,e : Integer;
inputs : String;
begin
//readln(inputs);
inputs:='1 2 3';
j:= 1;
// make sure that there is one space between two integers
repeat
x:= pos(' ', inputs); // position of the space
delete(inputs, x, 1)
until (x = 0);
x:= pos(' ', inputs); // position of the space
while x <> 0 do
begin
x:= pos(' ', inputs); //(1) '1_2_3' (2) '2_3'
val(copy(inputs, 1, x-1), v, e); // v = value | e = error pos
t[j]:=v;
delete(inputs, 1, x); //(1) '2_3' (2) '3'
j:=j+1; //(1) j = 2 (2) j = 3
//writeln(v);
end;
//j:=j+1; // <--- The mistake were simply here.
val(inputs, v, e);
t[j]:=v;
//writeln(v);
end;
I get this result ( resolved ) :
1
2
0
3
expected :
1
2
3
PS : I'm not very advanced, so excuse me for reducing you to basics.
Thanks for everyone who is trying to share knowledge.
Your code is rather inefficient and it also doesn't work for strings containing numbers in general.
A standard and performant approach would be like this:
type
TIntArr = array of Integer;
function GetNumbers(const S: string): TIntArr;
const
AllocStep = 1024;
Digits = ['0'..'9'];
var
i: Integer;
InNumber: Boolean;
NumStartPos: Integer;
NumCount: Integer;
procedure Add(Value: Integer);
begin
if NumCount = Length(Result) then
SetLength(Result, Length(Result) + AllocStep);
Result[NumCount] := Value;
Inc(NumCount);
end;
begin
InNumber := False;
NumCount := 0;
for i := 1 to S.Length do
if not InNumber then
begin
if S[i] in Digits then
begin
NumStartPos := i;
InNumber := True;
end;
end
else
begin
if not (S[i] in Digits) then
begin
Add(StrToInt(Copy(S, NumStartPos, i - NumStartPos)));
InNumber := False;
end;
end;
if InNumber then
Add(StrToInt(Copy(S, NumStartPos)));
SetLength(Result, NumCount);
end;
This code is intentionally written in a somewhat old-fashioned Pascal way. If you are using a modern version of Delphi, you wouldn't write it like this. (Instead, you'd use a TList<Integer> and make a few other adjustments.)
Try with the following inputs:
521 cats, 432 dogs, and 1487 rabbits
1 2 3 4 5000 star 6000
alpha1beta2gamma3delta
a1024b2048cdef32
a1b2c3
32h50s
5020
012 123!
horses
(empty string)
Make sure you fully understand the algorithm! Run it on paper a few times, line by line.

Divisibility of numbers in pascal

I want to write a pascal program that checks if particular number is divisible by 2, 3, 5, 7, 9 and 11 and whether the sum of the digits is even or odd. In the very end I want to write a statement like "This number is divisible by 5 and 9" and the sum of the numbers is even/odd. What should I do?
Use modulus:
program ModulusTest;
begin
if 8 mod 2 = 0 then
begin
write(8);
writeln(' is even');
end;
if 30 mod 5 = 0 then
begin
write(30);
writeln(' is divisible by 5');
end;
if 32 mod 5 <> 0 then
begin
write(32);
writeln(' is not divisible by 5');
end;
end.
Modulus is what remains after an integer division :)
This's my code, I separate into 2 sections :
program checkNumber;
var number : integer;
divider : string;
digit1, digit2, sum : integer;
begin
//First//
write('Number : '); readln(number);
if (number MOD 2 = 0) then divider := divider+'2, ';
if (number MOD 3 = 0) then divider := divider+'3, ';
if (number MOD 5 = 0) then divider := divider+'5, ';
if (number MOD 7 = 0) then divider := divider+'7, ';
if (number MOD 9 = 0) then divider := divider+'9, ';
if (number MOD 11 = 0) then divider := divider+'11, ';
write('This number is divisible by '); write(divider);
////////////////////////////////////////////////////////
//Second//
digit1 := number DIV 10;
digit2 := number MOD 10;
sum := digit1 + digit2;
write('and the sum of the numbers is ');
if (sum MOD 2 = 0) then write('even') else write('odd');
////////////////////////////////////////////////////////
end.
First part
You need MOD(modulus) operation to get the list of divider values:
write('Number : '); readln(number);
if (number MOD 2 = 0) then divider := divider+'2, ';
if (number MOD 3 = 0) then divider := divider+'3, '; //divider 2 3 5 7 9 11
.
.
Then save the divider into variable divider as string, and write it on monitor.
write('This number is divisible by '); write(divider);
Second part
You need to separate the digits into single variable using DIV(divide) and MOD(modulus) operation. In my code, I limit the number input for 2 digit (1 until 99):
digit1 := number DIV 10;
digit2 := number MOD 10;
sum := digit1 + digit2;
(You change the code use if..then.. function if you want input bigger number).
Then use MOD to check the number is even or odd:
if (sum MOD 2 = 0) then write('even') else write('odd');

A game with 100 oponnents, win as much money as possible

You play a game with 100 opponents. The game has k rounds. Every round you can eliminate some opponents (always atleast 1). You are rewarded for eliminating them.
The reward is: 100.000 * '# of eliminated opponents' / '# of opponents' <= in integers (rounded down)
I want to eliminate the opponents in a way, that gets me the largest amount of money possible.
Example game:
number of rounds = 3
first round we eliminate 50 opponents, so we get 100.000 * 50 / 100 = +50.000
second round we eliminate 30, so we get 100.000 * 30 / 50 = +60.000
last round we eliminate last 20 opponents, so we get 100.000 * 20 / 20 = +100.000
so the total winnings are: 210.000
I tried to write up something, but I don't think it's the most effective way to do it?
Program EliminationGame;
var
selectedHistory : array [1..10] of integer;
opponentCount,roundCount : integer;
maxOpponents,numberSelected : integer;
totalMoney : integer;
i : integer;
begin
totalMoney := 0;
maxOpponents := 100;
opponentCount := maxOpponents;
roundCount := 3; {test value}
for i:=1 to roundCount do begin
if (i = roundCount) then begin
numberSelected := opponentCount;
end else begin
numberSelected := floor(opponentCount / roundCount);
end;
selectedHistory[i] := numberSelected;
totalMoney := floor(totalMoney + (numberSelected / opponentCount * 100000));
opponentCount := opponentCount - numberSelected;
end;
writeln('Total money won:');
writeln(totalMoney);
writeln('Amount selected in rounds:');
for i:= 0 to Length(selectedHistory) do
write(selectedHistory[i],' ');
end.
Also it seems that floor function does not exist in pascal?
It seems the question has a maths answer that can be calculated in advance. As #Anton said it was obvious that the number of points given during the third round did not depend upon the number of eliminated enemies. So the third round should eliminate 1 enemy.
So We get the following function for a thre-round game.
f(x)=100000x/100+100000(99-x)/(100-x)+100000*1/1, where x- the number
of enemies eleminated at first round.
if we find the extrema (local maximum of the function) it appears equal to 90. That means the decision is the following: the first round eliminates 90 the second - 9, the third - 1 enemy.
Of course, for consideration: 90=100-sqrt(100).
In other words: the Pascal decision of the task is to loop a variable from 1 to 99 and see the maximum of this function. X-will be the answer.
program Project1;
var
x, xmax: byte;
MaxRes, tmp: real;
begin
xmax := 0;
MaxRes := 0;
for x := 1 to 99 do
begin
tmp := 100000 * x / 100 + 100000*(99 - x) / (100 - x) + 100000 * 1 / 1;
if tmp > MaxRes then
begin
MaxRes := tmp;
xmax := x;
end;
end;
writeln(xmax);
readln;
end.
The general decision for other number of enemies and rounds (using recursion) is the following (Delphi dialect):
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
Uses System.SysUtils;
var
s: string;
function Part(RemainingEnemies: byte; Depth: byte;
var OutputString: string): real;
var
i: byte;
tmp, MaxRes: real;
imax: byte;
DaughterString: string;
begin
OutputString := '';
if Depth = 0 then
exit(0);
imax := 0;
MaxRes := 0;
for i := 1 to RemainingEnemies - Depth + 1 do
begin
tmp := i / RemainingEnemies * 100000 + Part(RemainingEnemies - i, Depth - 1,
DaughterString);
if tmp > MaxRes then
begin
MaxRes := tmp;
imax := i;
OutputString := inttostr(imax) + ' ' + DaughterString;
end;
end;
result := MaxRes;
end;
begin
writeln(Part(100, 3, s):10:1);//first parameter-Enemies count,
//2-Number of rounds,
//3-output for eliminated enemies counter
writeln(s);
readln;
end.
This problem can be solved with a dynamic approach.
F(round,number_of_opponents_remained):
res = 0
opp // number_of_opponents_remained
for i in [1 opp]
res = max(res, opp/100 + F(round-1,opp - i) )
return res
I should say this not the complete solution and you add some details about it, and I am just giving you an idea. You should add some details such as base case and checking if opp>0 and some other details. The complexity of this algorithm is O(100*k).

Resources