Evaluating statements with negative numbers in Pascal - pascal

the following piece of code is meant to find the maximum number from a range of entered numbers. The entry is concluded once 0 is entered (0 is not taken into account when determining the maximum). It seems to be working for positive numbers but for a range of negative numbers it always says maximum is 0. Can anyone tell me where the error is?
program MaximumEndZero (input, output);
var
Max,
Value : integer;
begin
writeln('Enter numbers');
readln(Value);
if (Value = 0) then
writeln('No input')
else
begin
Max := Value;
while Value <> 0 do
begin
readln(Value);
if Value > Max then
Max := Value
end;
writeln('Max is: ', Max)
end;
end.
Thanks vm

You have created this problem by yourself by using the value of Value to signal the end of the program and then not taking account of this special meaning (Value = 0) in your code which works out which value is the maximum.
Just change your code to
if (Value <> 0) and (Value > Max) then
Max := Value
The (Value <> 0) and effectively says "ignoring Value if it happens to be zero ..."

Related

Can't display the final output once the user enters a negative number in PL/SQL

I can't display the final output once the user has entered a negative number.
I tried creating a program that will ask the user for numbers continuously. If the user enters a negative number, the program will stop running and will display the total, average, number of zeroes entered, highest and lowest number. Below is my written code:
SET SERVEROUTPUT ON;
DECLARE
n NUMBER(3);
total NUMBER(3) := 0;
numZeros NUMBER(3) := 0;
average NUMBER(3);
highest NUMBER(3) := 0;
lowest NUMBER(3) := 0;
BEGIN
LOOP
n := &n;
total := total + n;
IF n = 0 THEN
numZeros := numZeros + 1;
ELSIF n > highest THEN
high := n;
ELSIF n < lowest THEN
low := n;
END IF;
EXIT WHEN n < 0;
END LOOP;
average := total / n;
DBMS_OUTPUT.PUT_LINE('Total: ' || total);
DBMS_OUTPUT.PUT_LINE('Average: ' || average);
DBMS_OUTPUT.PUT_LINE('Number of zeros: ' || numZeros);
DBMS_OUTPUT.PUT_LINE('Highest number: ' || highest);
DBMS_OUTPUT.PUT_LINE('Lowest number: ' || lowest);
END;
The output throws an error saying how 'N' is not a procedure. I would appreciate some help in solving this issue.
There is a fundamental issue with your code, & is a substitution variable and is evaluated by the client application (i.e. SQL*Plus, SQL Developer or another client that supports substitution variables, which not all Oracle clients do) and is effectively implemented as if a find-replace was done on the source code.
Once the client has substituted the substitution variable then the statement is sent to the database where the PL/SQL engine will parse it. The PL/SQL engine never sees the substitution variable (because it is processed by the client application) and even if it did it would not understand how to handle it.
This means that you will be prompted for the replacement ONCE (and only once) and then that value will be used in every loop iteration so the loop will either never exit, if you enter a positive number first, or exit immediately, if you enter a negative number first.
If you want to enter a list of values then you need to enter them all at once:
SET SERVEROUTPUT ON;
DECLARE
items SYS.ODCINUMBERLIST := SYS.ODCINUMBERLIST(0,1,2,3,4,5);
total NUMBER(3,0) := 0;
numZeros NUMBER(3,0) := 0;
average NUMBER(5,2) := NULL;
highest NUMBER(3,0) := NULL;
lowest NUMBER(3,0) := NULL;
BEGIN
FOR i IN 1 .. items.COUNT LOOP
total := total + items(i);
IF items(i) = 0 THEN
numZeros := numZeros + 1;
END IF;
IF highest IS NULL OR items(i) > highest THEN
highest := items(i);
END IF;
IF lowest IS NULL OR items(i) < lowest THEN
lowest := items(i);
END IF;
END LOOP;
IF items.COUNT > 0 THEN
average := total / items.COUNT;
END IF;
DBMS_OUTPUT.PUT_LINE('Total: ' || total);
DBMS_OUTPUT.PUT_LINE('Average: ' || average);
DBMS_OUTPUT.PUT_LINE('Number of zeros: ' || numZeros);
DBMS_OUTPUT.PUT_LINE('Highest number: ' || highest);
DBMS_OUTPUT.PUT_LINE('Lowest number: ' || lowest);
END;
/
or, using SQL:
DECLARE
items SYS.ODCINUMBERLIST := SYS.ODCINUMBERLIST(0,1,2,3,4,5);
total NUMBER(3,0) := 0;
numZeros NUMBER(3,0) := 0;
average NUMBER(5,2) := NULL;
highest NUMBER(3,0) := NULL;
lowest NUMBER(3,0) := NULL;
BEGIN
SELECT COALESCE(SUM(column_value),0),
COUNT(CASE column_value WHEN 0 THEN 1 END),
AVG(column_value),
MAX(column_value),
MIN(column_value)
INTO total,
numZeros,
average,
highest,
lowest
FROM TABLE(items);
DBMS_OUTPUT.PUT_LINE('Total: ' || total);
DBMS_OUTPUT.PUT_LINE('Average: ' || average);
DBMS_OUTPUT.PUT_LINE('Number of zeros: ' || numZeros);
DBMS_OUTPUT.PUT_LINE('Highest number: ' || highest);
DBMS_OUTPUT.PUT_LINE('Lowest number: ' || lowest);
END;
/
fiddle
If you want to take user input then you can replace the initial lines with:
SET SERVEROUTPUT ON;
ACCEPT number_list CHAR PROMPT 'Enter a comma-delimited list of numbers:'
DECLARE
items SYS.ODCINUMBERLIST := SYS.ODCINUMBERLIST(&&number_list);
Change this line:
n := &n;
Remove n;. It should be:
n := &
I don't know if you made a mistake with this line:
high := n;
It should be:
highest := n;
Same with this line:
low := n;
which should be:
lowest := n;
After that, when I run the code, I get this compilation error:
ORA-06502: PL/SQL: numeric or value error: number precision too large
This is because PL/SQL has no capabilities for getting input from the user during execution of PL/SQL code.
Indeed the &amp is a feature of SQL*Plus and not of PL/SQL.
The loop simply keeps repeating with the first entered value (for &amp) until total becomes larger than 999.
Refer to Taking user input 'n' times PL/SQL
and PL/SQL: how do I prompt user input in a procedure?

