| Die Homepage von Joachim Mohr | ||
|
|
Umwandlung einer Dezimalzahl in eine Binärzahl |
|
|
Downloadseite "Umwandlungg Dezimalzahl in Binärzahl" (dez_bin.exe) "Umwandlung Dezimalzahl in Hexadezimalzahl etc" (dez_in_b.exe) |
|
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}.
Beispiel: 998 = 1111100110 bedeutet: 998 im Zehnersystem = 1111100110 im Zweiersystem
10 2
9 8 7 6 5 4 3 2 1 0
denn: 998 = 1·2 + 1·2 + 1·2 + 1·2 + 1·2 + 0·2 + 0·2 + 1·2 + 1·2 + 0·2
9 8 2
Sei n=998(10)=a9a8a7a6a5a4a3a2a1a0(2) =a ·2 +a ·2 +...+a ·2 +a ·2+a
9 8 2 1 0
Dabei handelt es sich um die Zahl 998 im Dezimalsystem und ihre Ziffern a9,a8, .... a0 im Dualsystem.
Beachte: a0 ist 1, wenn die Zahl ungerade, sonst Null
und n dividiert durch 2=a9a8...a1 Rest a0.
In Pascal: n mod 2 = a0
n1=n div 2 =a9a8...a1 (Verschiebung um 1)
Jetzt wiederholt sich das ganze:
n1 mod 2 = a1
n2=n1 div 2 = a9a8 ...a2
....
Im Beispiel: 998(10) = 1111100110 (2), denn
998 div 2 = 499 Rest 0 letzte Dualziffer
499 div 2 = 249 Rest 1 vorletzte Dualziffer
249 div 2 = 124 Rest 1 ...
124 div 2 = 62 Rest 0
62 div 2 = 31 Rest 0
31 div 2 = 15 Rest 1
15 div 2 = 7 Rest 1 ...
7 div 2 = 3 Rest 1 dritte Dualzifer
3 div 2 = 1 Rest 1 zweite Dualziffer
1 div 2 = 0 Rest 1 erste Dualziffer
Somit erhält man durch folgende Prozedur die Dualdarstellung:
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).
-1 -2 -3
Sei n=0,82(10)=0,a1a2a3a4...(2)=a ·2 + a ·2 + a ·2 + ...
1 2 3
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.
2. Viel stichhaltiger: Bei der ersten Version wird r = 0 geprüft.
Sowas wird unter Informatikern bei r real wegen der Rundungsfehler als
Programmierfehler betrachtet.
Nebenbei bemerkt: Nur Brüche mit einer Zweierpotenz im Nenner sind
im Dualsystem endlich. Alle anderen unendlich z.B.
0,1 (10) = 0.0001100110011001100110011...(2) Im Computer nur ...
0,9 (10) = 0.1110011001100110011001100...(2) ... endlich ...
0,1+0,9 = 0,1111111111111111111111111...(2) ... viele Stellen
d.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..1
(2)=0,999...9(10) erreicht! Das Programm bleibt bei einer wichtigen
Anwendung "hängen". Schleifenende wird nicht ereicht: Programm
ist unbrauchbar! Kunde ist verärgert! Keine weiteren
Aufträge!
|
Literatur: Zu dieser Problematik ist folgender Aufsatz zu
empfehlen: "What every computer scientist should know about floating-point arithmetic". Siehe http://www.validlab.com |
|
Aufgabe 17.1: Das nebenstehende (fehlerhafte) Programm soll von der Dezimalzahl n, die in Edit1 steht, die zugehörige Dualzahl berechnen. a) Gib die Dualdarstellung der Zahl 206 an! b) Was berechnet das Pragramm stattdessen bei der Eingabe von n=206? c) Wie müsste man das Programm ändern, dass die Umwandlung bei Eingabe von n=206 richtig erfolgt? (wenig!) d) Was würdest Du bei diesem Programm noch beanstanden? |
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]<>'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 FAQ ist folgende allgemeine Routine angegeben:
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;
|
|
|