Assembler BCD-Binär

Liebe/-r Experte/-in,

Habe folgendes Problem!
Ich möchte sehr große dezimale Zahlen (>100 Ziffern) ins binäre Zahlensystem umwandeln. Bin mit der Umwandlung vertraut und programmiere in VB, jedoch ist die Umwandlung bei Zahlen mit >100000 Ziffern schon sehr Zeitintensiv.
Ein Versuch dieses Problem in Assembler zu lösen, scheitert zum Einem an meine Einsteigerkenntnisse und zum Anderen an ein Fehlen eines schnellen Algorithmen.
Die Frage nun lautet: Wie macht es Windows intern bzw. Ecxel (bietet in VBA Zahlen mit bis zu 28 Ziffern an)? Wie könnten ein effektives Programm in Assembler aussehen?

wofür/wie willst Du diese großen Zahlen verwenden?

wie Excel das macht verbirgt sich mir; aber mit 10 Mio. Stellen und mehr habe ich schon einiges gemacht;
die Hauptroutinen in C und die eigentlichen Hardcore-Rechenroutinen in Assembler;

und BCD würde ich nicht mehr nehmen sondern was eigenes:
z.B. ein Array mit 32-bit DWORDs;

Addition und Subtraktion sind trivial; Division und Multiplikation zweier solcher Zahlen mit sehr viel Aufwand verbunden, aber die Multiplikation mit einem Integer bzw. die Division durch einen Integer auch wieder trivial;

#define BLKS 1000000
#define BLK 1000000000

unsigned long ulA[BLKS];
unsigned long ulB[BLKS];
unsigned long ulC[BLKS];

for ( int n = 0; n = BLK )
ulVal -= BLK, ulBit = 1;
else
ulBit = 0;
ulC[n] = ulVal;
}

// so funktioniert die Ausgabe
int n = BLKS;
while ( ulC[–n] == 0 );
do
{
if ( n & 0x07 )
printf( „%08lu“, ulC[n] );
else
printf( „%08lu\n“, ulC[n] );
}
while ( --n >= 0 );

// willst Du tatsächlich 0en und 1en ausgeben, besteht zuerst der Aufwand, die Dezimalzahl in eine Binärzahl umzuwandeln …

Danke für deine schnelle Antwort.

Ich möchte verschiedene Potenzen zu verschiedenen Basen errechnen, brauche das Ergebnis allerdings nur in binärer Form (für spätere Weiterberechnung). Benötige dieses für ein persönliches Projekt.

Das BCD nicht mehr aktuell ist hatte ich schon in diversen Web-Seiten gelesen. Da meine Ergebnisse in dezimaler Textform vorliegen, war mein Gedanke, diese werden im RAM-Speicher als ASCII Zeichen (ein Byte pro Ziffer) abgelegt. Anschliessend werden sie mittels BCD/Binär-Umgewandung auf die richtige Binärzahl umgerechnet.

Meine Vorgehensweise zuerst in dezimalen Zahlen die Potenzen zu errechen, dieses Ergebnisse in Text-Dateien zu speichern und anschliessend diese in einen Binärcode umzuwanden war schneller als andere Methoden. Zudem kann ich die Berechnungen paralell durchführen (nächste Potenz berechnen - vorherige umwandeln). Eine Berechnung direkt mit Binärzahlen brachte zeitmäßig keine Vorteil, lag wahrscheinlich auch daran, das ich dieses in VB programmiert hatte.

Eine Berechnung nur in binären Zahlen wäre für meine Zwecke daher ausreichend und sinnvoll. zb. besser wäre das Ergebnis von 1101^11000000111001 (13^12345) zu speichern ohne den Umweg der Umwandlung.

Danke!
Andreas

Danke für deine schnelle Antwort.

Ich möchte verschiedene Potenzen zu verschiedenen Basen
errechnen, brauche das Ergebnis allerdings nur in binärer Form
(für spätere Weiterberechnung).

