Newton-Raphson method (square root) in Pascal, recursion - pascal

I want to implement this square root method in Pascal using recursion. However, I have some problems understanding how to transfer iterative method into recursive method:
Program NewtonRaphsonRecursive(output);
{$mode objFPC}
function newton_raphson_rec(a: real; p: real; eps: real; max_i: integer) : real;
var
x: real;
i: integer;
begin
x := a / 2.0;
i := 0;
if abs(x - a / x) < eps then
begin
result := x;
end
else
begin
x := (x + a / x) / 2.0;
i := i + 1;
result := newton_raphson_rec(x, p, eps, max_i);
end;
end;
var
sqroot: real;
begin
sqroot := newton_raphson_rec(25, 0.001, 0.000001, 100);
writeln(sqroot);
end.
The code: https://onlinegdb.com/OvDBfHzLf

If you look at the start of the Newton-Raphson iterative solution in the other question, you will see that the first calculation (x := num / 2.0) is merely a first guess of the solution. You must remove that line in your recursive solution and enter a best guess into the function parameter.
function newton_raphson_recurse(num: real; new_guess: real; eps: real; max_i: integer) : real;
begin
Dec(max_i); // Decrement counter
new_guess := (new_guess + num / new_guess) / 2.0;
if (Abs(new_guess - num) < eps) or (max_i < 1)
then Result := new_guess
else Result := newton_raphson_recurse(num,new_guess,eps,max_I);
end;
...
sqroot := newton_raphson_recurse(9, 9/2.0, 0.0000001, 10);
Note how the new_guess is reused during the recursion with a more accurate value each time.
As always when testing a routine, single stepping into the program is a very good skill to learn when debugging.

Recursion operates on the same basic principles as imperative iteration. You have a starting state, an exit condition that causes termination of recursion/iteration, and an update that updates the state to converge on that exit condition.
Consider a simple example: summing a range.
function SumImperative(s, e : integer) : integer;
var
current : integer;
result : integer;
begin
current := s;
result := 0;
while current <= e do
begin
result := result + current;
current := current + 1
end;
SumImperative := result;
end;
Our function sets an initial state, the while current <= e do sets an exit condition, and current := current + 1 updates the state.
Now, recursively...
function SumRecursive(s, e : integer) : integer;
begin
if s > e then
SumRecursive := 0
else
SumRecursive := s + SumRecursive(s + 1, e)
end;
Here we set our initial state with the fucntion arguments. Our exit condition is s being greater than e. If that happens, the function returns 0 and there is no more recursion. If that codnition isn't met, we add s to the result of calling the fucntion again, but this time we update the state so that we're looking for s + 1 and e.
This looks like:
SumRecursive(1, 4)
1 + SumRecursive(2, 4)
1 + (2 + SumRecursive(3, 4))
1 + (2 + (3 + SumRecursive(4, 4)))
1 + (2 + (3 + (4 + SumRecursive(5, 4))))
1 + (2 + (3 + (4 + 0)))
1 + (2 + (3 + 4))
1 + (2 + 7)
1 + 9
10

Related

Quicksort script works, but heapsort one doesn't

