Der Algorithmus ist ganz einfach. Er werde an einem Beispiel
erläutert.
Die Umwandlung ins 3-System oder ins System mit der Basis B
erfolgt analog. Im 3-Sytem ist a mod 3 eine Ziffer aus
{0;1;2} im B-System ist a mod B eine Ziffer aus {0;1; ... ;
B-1}.
Dabei handelt es sich um die Zahl 998 im Dezimalsystem und ihre Ziffern a9,a8, .... a0 im Dualsystem.
function DezInBinVorkomma(n: integer):string; begin result:=''; repeat if n mod 2 =0 then result:='0'+result else result:='1'+result; n:=n div 2; until n=0; end;(Im Programm ist noch die Vorgabe, dass n in einem String gegeben ist).
Dabei handelt es sich um die Zahl 0,82 im Dezimalsystem und ihre Ziffern a0,a1,a2,... im Dualsystem.
n, der Reihe nach mit 2 multipliziert, ergibt als Vorkommastelle zuerst a0, dann a1, ...
Im Beispiel ist 0,82(10) =0.11010001111010111000... (2), denn 0,82·2 = 1,64 => 1. Dualziffer nach dem Punkt ist 1 - 0,64·2 = 1,28 ==> 2. Dualziffer nach dem Punkt ist 1 - 0,28·2 = 0,56 ==> 3. Dualziffer nach dem Punkt ist 0 - 0,56·2 = 1,12 ==> 4. Dualziffer nach dem Punkt ist 1 - ...
Somit erhält man durch folgende Prozedur die Dualdarstellung:
function DezInBinnachkomma(r: real):string; var n: integer; begin result := '0.'; n := 0; repeat inc(n); r := 2*r; if r >= 1 then Begin result:=result + '1'; r:= r - 1; End else result := result + '0'; until (r = 0) or (n > 64); end;November 2002: Philipps Verbesserungsvorschlag:
function DezInBinnachkomma(r: real):string; begin result := '0.'; repeat r := 2*r; if r >= 1 then Begin result := result + '1'; r := r-1; End else result:= result + '0'; until r < 1E-20; end;Zwei Vorteile: 1. Zählvariable n entfällt.
0,1 10) = 0.0001100110011001100110011...2) Im Computer nur ... 0,9 10 = 0.1110011001100110011001100...2 ... endlich ... 0,1+0,9 = 0,1111111111111111111111111...(2) ... viele Stellend.h. ein Programmierer, der in einer Schleife mit Anfangswert 0 und der Schrittweite 0,1 abfragt, wann 1 erreicht ist, erleidet damit Schiffbruch! Statt 1 wird möglicherweise nur 0,111..12=0,999...9(10) erreicht!
Ich hatte ein Programm geschrieben (ca. 1979), das
die Daten unserer Abiturienten erfasst,
Belegüberprüfungen und Berechnungen durchführt
und zum Schluss das komplizierte Abiturzeugnis ausdruckt. Das
Programm funktionierte jahrelang einwandfrei. Doch
plötzlich erhielten Schüler ein "befriedigend", wo
eigentlich hätte "gut" stehen müssen.
Was war passiert? Ich hatte den Compilerschalter von Pascal auf
"doppelte Rechengenauigkeit" gestellt. Mehr nicht.
Die Auswirkung war vereinfacht folgende:
Beim Punkteschema entspricht 7, 8 und 9 Punkte "befriedigend",
10, 11 und 12 Punkte "gut".
Bei mehreren Noten wird der Mittelwert gebildet. Dabei wird ab
n=9,5 auf "gut" aufgerundet (Achtung: unstetige
Funktion!).
Beim Umstellen des Compilers war (vereinfacht ausgedrückt)
der Mittelwert nicht mehr n=9,5 sondern n=9,499999999999999999 und die Abfrage
...
if n < 9,5 then s := "befriedigend" else s := "gut"
...
führte nach der Umstellung des Compilerschalters zu dem
fatalen Ergebnis.
Literatur: Zu dieser Problematik ist folgender Aufsatz zu
empfehlen: "What every computer scientist should know about floating-point arithmetic". Siehe http://www.validlab.com |
procedure TForm1.Button1Click(Sender: TObject); var n,p,i: integer; s: string; begin n := strToInt(edit1.text); p := 128; s := ''; for i := 1 to 8 do Begin if n >= p then BEgin n := n - p; s := s + '1'; ENd else s := '0' + s; p := p div 2; ENd; showmessage(s); end;
Beispiel Vorkomma: n=101011(2)=1*1+1*2+0*4+1*8+0·16+1*32 = 43 (10) Beispiel Nachkomma: n=0,1001(2)=1*1/2+0*1/4+0*1/8+1·1/16 = 0,5625 (10)
Die Prozeduren sind elementar und wohl ohne große Erläuterung verständlich.
function BinInDezVorkomma(s:string; var r:extended):boolean; var k:integer; p:extended; begin trim(s); r:=0; p:=1; for k:=length(s) downto 1 do Begin if s[k]='1' then r:=r+p else if s[k]<$gt;'0' then BEgin //Binärzahl nur 1 und 0 erlaubt result:=false; exit; ENd; p:=p*2; End; result:=true; end; function BinInDezNachkomma(s:string; var r:extended):boolean; //true kein Fehler var k:integer; p:extended; begin trim(s); r:=0; p:=1/2; for k:=1 to length(s) do Begin if s[k]='1' then r:=r+p else if s[k]<>'0' then BEgin //Binärzahl nur 1 und 0 erlaubt result:=false; exit; ENd; p:=p/2; End; result:=true; end;Downloadseite
function copyab(const s:string; const i:integer):string; //Rest von s ab i. em Zeichen begin result:=copy(s,i,length(s)-i+1) end; function BinInDezVorkomma(s:string; var r:extended):boolean; var k:integer; p:extended; begin trim(s); r:=0; p:=1; for k:=length(s) downto 1 do Begin if s[k]='1' then r:=r+p else if s[k]<>'0' then BEgin result:=false; exit; ENd; p:=p*2; End; result:=true; end; function BinInDezNachkomma(s:string; var r:extended):boolean; //true kein Fehler var k:integer; p:extended; begin trim(s); r:=0; p:=1/2; for k:=1 to length(s) do Begin if s[k]='1' then r:=r+p else if s[k]<>'0' then BEgin result:=false; exit; ENd; p:=p/2; End; result:=true; end; function BinInDez(s:string):string; var n:integer; a,b:string; vork,nachk:extended; korrekt:boolean; begin n:=pos('.',s); if n=0 then n:=pos(',',s); if n=0 then Begin korrekt := BinInDezVorkomma(s,vork); if korrekt then result := floatToStr(vork) else result := 'Falsche Eingabe'; End else Begin a:=copy(s,1,n-1); b:=copyab(s,n+1); korrekt:=BinInDezVorkomma(a,vork) and BinInDezNachkomma(b,nachk); if korrekt then result:=floatToStr(vork+nachk) else result:=''; End; end; function DezInBinVorkomma(s:string):string; var n:integer; begin result:=''; try n:=StrToInt(s) Except result:=''; exit End; repeat if n mod 2 =0 then result:='0'+result else result:='1'+result; n:=n div 2; until n=0; end; function DezInBinnachkomma(s:string):string; var r:extended; n:integer; begin r:=StrToFloat('0'+Decimalseparator+s); result:=''; n:=0; repeat inc(n); r:=2*r; if r>=1 then Begin result:=result+'1'; r:=r-1; End else result:=result+'0'; until (r=0) or (n>64); end; function DezInBin(s:string):string; var n:integer; a,b:string; begin n:=pos('/',s); if n>0 then Begin //Bruch->Dezimalzahl a:=copy(s,1,n-1); b:=copyab(s,n+1); try s:=FloatToStr(strToFloat(a)/StrToFloat(b)); except result:='Falsche Eingabe' End; End; n:=pos('.',s); if n=0 then n:=pos(',',s); if n=0 then result:=DezInBinVorkomma(s) else Begin a:=copy(s,1,n-1); b:=copyab(s,n+1); result:=DezInBinVorkomma(a) +decimalseparator+DezInBinNachkomma(b); End; end; procedure TForm1.E_dezChange(Sender: TObject); begin if e_bin.focused then exit; try e_bin.text:=dezInBin(e_dez.text); except e_bin.text := 'Falsche Eingabe' End; end; procedure TForm1.E_binChange(Sender: TObject); begin if e_dez.focused then exit; try e_dez.text:=BinInDez(e_bin.text); except e_dez.Text := 'Falsche Eingabe' End end;In Simon Reinhards www.delphi-fundgrube.de ist folgende allgemeine Routine angegeben: (Nur noch im Archiv aufrufbar:Archiv)
type TNumbBase = 1..36; function NumbToStr(Numb: LongInt; Base: TNumbBase): String; const NumbDigits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; begin Result:=EmptyStr; while Numb > 0 do begin Result:=NumbDigits[(Numb mod Base)+1]+Result; Numb:=Numb div Base; end; if Result=EmptyStr then Result:='0'; end;