willst Du auch sowas 2^216091-1 berechnen?
(hier das Ergebnis: http://www.mathemainzel.info/files/nmbrs/_prime.html)

Das BCD nicht mehr aktuell ist hatte ich schon in diversen
Web-Seiten gelesen.

der Nachteil von BCD ist einfach, daß Du 1 Dezimalstelle pro Halbbyte „pfuscht“ und damit nur sehr unhandlich gerechnet werden kann, vor allem, wenn es um was größers geht;

Da meine Ergebnisse in dezimaler Textform
vorliegen, war mein Gedanke, diese werden im RAM-Speicher als
ASCII Zeichen (ein Byte pro Ziffer) abgelegt.

wie weit bist Du mit der internen Darstellung vertraut?

z.B. 1 Byte

speichert 256 mögliche Werte (8 Bits, 2^8 = 256)
vorzeichenbehaftet bedeutet dies -128 bis +127
vorzeichenlos bedeuted dies 0 bis 255

als BCD eben von 0 bis 99:

oberes Halbbyte: 0000 bis 1001
unteres Halbbyte: 0000 bis 1001
(beide Halbbytes jeweils von 0 bis 9)

oder Du machst es etwas geschickter und speicherst in einem Byte direkt Werte von 0 bis 99:
00000000 (0)
00000001 (1)

00010111 (45)

01011111 (95)
01100000 (96)
01100001 (97)
01100010 (98)
01100011 (99)

damit kannst Du so richtig rechnen;

faßt Du hingegen mehrere Bytes (2, 4 oder 8) zusammen,
dann kannst Du die Möglichkeiten von 32-bit od. 64-bit Architekturen ausnutzen;

zb. besser wäre das Ergebnis
von 1101^11000000111001 (13^12345) zu speichern ohne den Umweg
der Umwandlung.

es darf ruhig etwas Mathematik angewendet werden:

wegen 13^8 = 815730721
13^12345 = (13^8)^1543 * 13
daher am Rechenbeginn die Zahl mit 13 initialisieren
und anschließend 1543 mal mit 815730721 multiplizieren;

mit 32-bit DWORDs sieht das folgendermaßen aus:

[3] [2] [1] [0]
0 0 0 13 (nach der Initialisierung)
0 0 10 604499373 (nach der 1ten Multiplikation)

Grüße,
Walter

1 Like

Wiederum danke für die sehr schnelle Antwort.

willst Du auch sowas 2^216091-1 berechnen?
(hier das Ergebnis:
http://www.mathemainzel.info/files/nmbrs/_prime.html)

Die Darstellung von 2^n-1 in dualer schriebweise sind sehr trivial - lauter 1er (n-mal). Bei meinen Berechnungen ist die Basis und Exponent eine p-Zahl (zb. 5^12343 oder 13^12343).

Das BCD nicht mehr aktuell ist hatte ich schon in diversen
Web-Seiten gelesen.

der Nachteil von BCD ist einfach, daß Du 1 Dezimalstelle pro
Halbbyte „pfuscht“ und damit nur sehr unhandlich gerechnet
werden kann, vor allem, wenn es um was größers geht;

Da meine Ergebnisse in dezimaler Textform
vorliegen, war mein Gedanke, diese werden im RAM-Speicher als
ASCII Zeichen (ein Byte pro Ziffer) abgelegt.

wie weit bist Du mit der internen Darstellung vertraut?

z.B. 1 Byte

Die Darstellungen der Bit und Byte sind mir vertraut. Auch das BCD ein Halbbyte (Nibble) benutzt. Lese ich jedoch eine Zahl bzw. Ziffer ein so wird sie doch in ASCII-Code dargestellt - „3“ = 33H bzw 00110011B und bräuchte demnach für jede Ziffer ein Byte („3125“ = 4 Byte?). Oder unterliege ich da einen Fehler?

speichert 256 mögliche Werte (8 Bits, 2^8 = 256)
vorzeichenbehaftet bedeutet dies -128 bis +127
vorzeichenlos bedeuted dies 0 bis 255

als BCD eben von 0 bis 99:

oberes Halbbyte: 0000 bis 1001
unteres Halbbyte: 0000 bis 1001
(beide Halbbytes jeweils von 0 bis 9)

oder Du machst es etwas geschickter und speicherst in einem
Byte direkt Werte von 0 bis 99:
00000000 (0)
00000001 (1)

00010111 (45)

01011111 (95)
01100000 (96)
01100001 (97)
01100010 (98)
01100011 (99)

damit kannst Du so richtig rechnen;

faßt Du hingegen mehrere Bytes (2, 4 oder 8) zusammen,
dann kannst Du die Möglichkeiten von 32-bit od. 64-bit
Architekturen ausnutzen;

Wenn ich 8 Byte zusammenfasse wären das max. eine 19stellige Dezimalzahl. Kann diese auch mit der 64-Bit Architektur in Assembler-Code, ohne auf 32-Bit Befehlen zurückzugreifen, weiter gerechnet werden? Und wie sieht es mit den einzelnen Daten aus; müssten diese anders im Speicher abgelegt oder eingelesen werden?

zb. besser wäre das Ergebnis
von 1101^11000000111001 (13^12345) zu speichern ohne den Umweg
der Umwandlung.

es darf ruhig etwas Mathematik angewendet werden:

wegen 13^8 = 815730721
13^12345 = (13^8)^1543 * 13
daher am Rechenbeginn die Zahl mit 13 initialisieren
und anschließend 1543 mal mit 815730721 multiplizieren;

mit 32-bit DWORDs sieht das folgendermaßen aus:

[3] [2] [1] [0]
0 0 0 13 (nach der Initialisierung)
0 0 10 604499373 (nach der 1ten Multiplikation)

Mit der Mathematik habe ich weniger das Problem, nur mit der Umsetzung in der Sprache Assembler. Das VB Programm ist ähnlich aufgebaut.

Hier mal ein kleines VBScript-Programm, das Du in einen Texteditor (zb. Notepad) einfügen kannst (mit der Endung .vbs abspeichern). Irgendeine Dezimalzahl bei der Abfrage eingeben und Ergebnis erscheint prommt.

**const y=10,k=12 'y=Anzahl der Ziffern, k=12 Bit (2^12=4096) zusammen maximal (10E+11-1)*40960)",„Dec to Bin…“)) 'irgend eine Zahl
if n=emtpy then wscript.quit 'leer dann abbruch
if n0 sein
t=timer ’ Start der Zeitberechnung

n1=n ’ n sichern

’ Berechnung der benötigten Array´s

z=int(len(n)/y)
if z*yy then n1=left(n1,len(n1)-y)
next

’ Umwandlung von Dec in Bin

x=1: c=empty
do
w=0
for i=x to z
v(i)=v(i)+w*10^y
w=v(i)-int(v(i)/a)*a
v(i)=(v(i)-w)/a
next
c=d(w)&c
if v(x)=0 then x=x+1
loop until x>z

’ Führende Nullen entfernen, falls vorhanden

for i=1 to k-1
if cdbl(left(c,i))>0 then exit for
next
if i>1 then c=right(c,len©-i+1)

’ Ausgabe des Ergebnisses

t=timer-t
msgbox n & " =" & chr(10) & c,0,„Dec >> Bin… (in " & t & " sec.)“

wscript.quit**

Grüße
Andreas

Die Darstellung von 2^n-1 in dualer schriebweise sind sehr
trivial - lauter 1er (n-mal).

Stimmt; nur der Mensch ist Dezimalsystem-gepolt; die EDV tut sich da etwas leichter;

„Gib ma mal 11 Scheiben Käse“

1 Like

Die Darstellung von 2^n-1 in dualer schriebweise sind sehr
trivial - lauter 1er (n-mal).

Stimmt; nur der Mensch ist Dezimalsystem-gepolt; die EDV tut
sich da etwas leichter;

„Gib ma mal 11 Scheiben Käse“