Fehler: in 000nav.txt ist nicht "jmbruch.php" aufgeführt!
{ "Extended integer" werden mit extended simuliert.
extended hat 18-19 signifikante Stellen, d.h. man kann damit
Integer darstellen, die 18-19 Dezimalstellen haben.
Gespeichert werden diese Integer als extended.
Int64 wären aucg möglich ... Nur dort entstehen Überlauffehler, die werden
hier abgefangen mit "zugross". Dann wird die Zahl "unde" (Magic).
Die Grundoperationen mit e(xttended) gekennzeichnet sind dann:
Adde a+b //Muss nicht extra programmiert werden, bis auf unde(fined)
Sube a-b
Multe a*b
Dive(a,b) a div b //Funktionen implementiert
Mode(a,b) a mod b
ggTe(a,b) ggT(a,b)
hoche(a,b) a^b
}
unit jmbruch;
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls, WinSpool, ComCtrls;
const maxNennerMalZaehler = 1E12; //z.B. Nenner/Zähler 123456/765432 //geändert Februar 2003 vorher 1E14
eps_fuerBruch = 1E-15;
g_eps =1E-12; //von jmMath?????????????
zugross = 1.0*high(Int64) + 0.5;
undefined_e = 8642E97531; //undefined_extended = magic
var nPZe: integer; //nPZe: "n=Anzahl für PZe"
PZe: array of Integer; //PZe: "Primzahl extended"
//Betrifft extended als Integer
function alsIntegergleich(const a,b: extended): boolean;
function adde(const a,b: extended): extended;
function sube(const a,b: extended): extended;
function multe(const a,b: extended): extended;
function dive(const a,b: extended): extended; //<> a/b
function mode(const a,b: extended): extended;
function odd(const a:extended): boolean;
function ggTInt(const a,b: integer): integer; //siehe pyth Zahlentripel
function ggTe(const a,b: extended): extended;
procedure kuerzee(var a,b:Extended);
function hoche(const m,e: extended): extended;
//Allgemeine Hilfsfunktionen
function IsInteger(const x: extended; eps_Genauigkeit: extended): boolean;
//z.B. x=2,000..0001 x=1,999..9
function RealIsIntegerToStr(x:extended): string;
//Primzahlen
//lokal function PrZe(const n:Integer): integer; // die n. Primzahl, gezählt ab 0
function Primzahlausgabe(const n:extended): integer; // die n. Primzahl, gezählt ab 1
function kleinsterPrimfaktor(const x: extended): extended; //2, 3 ... oder x
function groessterPrimfaktor(const x: extended): extended;
function PFZ(x0: extended): string; // Teste mit 304 250 263 527 211
//Ausgabe als Bruch
function ErmittleBruche(const q:extended;var a,b:extended; eps_Genauigkeit:Extended):boolean;
//Die Hauptpozedur
function ReellZuBruch_(const q:extended;const alsGemZahl:boolean):string; //stets Ergebnis
function ReellZuBruch(const q:extended):string; //stets Ergebnis, unechterBruch oder float
function ReellZuGemZahl(const q:extended):string; //Stets Ergebnis: Gem Zahl oder float
function GleichBruchfallsBruchsonstleer(r: extended): string;
function GleichBruchoderWurzelsonstleer(r: extended): string;
//Ausgabe als Wurzel oder Vielfaches von Pi
function AlsWurzeloderPi(x0:extended; wur:string):string; //evtl. ''
function AlsVielfachesVonPioderleer(x:extended):string;
//es wird versucht x=a/b*wur(c)
//-> x^2=z/n Nenner klein genug, dann x=1/n*wur(z*n)
function AlsBruchoderWurzel(r: extended): string; //nie ''
function AlsBruchoderWurzelmitNaeherung(r: extended): string;
implementation
uses unitrechne, jmabbrechen, jmhilf;
function IsInteger(const x: extended; eps_Genauigkeit: extended): boolean;
begin
result := frac(abs(x) + eps_Genauigkeit) < eps_Genauigkeit * 2;
end;
function alsIntegergleich(const a,b: extended): boolean;
begin
result := (abs(a - b) < 0.5) //Es handelt sich um ganze Zahlen
end;
function adde(const a,b: extended): extended;
begin
if (a = undefined_e) or (b = undefined_e) then result := undefined_e
else result := a + b;
if abs(result) > zugross then result := undefined_e;
end;
function sube(const a,b: extended): extended;
begin
if (a = undefined_e) or (b = undefined_e) then
result := undefined_e else result := a - b;
if abs(result) > zugross then result := undefined_e;
end;
function multe(const a,b: extended): extended;
begin
if (a = undefined_e) or (b = undefined_e)
then result := undefined_e else result := a * b;
if abs(result) > zugross then result := undefined_e;
end;
function dive(const a,b: extended): extended;
begin
if (a = undefined_e) or (b = undefined_e) or (b = 0)
then result := undefined_e else result := int(a/b);
end;
function mode(const a,b: extended): extended;
begin
if (a = undefined_e) or (b = undefined_e) or (b = 0)
then result := undefined_e else
result := a - b*dive(a,b);
end;
function odd(const a:extended): boolean;
begin
result := alsIntegergleich(mode(a,2),1);
end;
function ggTInt(const a,b: integer): integer;
begin
if b = 0 then result:=a else result:=abs(ggTInt(b,a mod b));
end;
function ggTe(const a,b: extended): extended;
begin
if (a = undefined_e) or (b = undefined_e) then result := undefined_e else
if b = 0 then result:=a else result:=abs(ggTe(b,mode(a,b)));
end;
function hoche(const m,e: extended): extended;
begin
if abs(m) > zugross then result := undefined_e else Begin
if e = 0 then result := 1 else
if odd(e) then result := m*hoche(m,e-1) //da m^e=m*m(e-1)
else result := hoche(m*m,dive(e,2)) //da m^e=(m*m)(e/2)
End;
if abs(result) > zugross then result := undefined_e;
end;
procedure suchenaechstePrimzahl;
var groesstePZ: integer;
function hatKeineTeiler:boolean; //Versuch, ob groesstePrimzahl wirklich PZ ist, d.h.
//nicht durch bisherige PZ geteilt werden kann
//Prüfung:primzahl[j] Teiler von GroesstePrimzahl? bis
// primzahl[j] > Wurzel(groesstePrimzahl) nil then Begin
abbrechen.labbrechen.Caption := IntToStr(nPZe);
application.ProcessMessages;
if abbrechen.stop then exit;
End else Begin
abbrechen := TFormabbrechen.create(nil);
FRechne.Enabled := false;
abbrechen.Caption := 'Primzahlahlen werden berechnet';
abbrechen.show;
End;
groesstePZ:=PZe[nPZe]; //Größte bisher gefundene PZ
repeat
inc(groesstePZ,2); //Eine noch groesserPZ wird gesucht, evl. PZ-Zwilling
until hatkeineTeiler;
inc(nPZe); //Jetzt gibt's eine PZ mehr
if length(PZe) <= nPZe + 1 then setlength(PZe,nPZe + 500);
PZe[nPZe] := groesstePZ; //Neue größte PZ
end;
procedure garantierePZe(const i: integer);
begin
while nPZe < i do Begin
if abbrechen <> nil then if abbrechen.stop then exit;
suchenaechstePrimzahl;
End;
end;
function PrZe(const n:Integer): integer; // die n. Primzahl, gezählt ab 0
begin
garantierePZe(n);
if abbrechen <> nil then if abbrechen.stop then Begin
result := 0;
exit;
End;
//Bei Abbruch n < nPrZe
if n <= nPZe then result := PZe[n] else result := 0;
end;
function Primzahlausgabe(const n:extended): integer; // die n. Primzahl, gezählt ab 1
begin
if (n < 1) or (n > high(integer)) then
result := 0 else result := PrZe(round(n)-1);
if abbrechen <> nil then Begin
if abbrechen.stop then result := 0;
abbrechen.free; //Jetzt auf jeden Fall
abbrechen := nil;
FRechne.Enabled := true;
frechne.Show;
End;
end;
function RealIsIntegerToStr(x:extended):string;
begin
result:=trim(floatToStrf(x,ffGeneral,4,18));
if pos('E',result) > 0 then result := floattostr(x);
end;
function kleinsterPrimfaktor(const x: extended): extended;
var i:integer;
begin
for i := 0 to round(sqrt(x)) do Begin
if alsIntegergleich(mode(x,PrZe(i)),0) then BEgin
result := PrZe(i);
exit;
ENd;
End;
result := x; //x ist Primzahl
if abbrechen <> nil then Begin
abbrechen.free;
abbrechen := nil;
FRechne.Enabled := true;
frechne.Show;
End;
end;
function groessterPrimfaktor(const x: extended): extended;
var i:integer;
begin
i := 0;
while PrZe(i)*PrZe(i) < x do inc(i);
while i >= 0 do Begin
if alsIntegergleich(mode(x,PZe[i]),0) then BEgin
result := PrZe(i);
exit;
ENd;
dec(i);
End;
result := x; //x ist Primzahl
if abbrechen <> nil then Begin
abbrechen.free;
abbrechen := nil;
FRechne.Enabled := true;
frechne.Show;
End;
end;
procedure rundeWennInteger(var x: Extended);
begin if isInteger(x, g_eps) then Begin
if x >= 0 then x := int(x + 0.5) else
x := -int(abs(x) + 0.5);
End;
end;
function PFZ(x0: extended): string; // Teste mit 304 250 263 527 211
var x,faktor: extended;
begin
x := x0;
RundeWennInteger(x); //sonst bei Fibonacci 144=..*3*1
result := '';
if abs(x) <= 1 then exit;
if abs(x) > 1E19 then Begin //geprüft mit 10^19+1=100...001
showmessage('Durch Rundungsfehler der Fließkommazahl ist PFZ möglicherweise nicht korrekt!');
result := '?';
End;
if x < 0 then result := '-' else result := ' ';
x := abs(x);
repeat
faktor := kleinsterPrimfaktor(x);
x := x/faktor;
if length(result) > 1 then result := result + '*';
result := result + FloatToStr(faktor);
until x <= 1.5;
Try
result := trim(result);
if alsIntegergleich(abs(x0),faktor) then result := result + '(PZ)'
except result := '' End;
end;
PROCEDURE kuerzee(var a,b:Extended);
var t:Extended;
begin
t := ggte(a,b);
a := dive(a,t);
b := dive(b,t)
end;
function ErmittleBruche(const q:extended; var a,b:extended; eps_Genauigkeit:Extended):boolean;
//=true, falls erfolgreich
const MaxIteration=50;
var q0,Qabs,GanzZahligerAnteilVonQ,NachkommaVonQ,am,amm,bmm,bm:extended;
{am=a index -1 amm index -2}
zaehl:integer;
begin //Methode: Kettenbruchentwicklung
result := false;
qabs := abs(q); //Es wird mit positiven Werten gerechnet
q0 := qabs;
a := 1;
b := 0;
am := 0; //altes a
bm := 1; //altes b
zaehl := 0;
try //damit nach exit Finally ausgeführt wird
repeat
inc(zaehl);
if zaehl>MaxIteration then exit;
GanzZahligerAnteilVonQ:=int(q0+eps_Genauigkeit); //wg. Rundungsfeler muss z.B. 4.99.. zu 5.00.. werden
NachkommaVonQ:=q0-GanzZahligerAnteilVonQ; //=fraq(qabs)
amm := am; //uraltes a
bmm := bm; //uraltes b
am := a; //altes a
bm := b; //altes a
try // möglich overflow (kommt nur vor, falls eps_Gen. zu klein)
a := adde(GanzZahligerAnteilVonQ*am,amm); //Anfang: ak=GanzZahligerAnteilVonQ
b := adde(GanzZahligerAnteilVonQ*bm,bmm); // bk=1
kuerzee(a,b);
if NachkommaVonq < eps_Genauigkeit then exit;//endlicher Kettenbruch siehe finally
q0 := 1/NachkommaVonq; //Jetzt ja NachkommaVonq>=eps_Genauigkeit
Except exit End;
until abs(qabs - a/b)=eps_Genauigkeit then result:=false else result := true;
except result := false End;
if q<0 then a:=-a;
End;
end;
function reellZuBruchefallsmoeglichsonstleer(const q: extended;
gemischteZahl: boolean; eps: extended): string;
//liefert ganze Zahl oder Bruch oder -falls nicht möglich- leeren String
const Hochkomma = #39;
var a,b: extended;
begin
try
if ErmittleBruche(q,a,b,eps) then Begin
if abs(a*b) > maxNennerMalZaehler then BEgin
result := '';
exit;
End;
if abs(b-1) < eps then Begin
result := IntToStr(round(a));
exit;
End;
if gemischteZahl and (abs(q) > 1) then Begin
if q < 0 then result := '-' else result := '';
result := result + intToStr(round(dive(abs(a),b))) + Hochkomma
+ intToStr(round(mode(abs(a),b))) + '/' + IntToStr(round(b));
End else result := IntToStr(round(a)) + '/' + IntToStr(round(b));;
End else result := '';
{Teste mit +/- ... 1/2+1/7, 999.9999999, Pi, 15, 13579/246810}
except result := '' End;
end;
function ReellZuBruch_(const q:extended;const alsGemZahl:boolean):string;
//liefert ganze Zahl oder Bruch oder -falls nicht möglich- floatToStr
begin
result := reellZuBruchefallsmoeglichsonstleer(q,alsGemZahl,eps_fuerBruch);
if result = '' then result := FloatToStrF(q,ffGeneral,18,10);
end;
function ReellZuBruch(const q:extended):string; //stets Ergebnis, unechterBruch oder float
begin result:=ReellZuBruch_(q,false) end;
function ReellZuGemZahl(const q:extended):string; //stets Ergebnis, Gem Zahl oder oder float
begin result:=ReellZuBruch_(q,true) end;
function GleichBruchfallsBruchsonstleer(r: extended): string;
var s: string;
begin
s := ReellZuBruch(r);
if pos('/', s) > 0 then result := '=' + s else result := '';
end;
//------------------- Wurzel -------------------------
function AlsVielfachesVonPioderleer(x:extended):string;
var z,n:extended;
begin
result:=''; //Misserfolg
if x > 1E9 then exit;
try
if ErmittleBruche(x/Pi,z,n,1E-15) then Begin
if abs(n)<1000000 then BEgin
if n=1 then BEgin
if z = 1 then result := 'Pi' else
if z = -1 then result := '-Pi' else
result:=RealIsIntegerToStr(z)+'*Pi'
End else
result:=RealIsIntegerToStr(z)+'/'+RealIsIntegerToStr(n)+'*Pi'
ENd;
End;
except End;
end;
function teilweiseRadiziert(n: extended): string;
var NrPZ: Integer;
z,qu: extended;
begin
NrPZ := 0;
z := 1;
repeat
qu:=PrZe(NrPz)*PrZe(NrPz);
while IsInteger(n/qu,1E-15) do Begin
z:=z*PrZe(NrPz);
n:=n/qu;
End;
inc(NrPz);
until (NrPz>1000) or (qu>n);
if z=1 then result := 'sqrt('+floatToStr(n)+')' else
result := FloatToStr(z)+'*sqrt('+floatToStr(n)+')';
end;
function letzterVersuchoderleer(x: extended): string;
//x= (a+wur(b)/c //a,c ganz, b>0 rational => b = (c*x-a)^2
var z,n: extended;
a,c,sgn: integer;
nenner,
sqrt_z_mal_n: string;
begin
result := '';
for c := 1 to 10 do for a := -10 to 10 do if c <> 0 then
//z/n = (cx-a)^2 => cx - a = +- sqrt(z*n)/n => x = (a*n +- sqrt(z*n))/(c*n)
if ErmittleBruche(sqr(c*x-a),z,n,1E-12) then
if abs(z*n) < 1000 then Begin
if abs(x*c*n - a*n - sqrt(z*n)) < abs(x*c*n - a*n + sqrt(z*n))
then sgn := +1 else sgn := -1;
if abs(x*c*n - a*n - sgn*sqrt(z*n)) > 1E-12 then exit;
if alsIntegergleich(c*n,1) then nenner:='' else nenner := '/'+floatToStr(c*n);
if sgn = 1 then result := '+' else result := '-';
//result := '(' + floatToStr(a*n) + result + 'sqrt(' +floatToStr(z*n) +'))' + nenner;
sqrt_z_mal_n := teilweiseRadiziert(z*n);
result := '(' + floatToStr(a*n) + result + sqrt_z_mal_n +')' + nenner;
exit;
End;
end;
function AlsWurzeloderPi(x0:extended; wur:string):string; //evtl. ''
//es wird versucht x=a/b*wur(c)
//-> x^2=z/n Nenner klein genug, dann x=1/n*wur(z*n)
var c,xq,z,n,qu:extended;
NrPZ:integer;
function mitWurzel(x,z,n,c:extended):string;
var wu:string;
begin
kuerzee(z,n);
if abs(c-1)<1E-15 then wu:='' else wu:='*'+wur+'('+RealIsIntegerToStr(c)+')';
if n=1 then Begin
if z=1 then result:=copyab(wu,2) else result:=RealIsIntegerToStr(z)+wu
End else result:=RealIsIntegerToStr(z)+'/'+
RealIsIntegerToStr(n)+wu;
if x<0 then result:='-'+result;
end;
begin
result:='';
try
xq:=x0*x0;
except result := ''; exit End;
try
if ErmittleBruche(xq,z,n,1E-15) then if abs(n)<1000000000 then Begin
if abs(z) < g_eps then Begin
result := '0'; //sonst lautet Primfaktorenzerlegung 0*2*2*2....
exit;
End;
//x^2=z/n => x=1/n*wur(z*n);
//z.B. 123/124*wur(2/19) hoch 2= 15 129*146 072
c:=z*n; //x=1/n*wur(c)
//Teilweise radizieren!
z:=1;
if c>1000000 then exit;
NrPZ:=0;
repeat
qu:=PrZe(NrPz)*PrZe(NrPz);
while IsInteger(c/qu,1E-15) do Begin
z:=z*PrZe(NrPz);
c:=c/qu;
End;
inc(NrPz);
until (NrPz>1000) or (qu>c);
result:=mitWurzel(x0,z,n,c);
End
finally
if result = '' then result := AlsVielfachesVonPioderleer(x0);
if result = '' then result := letzterVersuchoderleer(x0);
if abbrechen <> nil then BEgin
abbrechen.free;
abbrechen := nil;
FRechne.Enabled := true;
frechne.Show;
End;
ENd;
end;
function AlsBruchoderWurzel(r: extended): string;
begin
try
if isinteger(r,g_eps) then Begin
result := formatfloat('0',r);
exit;
End;
result := reellZuBruchefallsmoeglichsonstleer(r,true,eps_fuerBruch);
if pos('/', result) > 0 then exit;
if result = '' then result := AlsWurzeloderPi(r,'sqrt');
except result := entferneSpacesNachMinus(formatfloat('0.
#',r)) End;
if result ='' then result := FloatToStrF(r,ffGeneral,12,10) else
result := result + '=' + FloatToStrF(r,ffGeneral,12,10);
end;
function GleichBruchoderWurzelsonstleer(r: extended): string;
var s: string;
begin
s := AlsWurzeloderPi(r,'sqrt');
if (pos('/', s) > 0) or (pos('sqrt',s) > 0) then result := '=' + s else result := ''
end;
function AlsBruchoderWurzelmitNaeherung(r: extended): string;
begin
result := AlsBruchoderWurzel(r);
if pos(decimalseparator,result) = 0 then
if not isInteger(r,eps_fuerBruch) then result := result + ' = ' + ssd_(r,3);
end;
begin //initialisierung für Primzahlen
setlength(PZe,2);
PZe[0] := 2;
PZe[1] := 3;
nPze := 1; //Zählung ab 0
end.