Part of a Pascal ISO 10206 program I am building, requires me to implement a function to exponentiate a real number (x) to Eulers number (e), without using any exponentiation functions already included in Pascal(**,pow,exp...).
I have been trying different algorithms for hours but I cant figure out how to do it without using the already included exponentiation functions.
Any help would be appreciated. Any mathematical algorithm of some sort etc... Thanks in advance.
As others have said, it doesn't make sense not to use Exp() or a function based upon it. But if you really must use something else, and don't want to get too technical/mathematical, then the following should work (the real algorithm is far more complicated and requires much more knowledge of math).
The program uses a combination of the first N terms of Taylor series for the fraction of X and binary exponentiation for the integer part of X. It is probably not very fast, but pretty accurate, even for larger exponents. For comparison, I also display Exp(X). If your Pascal has a Double or Extended type, use those instead of Real.
program SimplePower;
{ Required for Delphi, you can omit it in other Pascals: }
{$APPTYPE CONSOLE}
{ Returns approximate value of e^X using sum of first N terms of Taylor series.
Works fine with X values between 0 and 1.0 and N ~ 30. }
function Exponential(N: Integer; X: Real): Real;
var
I: Integer;
begin
Result := 1.0;
for I := N - 1 downto 1 do
Result := 1.0 + X * Result / I;
end;
{ Binary exponentiation of Base by integer Exponent. }
function IntegerExp(Base: Real; Exponent: Integer): Real;
begin
Result := 1.0;
while Exponent > 0 do
begin
if Odd(Exponent) then
Result := Result * Base;
Base := Base * Base;
Exponent := Exponent shr 1;
end;
end;
{ Combines IntegerExp function for integral part with
Exponential function for fractional part. }
function MyExp(N: Integer; X: Real): Real;
const
E = 2.7182818284590452353602874713527; { from Google: "e euler" }
var
Factor: Real;
Fraction: Real;
begin
Fraction := Exponential(N, Frac(X));
Factor := IntegerExp(E, Trunc(X));
Result := Factor * Fraction;
end;
{ Simple demo: }
const
N = 30;
X = 73.4567890242421234;
begin
Writeln('MyExp(', N, ', ', X:22:18, ') = ', MyExp(N, X):22:18);
Writeln('Exp(', X:22:18, ') = ', Exp(X):22:18);
end.
Ref:
Taylor series for exponentiation
Binary exponentiation
I did not do anything for negative exponents, but just know that Exp(-x) = 1/Exp(x). You could amend MyExpwith that knowledge.
I used the solution pointed out by #RudyVelthuis in some other post, but modified it a bit. It is based upon that x^0.5 = sqrt(x), which we can use to our advantage. Ill leave the Pascal ISO 10206 code I used attached. Thank you all for your help, specially Rudy.
function MyPow(base,power,precision:real):real;
begin
if (power<0) then MyPow:=1/MyPow(base,-power,precision)
else if (power>=10) then MyPow:=sqr(MyPow(base,power/2,precision/2))
else if (power>=1) then MyPow:=base*MyPow(base,power-1,precision)
else if (precision>=1) then MyPow:=sqrt(base)
else MyPow:=sqrt(MyPow(base,power*2,precision*2));
end;
Related
I am working on my school project and I would like to use Dynamic (not static) array. I worked with ObjectPascal, so I am used to some syntax. But now I am programming in the old TurboPascal (I am using Turbo Pascal 7 for Windows).
It doesn't seem to know the ObjectPascal, so I thought, that you Turbo Pascal doesn't know dynamic arrays.
Could anyone tell me, if my theory is right or not? I tried to google, but I was not succesfull.
Basicly I am asking "how is it with dynamic arrays in Turbo Pascal 7" ?
Thank you for all reactions.
As MartynA says, there is no dynamic array type in Turbo Pascal. You need to manually allocate memory using pointers, and be careful if you use rangechecks.
Typically you define an array type
TYPE
TArrayT = array[0.. ((65535-spillbytes) div sizeof(T))-1] of T;
where spillbytes is a constant for a small deduction because you can't use the whole 64k, see what the compiler accepts. (Probably this deduction is for heapmanager structures inside the 64k block)
Then you define a pointer
PArrayT= ^TArrayT;
and a variable to it
var
P : PArrayT;
and you allocate nrelement elements using getmem;
getmem(P,SizeOf(T) * nrelements);
and optionally fill them with zero to initialize them:
fillchar(p^,SizeOf(T) * nrelements,#0);
You can access elements using
p^[index]
to free them, use freemem using the exact opposite of the getmem line.
freemem(P,Sizeof(T)*nrelements);
Which means you have to save the allocated number of elements somewhere. This was fixed/solved in Delphi and FPC.
Also keep in mind that you can't find bugs with rangechecking anymore.
If you want arrays larger than 64k, that is possible, but only with constraints, and it matters more which exact TP target (dos, dos-protected or Windows you use) I advise you to search for the online SWAG archive that has many examples. And of course I would recommend to go to FreePascal/Lazarus too where you can simply do:
var x : array of t;
begin
setlength(x,1000000);
and be done with it without additional lines and forget about all of this nonsense.
I'm using Turbo Pascal 5.5 and to create a dynamic array, perhaps the trick is to declare an array with zero dimension as follows:
dArray = array [0..0] of integer;
And then declare a pointer to that array:
pArray = ^dArray ;
And finally, create a pointer variable:
ArrayPtr : pArray;
You can now reference the pointer variable ArrayPtr as follows:
ArrayPtr^[i]; { The index 'i' is of type integer}
See the complete example below:
{
Title: dynarr.pas
A simple Pascal program demonstrating dynamic array.
Compiled and tested with Turbo Pascal 5.5.
}
program dynamic_array;
{Main Program starts here}
type
dArray = array [0..0] of integer;
pArray = ^dArray ;
var
i : integer;
ArrayPtr : pArray;
begin
for i := 0 to 9 do { In this case, array index starts at 0 instead of 1. }
ArrayPtr^[i] := i + 1;
writeln('The Dynamic Array now contains the following:');
writeln;
for i := 0 to 9 do
writeln(ArrayPtr^[i]);
end.
In this example, we have declared the array as:
array[0..0] of integer;
Therefore, the index starts at 0 and if we have n elements, the last element is at index n-1 which is similar to array indexing in C/C++.
Regular Pascal arrays start at 1 but for this case, it starts at 0.
unit Vector;
interface
const MaxVector = 8000;
// 64 k div SizeOf(float); number of float-values that fit in 64 K of stack
VectorError: boolean = False;
// toggle if error occurs. Calling routine can handle or abort
type
VectorStruc = record
Length: word;
Data: array [1..MaxVector] of float;
end;
VectorTyp = ^VectorStruc;
procedure CreateVector(var Vec: VectorTyp; Length: word; Value: float);
{ Generates a vector of length Length and sets all elements to Value }
procedure DestroyVector(var Vec: VectorTyp);
{ release memory occupied by vector }
procedure SetVectorElement(var Vec: VectorTyp; n: word; c: float);
function GetVectorElement(const Vec: VectorTyp; n: word): float;
implementation
var ch: char;
function WriteErrorMessage(Text: string): char;
begin
Write(Text);
Read(WriteErrorMessage);
VectorError := True; // toggle the error marker
end;
procedure CreateVector(var Vec: VectorTyp; Length: word; Value: float);
var
i: word;
begin
try
GetMem(Vec, Length * SizeOf(float) + SizeOf(word) + 6);
except
ch := WriteErrorMessage(' Not enough memory to create vector');
exit;
end;
Vec^.Length := Length;
for i := 1 to Length do
Vec^.Data[i] := Value;
end;
procedure DestroyVector(var Vec: VectorTyp);
var
x: word;
begin
x := Vec^.Length * SizeOf(float) + SizeOf(word) + 6;
FreeMem(Vec, x);
end;
function VectorLength(const Vec: VectorTyp): word;
begin
VectorLength := Vec^.Length;
end;
function GetVectorElement(const Vec: VectorTyp; n: word): float;
var
s1, s2: string;
begin
if (n <= VectorLength(Vec)) then
GetVectorElement := Vec^.Data[n]
else
begin
Str(n: 4, s1);
Str(VectorLength(Vec): 4, s2);
ch := WriteErrorMessage(' Attempt to read non-existent vector element No ' +
s1 + ' of ' + s2);
end;
end;
procedure SetVectorElement(var Vec: VectorTyp; n: word; C: float);
begin
if (n <= VectorLength(Vec)) then
Vec^.Data[n] := C
else
ch := WriteErrorMessage(' Attempt to write to non-existent vector element');
end;
end.
As long as your data fit on the stack, i.e., are smaller than 64 kB, the task is relatively simple. The only thing I don't know is where the 6 bit of extra size go, they are required, however.
I'm using PASCAL for a course i'm doing and i'm having trouble with an assignment, in my program i'm using 2 arrays that uses a variable from a user's input but when i go to run the program it comes up with, Error: Can't evaluate constant expression. The code for the array is:
Var
x : integer;
s : array[1..x] of real;
n : array[1..x] of string[30];
Here x is the user's input, is there a way for an array to go from 1 to x?
If x is a variable, that won't work indeed. The range of a so called static array must be a constant expression, i.e. it must be known at compile time.
So what you want won't work, as is.
In FreePascal, you can use dynamic arrays, though. Their lengths can be set and changed at runtime.
var
x: Integer;
s: array of Real;
n: array of string[30]; // why not just string?
and later:
x := someUserInput(); // pseudo code!
SetLength(s, x);
SetLength(n, x);
You should be aware of the fact that dynamic arrays are 0-based, so your indexes run from 0 up to x - 1. But for the limits of the array, you should rather use Low() and High() instead:
for q := Low(s) to High(s) do
// access s[q];
(Low() and High() are not the topic, but just know they can also be used for static arrays, and that they return the actual array bounds -- I always use High and Low for this)
Here is not so simple as using managed types like dynamic arrays suggested by #RudyVelthuis but more funny solution providing some comprehension
about how it works internally :)
program dynarr;
{$mode objfpc}{$H+}
type
TArrayReal = array[1..High(Integer)] of Real;
TArrayString30 = array[1..High(Integer)] of string[30];
PArrayReal = ^TArrayReal;
PArrayString30 = ^TArrayString30;
var
i: Integer;
x: Integer;
s: PArrayReal;
n: PArrayString30;
begin
Write('Count: '); Readln(x);
// Allocate memory for the actual count of the elements
s := GetMem(SizeOf(Real) * x);
n := GetMem(SizeOf(string[30]) * x);
try
for i := 1 to x do
begin
Write('Row ', i:3, ': '); Readln(s^[i], n^[i]);
end;
Writeln('Your input was:');
for i := 1 to x do
Writeln('Row ', i:3, ': ', s^[i]:10:3, n^[i]: 20);
finally
// Do not forget to release allocated memory
FreeMem(s);
FreeMem(n);
end;
end.
I have to code a program in pascal that, given the three coefficients of a polynomial(ax²+bx+c), outputs its roots.
Here's what I have right now:
program poly;
type
polynomial = record
a, b, c : real;
end;
procedure readPolynomial (var p : polynomial);
begin
writeln ('Input 1st coefficient: ');
readln (p.a);
writeln ('Input 2nd coefficient: ');
readln (p.b);
writeln ('Input 3rd coefficient: ');
readln (p.c);
end;
function square (x : real) : real;
begin
square := x * x;
end;
procedure roots (p : polynomial; var rP, rN : real);
begin
rP := (-p.b + (sqrt((square(p.b)) - (4 * p.a * p.c)))) / (2 * p.a);
rN := (-p.b - (sqrt((square(p.b)) - (4 * p.a * p.c)))) / (2 * p.a);
writeln('The roots are: ', rP:0:3, ' y ' ,rN:0:3);
end;
var
myPolynomial : polynomial;
r1, r2 : real;
begin
writeln ('Enter the coefficients: ');
readPolynomial (myPolynomial);
roots (myPolynomial, r1, r2);
end.
It works fine for real roots but I don't know how to make it work with complex numbers.
I am assuming your coefficients are real numbers (they user can't enter complex numbers as coefficients). That would add a whole new level of complexity (no pun intended) to the problem.
You need to check the discriminant ((square(p.b)) - (4 * p.a * p.c)) to see if it's less than 0. Currently, your code just does, sqrt((square(p.b)) - (4 * p.a * p.c)) but you aren't checking if you are taking the square root of a negative number (which you can't do using the Pascal sqrt library function).
If the discriminant is negative, then you have a complex root and you can separate the real and imaginary parts as you wish in your program. It's basic quadratic formula.
For example:
procedure roots (p : polynomial; var rP, rN : real);
var disc: real;
begin
disc := square(p.b) - 4*p.a*p.c;
if disc >= 0 then begin
rP := (-p.b + sqrt(disc)) / (2 * p.a);
rN := (-p.b - sqrt(disc)) / (2 * p.a);
writeln('The roots are: ', rP:0:3, ' y ' ,rN:0:3);
end
else begin
// Roots are:
// -p.b/(2*p.a) + (sqrt(-disc)/(2*p.a))i
// -p.b/(2*p.a) - (sqrt(-disc)/(2*p.a))i
end
end;
Here you use the fact that sqrt(x) if x is negative would be, (sqrt(-x))i where i is sqrt(-1). Note that you could also split out the disc = 0 case to avoid repeating a double root.
Since your roots function prints out the results and your main program doesn't use the returned arguments rN and rP, it's not clear to me if you need to pass back the roots at all. But if want to pass the roots back as arguments (the way you have your function currently designed), I'll leave that as an exercise. You just have to decide on a representation for complex roots. One way is to use the Complex number type for the results (if your compiler library supports them), and when the results are real, the imaginary parts will just be zero. Alternatively, if you need to create your own, just make a type which is a record consisting of a real and imaginary part.
type complex = record
re: real;
im: real;
end;
My program should inverse a string (ex. for Hello world returns dlrow olleH) and it works only for strings smaller than 20 characters. For 20 or more i get "Error 202 Stack overflow". Thank you :)
Program Inv;
var S, A: String;
n: integer;
Function I(X: String; z: integer):String;
begin
if z=1 then I:=X[z] else
I:=X[z]+I(X, z-1);
end;
begin
write ('Enter your text: ');
readln (S);
n:=length(S);
A:=I(S, n);
writeln (A);
readln;
end.
Unless you are required to show a recursive solution, you're usually better to sticking with iteration(a). Recursion uses an often-limited resource (the stack) to weave its magic and is often the cause of crashes when you exceed that limit.
Iterative solutions tend to be far less restrictive, such as the code below:
program PaxCode;
Function reverse(inp_str: string) : string;
var out_str : string = '';
var idx : integer = 1;
begin
while (idx <= length(inp_str)) do
begin
out_str := inp_str[idx] + out_str;
idx := idx + 1
end;
reverse := out_str
end;
var test_str: string = 'My hovercraft is full of eels and they will not let me drive it';
begin
writeln(test_str);
writeln(reverse(test_str))
end.
As you can see, the output is correct, and not limited to twenty (or twenty-nine) characters:
My hovercraft is full of eels and they will not let me drive it
ti evird em tel ton lliw yeht dna slee fo lluf si tfarcrevoh yM
(a) The best areas for recursion are those where each level removes a sizable proportion of the solution space. For example, binary searches remove fully 50% of the remaining solution space on every level so you could search through a structure holding four billion entries with just thirty-two levels, since 232 is a touch above 4.2 billion.
Something like reversing a 400-character string will take, ..., let me think, oh yes, 400 levels. That won't necessarily end well :-)
Let's say we have to create a calculator, and the first function it has is Fatorial.
We can write it as a recursive function or use a loop to get the result.
We all know that recursion is more slow because of it's exponential nature.
But how to prove it by code and not by counting lines?
I have tried to calculate the amount of milliseconds spent, but with my i7 it is always zero between the initial time and when the code stops.
How can I measure the difference of speed of code between loop and recursive method?
type
TJanela = class(TForm)
Instrucao: TLabel;
Entrada: TEdit;
Botao: TButton;
procedure Calcular(Sender: TObject);
end;
var
Janela: TJanela;
Val, Fat, Start, TimeRecursive, TimeLoop: Int64;
function FR(N: Int64): Int64; // Fatorial Recursivo
function FL(N: Int64): Int64; // Fatorial em Loop
implementation
{$R *.dfm}
procedure TJanela.Calcular(Sender: TObject);
begin
Val := StrToInt(Entrada.Text);
Start := StrToInt(FormatDateTime('nnsszzz',Now));
Fat := FR(Valor);
TimeRecursive := StrToInt(FormatDateTime('nnsszzz',Now)) - Start;
Start := StrToInt(FormatDateTime('nnsszzz',Now));
Fat := FL(Valor);
TimeLoop := StrToInt(FormatDateTime('nnsszzz',Now)) - Start;
if Val > 25 then
ShowMessage('Delphi can't calculate above [ 25! ]')
else
ShowMessage(' [ ' +
IntToStr(Val) + '! ] is equal to [ ' +
FormatFloat('###,###,###,###,###,###',Fat) + ' ]'#13#13+
'Recursive: [ ' + IntToStr(TimeRecursive) + ' ] ms;'#13+
'Loop: [ ' + IntToStr(TimeLoop) + ' ] ms;');
end;
function FR(N: Int64): Int64;
begin
if N <= 1 then
Result := 1
else
Result := N * FR(N - 1);
end;
function FL(N: Int64): Int64;
var
I: Integer;
begin
for I := 2 to N - 1 do
N := N * I;
if N = 0 then
Result := 1
else
Result := N;
end;
Now that David came with the answer, I asked a question on Mathematics so they can help me to come out with two equations to determine the proximate time a given factorial will spend on the computer in both methods.
You are using quite a low resolution timer and a single evaluation of the factorial function is too fast to even register.
You could use a higher resolution timer, but by far the easiest approach is to time something that takes longer. Instead of timing a single call to factorial, time a thousand, or a million.
If you are actually interested in implementing a fast factorial function, for integer inputs, then you should use a lookup table.
For what it is worth, I think that TStopWatch in the Diagnostics unit is more convenient for timing than the date/time functions.
Use a profiler. Recent versions of Delphi include limited functionality versions of AQTime, but a search for profiler Delphi here turns up Profiler and Memory Analysis Tools for Delphi here at StackOverflow.
Profilers allow you to evaluate your code in several different ways, including the precise amount of time spent executing various parts of it. You can use the results to determine which takes more (or less) time.
if its just for testing, could you put a TimeGetTime() instead of GetTime() before the loop and one after. then just save the value in a list box to see how long it takes.
if that is too slow try QueryPerformanceCounter/QueryPerformanceFrequency