I've been using a quicksort function to sort my stringlists, but as an exercise I wanted to try and code an heapsort function too. Unfortunately it does not work and I can't understand why. The utility functions I use work (because I use them in the quicksort script too and trying both on a list the quicksort one works and the other doesn't)
{------------------------------------------------------------------------------}
Procedure Heapify(AList : TStringList; N, Root : Integer);
Var
Max, L, R : Integer;
Begin
Max := Root;
L := (2 * Root) + 1;
R := (2 * Root) + 2;
If (L < N) And (ListSort(AList, Max, L) < 0 {function to compare strings, read as List[L]>List[Max]}) Then Max := L;
If (R < N) And (ListSort(AList, Max, R) < 0) Then Max := R;
If Max <> Root Then
Begin
ExchangeItems(AList, Root, Max); {Function to swap strings}
Heapify(AList, N, Max);
End;
End;
{------------------------------------------------------------------------------}
Procedure HeapSortStringList(AList : TStringList);
Var
I : Integer;
Begin
For I := (AList.Count / 2) - 1 DownTo 0 Do Heapify(AList, AList.Count, I);
For I := AList.Count - 1 DownTo 1 Do
Begin
ExchangeItems(AList, I, 0);
Heapify(AList, I, 0);
End;
End;
{------------------------------------------------------------------------------}
How did you compile this code?
Note that compiler gives us message:
[dcc32 Error] Unit2.pas(175): E2010 Incompatible types: 'Integer' and
'Extended'
(AList.Count / 2) should be (AList.Count div 2) for integers
After this correction code becomes working.

Limiting Ord to letters only

I'm trying to create a simple Crypting method for a school project, the idea is to change a character by increasing it's ascii with a user entered number then replacing it back.
So my problem is when I do it, it works, but it also includes symboles like %$! ...etc.
What I want to do is to limit the Ord function to letters only, For example if the user entered the number 100 but there's only 26 letters in the alphabet, it will keep looping over and over through that 26 till it reaches the 100th.
Hope I'm clear enough lol
Here's what I have so far, a part of a whole code:
Procedure Crypting( Var cryptFile : Text; tempVar2 : String; pNumber: Integer);
Begin
Writeln('Enter P : ');
Readln(P);
Reset( cryptFile );
For i:= 1 to length(tempVar2) do
Write(Chr(Ord(tempVar2[i])+P));
End;
It seems like you are looking to implement the Caesar cipher.
First, you need to use an if statement to check if the current character is a letter or not. If so, you transform it; if not, you leave it as it is.
Second, it is not enough to simply add P to the character code. Although it works for A and P = 3, producing D, what will happen for Y and P = 3? You need to use modular arithmetic so you get Y → Z → A → B.
Third, in programming, it is important to structure your code well and refactor it properly. Currently, you mix input and transformation. You should keep these separate. If you create a Caesar function, you can use it every time you need to perform the Caesar cipher.
If we also need to support both capital and small letters, it is better to use a case construct instead of an if .. else if .. else construct.
Putting it all together:
function Caesar(const S: string; N: Integer): string; // slow
var
i: Integer;
begin
Result := '';
for i := 1 to Length(S) do
case S[i] of
'A'..'Z':
Result := Result + Chr(Ord('A') + (Ord(S[i]) - Ord('A') + N) mod 26);
'a'..'z':
Result := Result + Chr(Ord('a') + (Ord(S[i]) - Ord('a') + N) mod 26);
else
Result := Result + S[i];
end;
end;
This function works, but is not optimal from a performance point of view, since you need a heap allocation for every iteration. It is better to allocate the result string once and then only fill it:
function Caesar(const S: string; N: Integer): string;
var
i: Integer;
begin
SetLength(Result, Length(S));
for i := 1 to Length(S) do
case S[i] of
'A'..'Z':
Result[i] := Chr(Ord('A') + (Ord(S[i]) - Ord('A') + N) mod 26);
'a'..'z':
Result[i] := Chr(Ord('a') + (Ord(S[i]) - Ord('a') + N) mod 26);
else
Result[i] := S[i];
end;
end;
A complete example:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
function Caesar(const S: string; N: Integer): string;
var
i: Integer;
begin
SetLength(Result, Length(S));
for i := 1 to Length(S) do
case S[i] of
'A'..'Z':
Result[i] := Chr(Ord('A') + (Ord(S[i]) - Ord('A') + N) mod 26);
'a'..'z':
Result[i] := Chr(Ord('a') + (Ord(S[i]) - Ord('a') + N) mod 26);
else
Result[i] := S[i];
end;
end;
var
s: string;
N: Integer;
begin
Writeln('Please enter a string to transform:');
Readln(s);
Writeln('Please enter shift size:');
Readln(N);
Writeln;
Writeln('Result: ', Caesar(s, N));
Writeln;
Writeln('Thank you for using this program! Have a nice day!');
Writeln('Press Return to exit.');
Readln;
end.
(The precise program structure depends on the kind of Pascal you are using -- there are many different kinds of Pascal.)
Screenshot:

Pascal - Sum of odd numbers between 0 and X

I've beeng having some trouble with this code... I need to create an algorithm which makes the user input a number (X), and then the program calculates the sum of all the odd numbers below (x).
This what I've tried so far, but can't really wrap my head around the logic behind it:
Program odd_numbers;
Var
Num, Limite, Soma: integer;
Begin;
Soma := 0;
Writeln('Choose a limit:');
Readln(Limite);
While (Limite / 2 > 0) do
Begin;
Soma := ((Num < Limite) mod 2 > 0);
Writeln('The sum of odd numbers from 0 to ', Limite, ' é ', Soma);
End;
if (Limite mod 2 = 0) then
Begin;
Soma := ((Num < Limite) mod 2 = 0);
Writeln('The sum of odd numbers from 0 to ', Limite, ' é ', Soma);
End;
End.
*PS: Been writing the code with variables in Portuguese, so don't mind the variables appearing weird to understand. *
I see that everyone is happily looping, but this is not necessary. This is a simple arithmetic sequence, and the sum can be calculated without a loop.
Just think of the following:
1 + 3 = 2 * (1 + 3) / 2 = 2 * 2 = 4 ; limits 3 and 4
1 + 3 + 5 = 3 * (1 + 5) / 2 = 3 * 3 = 9 ; limits 5 and 6
1 + 3 + 5 + 7 = 4 * (1 + 7) / 2 = 4 * 4 = 16 ; limits 7 and 8
1 + 3 + 5 + 7 + 9 = 5 * (1 + 9) / 2 = 5 * 5 = 25 ; limits 9 and 10
1 + 3 + 5 + 7 + 9 + 11 = 6 * (1 + 11) / 2 = 6 * 6 = 36 ; limits 11 and 12
But not only that, you'll see that it is in fact always a perfect square: Sqr((n+1) div 2).
So just calculate:
program odd_numbers;
var
Num, Limite, Soma: Integer;
begin
Write('Choose a limit: ');
Readln(Limite);
Num := (Limite + 1) div 2;
Soma := Num * Num;
Writeln('The sum of odd numbers from 0 to ', Limite, ' is ', Soma);
end.
Looks a little simpler than what the others propose.
The loop While (Limite / 2 > 0) do ... uses real arithmetic and not integer arithmetic. I guess you mean While (Limite div 2 > 0) do ... And you should change Limite in the loop otherwise you get stuck because the exit condition can never be reached.
After you have asked the user to enter a number, Limite, you need to keep that unchanged, because you need it in the final message. You also need a loop where you go through all numbers from Limite towards 0.
You started with a while loop which is ok, you are just missing the loop control variable. That is a variable that eventually gets a terminating value which then stops the loop. Use for example the Num variable you already have declared. You can use the same variable to investigate the numbers between user input and 0, for being odd values.
num := limite-1; // give num a start value based on user input (-1 because of "... numbers below (x)")
while num > 0 do // stop the loop when 0 is reached
begin
// here you investigate if `num` is a odd number (e.g. using `mod` operator or
// possibly your pascal has a built in `function Odd(value: integer): boolean;`)
// and add it to `Soma` if it is
num := num - 1;// decrement num at every iteration
end;
Finally you need to consider changes to the above, to handle negative input from the user.
To test if an integer is an odd value, you could use following function:
function IsOdd( value : Integer) : Boolean;
begin
IsOdd := (value mod 2) <> 0;
end;
Many pascal compilers have a built-in function called Odd(), which you could use.
A while loop works well to solve this problem. If you start with lowest odd number above zero, i.e. one and continue upwards so long we do not exceed the limit value we have a simple start:
function GetOddSumBelowX( X : Integer) : Integer;
var
i,sum: Integer;
begin
i := 1; // Start with first odd number
sum := 0;
while (i < X) do begin // as long as i less than X, loop
if IsOdd(i) then begin
sum := sum + i; // add to sum
end;
i := i + 1; // Increment i
end;
GetOddSumBelowX := sum;
end;
Now, that was simple enough. Next step to simplify the loop is to increment the i variable by two instead, just to jump between all odd numbers:
function GetOddSumBelowX( X : Integer) : Integer;
var
i,sum: Integer;
begin
i := 1; // Start with first odd number
sum := 0;
while (i < X) do begin // as long as i less than X, loop
sum := sum + i; // add to sum
i := i + 2; // Increment to next odd number
end;
GetOddSumBelowX := sum;
end;

Optimize a perfect number check to O(sqrt(n))

Part of the program I have checks if an input number is a perfect number. We're supposed to find a solution that runs in O(sqrt(n)). The rest of my program runs in constant time, but this function is holding me back.
function Perfect(x: integer): boolean;
var
i: integer;
sum: integer=0;
begin
for i := 1 to x-1 do
if (x mod i = 0) then
sum := sum + i;
if sum = x then
exit(true)
else
exit(false);
end;
This runs in O(n) time, and I need to cut it down to O(sqrt(n)) time.
These are the options I've come up with:
(1) Find a way to make the for loop go from 1 to sqrt(x)...
(2) Find a way to check for a perfect number that doesn't use a for loop...
Any suggestions? I appreciate any hints, tips, instruction, etc. :)
You need to iterate the cycle not for i := 1 to x-1 but for i := 2 to trunc(sqrt(x)).
The highest integer divisor is x but we do not take it in into account when looking for perfect numbers. We increment sum by 1 instead (or initialize it with 1 - not 0).
The code if (x mod i = 0) then sum := sum + i; for this purpose can be converted to:
if (x mod i = 0) then
begin
sum := sum + i;
sum := sum + (x div i);
end;
And so we get the following code:
function Perfect(x: integer): boolean;
var
i: integer;
sum: integer = 1;
sqrtx: integer;
begin
sqrtx := trunc(sqrt(x));
i := 2;
while i <= sqrtx do
begin
if (x mod i = 0) then
begin
sum := sum + i;
sum := sum + (x div i) // you can also compare i and x div i
//to avoid adding the same number twice
//for example when x = 4 both 2 and 4 div 2 will be added
end;
inc(i);
end;
if sum = x then
exit(true)
else
exit(false);
end;

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