Insertion Sort - TStringList Delphi

i'm trying to sort TStringList of integers from a text file with Insertion and Selection Sort .Selection Sort works ok , but the Insertion Sort doesnt work with my code . Can someone tell me where i'm wrong ? My 'numbers.txt' has 5000 lines of numbers. Thanks in advance
UPDATE : I have edited my code a bit , it works now with Insertion-Sort but it sorts just 4 indexes of integer as on the image
var
i, Position, n: integer;
Value: string;
begin
n := Items.Count;
for i := 1 to n - 1 do
begin
Value := Items[i];
Position := i-1;
while (Position >0) and (Items[Position]>Value) do
begin
Items[Position+1]:= Items[Position] ;
Position := Position -1 ;
end;
Items[Position+1] := Value;
end;
end;
Your data in the image is sorting exactly as it should, because you're sorting on string values, and based on the comparison you're making the order is perfect. "1143" falls exactly between the string values "11413" and "11443", because the comparison is made character by character out to the length of the shortest of the values. "1141" < "1143" < "1144", based on the first four characters of each string.
If you want an actual integer sort, then you need to convert the two values to integer before comparing them. Something like this should work (note I did not test your overall sort logic - I just used values that demonstrate the concept):
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, System.Classes;
var
i, Position, n: integer;
Value: integer;
Items: TStringList;
begin
Items := TStringList.Create;
try
Items.DelimitedText := '1116,11170,11178,11206,1122,11221,11228';
n := Items.Count;
for i := 1 to n - 1 do
begin
Value := StrToInt(Items[i]);
Position := i - 1;
while (Position > 0) and (StrToInt(Items[Position]) > Value) do
begin
Items[Position + 1]:= Items[Position];
Position := Position - 1 ;
end;
Items[Position+1] := IntToStr(Value);
end;
for i := 0 to Items.Count - 1 do
WriteLn(Items[i]);
finally
Items.Free;
end;
ReadLn;
end.
The output I got from the code above in a console window:
1116
1122
11170
11178
11206
11221
11228

A misunderstanding about MOD statements or FOR loops in Pascal

I'm trying to teach myself Pascal, and am putting together a program to determine prime numbers. It's crude, and inaccurate, but just a practice exercise.
I've created a FOR loop that will see if a counted number has a remainder if divided by a set of prime numbers. If it doesn't it's not considered prime:
begin
writeln('This program calculates all the integers below a given number');
writeln('Please enter a number greater than 1');
readln(number);
//Need code to deal with entries that equal 1 or less, or aren't integers
prime:=true;
if number >=2 then writeln(2);
if number >=3 then writeln(3);
if number >=5 then writeln(5);
if number >11 then writeln(7);
For count := 1 to number do
begin
if count MOD 2 = 0 then prime:=false;
if count MOD 3 = 0 then prime:=false;
if count MOD 5 = 0 then prime:=false;
if count MOD 7 = 0 then prime:=false;
if prime = true then writeln(count);
writeln ('count= ',count)
end;
writeln('Hit any key to continue');
readln();
end.
However, no matter what number I put in, the For loop prints 1 for the prime number. I've added a count print to see if the loop is working, and it seems to be. Any tips?
Thanks in advance!
Your variable prime is set to true before entering the loop.
Inside the loop, when count is 1, the prime variable is not set again, hence it will print true.
In other words:
1 mod 2 equals 1
1 mod 3 equals 1
1 mod 5 equals 1
1 mod 7 equals 1
Since neither of these statements equals zero, the prime variable is not changed from its initial true value.
If you want to test if a number is a prime using a list of prime numbers, you should iterate from the list of prime numbers.
Here is a simple test that does that.
procedure TestIsPrime( number : Integer);
const
// A loopup table with primes. Expand to cover a larger range.
primes : array[1..4] of Integer = (2,3,5,7);
var
count : Integer;
highTest : Integer;
IsPrime : Boolean;
begin
if (number <= 0) then begin
WriteLn('Illegal number: ',number);
Exit;
end;
IsPrime := number > 1; // 1 is a special case !!
if (number >= Sqr(primes[High(primes)])) then begin
WriteLn('Needs more primes in table to test: ',number);
Exit;
end;
highTest := Trunc(Sqrt(number)); // Highest number to test
for count := 1 to High(primes) do begin
if (highTest >= primes[count]) then begin
if (number MOD primes[count] = 0) then begin
IsPrime := false;
Break;
end;
end
else
Break;
end;
if IsPrime = true then WriteLn(number);
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;

How to find the second largest value with Pascal

I have a Problem to Show the second largest value.
Here is the Code
program testeFeldZweitMax (input, output);
{ testet die Funktion FeldZweitMax }
const
FELDGROESSE = 10;
type
tIndex = 1..FELDGROESSE;
tFeld = array [tIndex] of integer;
var
Feld : tFeld;
i : integer;
function FeldZweitMax (var inFeld : tFeld) : integer;
var
Maximum: integer;
j : tIndex;
begin
Maximum := inFeld[1];
for j := 2 to FELDGROESSE do
if inFeld[j] > Maximum then
Maximum := inFeld[j];
FeldZweitMax := Maximum
end;
begin { Testprogramm }
writeln('Bitte geben Sie ', FELDGROESSE, ' Zahlen ein:');
for i := 1 to FELDGROESSE do
read (Feld [i]);
writeln('Die zweitgroesste Zahl ist ', FeldZweitMax (Feld), '.');
end. { testeFeldZweitMax }
As you can see the Code Show me only the largest value. I Need some help with showing the second largest value.
var
Maximum, ZweitMax: integer;
j : tIndex;
begin
Maximum := inFeld[1];
ZweitMax := inFeld[2];
for j := 1 to FELDGROESSE do
begin
if inFeld[j] < Maximum then
inFeld[j] := Maximum;
Maximum := ZweitMax;
ZweitMax := inFeld[j];
FeldZweitMax := ZweitMax
end
end;
It doesn't work perfectly. Some suggestions for me?
Consider that you have (at some point) the values Maximum > ZweitMax (f.ex. 5 and 2 respectively).
The next value (x) to evaluate might be
a) x > Maximum
b) x > ZweitMax (but less than Maximum)
c) x < ZweitMax
In case a) Maximum should become x and ZweitMax should become previous Maximum
In case b) Maximum should remain and ZweitMax should become x
In case c) no change to Maximum and ZweitMax (IOW, no action required)
A couple of hints:
Initialize both Maximum and ZweitMax to the smallest possible value (according to the type) before you start to evaluate the actual inputted values.
In case a) set ZweitMax to previous Maximum before assigning the new value to Maximum.

Resources