BCD-Format
-
Die double-to-string Umwandlung führe ich jetzt direkt in der Funktion aus.
struct bcd_number * string2bcd(double x){ struct bcd_number *b; int j,k; int deztren; const char *s; /* double in string umwandeln*/ sprintf(*s,"%f",x); /* Speicher reservieren */ b=malloc(sizeof(struct bcd_number)); b->laenge=0; b->nachkommastellen=0; b->vorzeichen=1; j=0; /* Negatives Vorzeichen detektieren */ if (s[j]=='-'){ b->vorzeichen*=-1; j++; } /* zunächst erforderliche Längen bestimmen */ /* bislang kein Dezimaltrenner erkannt */ deztren=0; /* durchlaufen bis zum Stringende */ for (; s[j]!='\0'; j++){ if (s[j]=='.') /* Flag für erkannten Dezimaltrenner setzen */ deztren=1; else{ b->laenge++; if (deztren) b->nachkommastellen++; } } /* Ziffernarray dynamisch reservieren entsprechend den nun bekannten Längen */ b->ziffern=malloc(b->laenge*sizeof(unsigned char)); /* zurück auf Anfang */ j=0; if (s[j]=='-') j++; /* String durchlaufen und BCD-Ziffern übernehmen */ k=0; for (; s[j]!='\0'; j++) if (s[j]!='.') b->ziffern[k++]=s[j]-'0'; return b; }
Würde die Funktion, so wie sie hier steht, funktionieren? Der Compiler meckert nämlich bei den Zeilen mit den Pfeilen ("->") oder liegt es daran, dass ich noch kein richtiges Programm habe?
Um die Feinheiten, wie Leerzeichen überlesen etc., kümmere ich mich dann am Ende.Nach welchem Schema muss ich in der zweiten Funktion vorgehen? Ich muss ja den BCD-Code wieder in double umwandeln. Da fehlt mir jetzt irgendwie der Ansatz, weil einfach das ganze rückwärts funktioniert ja nicht.
-
Siegfried101 schrieb:
const char *s; /* double in string umwandeln*/ sprintf(*s,"%f",x);
s ist so ein Zeiger, der irgendwohin - wahrscheinlich ins Nirwana - zeigt. Deshalb würde sprintf irgendwohin - wahrscheinlich mit Absturz - schreiben. So ist es richtig:
#include <stdio.h> #include <stdlib.h> struct bcd_number { unsigned int laenge; unsigned int nachkommastellen; char vorzeichen; unsigned char *ziffern; }; struct bcd_number * string2bcd(double x){ struct bcd_number *b; int j,k; int deztren; char s[512]; /* double in string umwandeln*/ sprintf(s,"%.10f",x); /* Speicher reservieren */ b=malloc(sizeof(struct bcd_number)); b->laenge=0; b->nachkommastellen=0; b->vorzeichen=1; j=0; /* Negatives Vorzeichen detektieren */ if (s[j]=='-'){ b->vorzeichen*=-1; j++; } /* zunächst erforderliche Längen bestimmen */ /* bislang kein Dezimaltrenner erkannt */ deztren=0; /* durchlaufen bis zum Stringende */ for (; s[j]!='\0'; j++){ if (s[j]=='.') /* Flag für erkannten Dezimaltrenner setzen */ deztren=1; else{ b->laenge++; if (deztren) b->nachkommastellen++; } } /* Ziffernarray dynamisch reservieren entsprechend den nun bekannten Längen */ b->ziffern=malloc(b->laenge*sizeof(unsigned char)); /* zurück auf Anfang */ j=0; if (s[j]=='-') j++; /* String durchlaufen und BCD-Ziffern übernehmen */ k=0; for (; s[j]!='\0'; j++) if (s[j]!='.') b->ziffern[k++]=s[j]-'0'; return b; } int main( void ) { double eingabe = -2345.2; struct bcd_number* bcd; size_t i; bcd = string2bcd (eingabe); printf ("Eingabe: %f\n",eingabe); printf ("bcd.laenge: %u\n",bcd->laenge); printf ("bcd.nachkommastellen: %u\n",bcd->nachkommastellen); printf ("bcd.vorzeichen: %i\n",bcd->vorzeichen); printf ("bcd.ziffern: "); for (i=0; i<bcd->laenge; ++i) printf ("%i ",bcd->ziffern[i]); puts ("\n"); free (bcd->ziffern); free (bcd); return 0; }
Hier mal zu Weihnachten meine Version. Zwar mit math.h, aber vielleicht kannst Du ein paar Ideen verwerten:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> struct bcd_number { unsigned int laenge; unsigned int nachkommastellen; char vorzeichen; unsigned char *ziffern; }; struct bcd_number* double2bcd(double x) { char tmp[512]; struct bcd_number* bcd = malloc (sizeof(struct bcd_number)); double vor, nach = modf (x, &vor); bcd->ziffern = malloc (512); char* z = (char*) bcd->ziffern; sprintf (tmp,"%.f",fabs(vor)); bcd->laenge = strlen(tmp); bcd->vorzeichen = (vor < 0) ? '-' : '+'; for (size_t i=0; i<bcd->laenge; ++i) { *z++ = tmp[i] - '0'; } sprintf (tmp,"%.40f",fabs(nach)); for (size_t i = strlen(tmp)-1; i!=0; --i) if (tmp[i] != '0') { tmp[i+1] = 0; break; } bcd->nachkommastellen = strlen(tmp+2); bcd->laenge += bcd->nachkommastellen; for (char* t = tmp + 2; *t; *z++ = *t++ - '0'); bcd->ziffern = realloc (bcd->ziffern, bcd->laenge); return bcd; } double bcd2double (struct bcd_number* b) { char tmp[512]; char* t = tmp; unsigned char * z = b->ziffern; unsigned i, imax; *t++ = b->vorzeichen; for (i = 0, imax = b->laenge - b->nachkommastellen; i < imax; ++i) sprintf (t++,"%u",*z++); *t++ = '.'; for (imax = b->laenge; i < imax; ++i) sprintf (t++,"%u",*z++); *t = 0; return atof (tmp); } int main( void ) { double eingabe = -2345.2; printf ("Eingabe: %f\n\n",eingabe); struct bcd_number* bcd = double2bcd(eingabe); printf ("bcd.laenge: %u\n",bcd->laenge); printf ("bcd.nachkommastellen: %u\n",bcd->nachkommastellen); printf ("bcd.vorzeichen: %c\n",bcd->vorzeichen); printf ("bcd.ziffern: "); for (size_t i=0; i<bcd->laenge; ++i) printf ("%i ",bcd->ziffern[i]); puts ("\n"); double dobbel = bcd2double (bcd); printf ("Double (evtl von printf gerundet): %f\n",dobbel); free (bcd->ziffern); free (bcd); return 0; }
:xmas1:
Frohe Weihnachten
ralph
-
Der genaue Mecker (Wortlaut) vom Compiler wär schon interessant wenn man dir helfen soll.
Und dein
const char *s; /* double in string umwandeln*/ sprintf(*s,"%f",x);
funktioniert so nicht, da du weder s initialisiert hast und somit s auch auf keinen sinnvollen Speicher zeigt.
Ein Array für genug ZEichen sollte reichen.Auch gibt das %f sechs Nachkommastellen aus, was für deinen Zweck auch nicht ausreicht. Du kannst auch mehr Nachkommstellen angeben, das ergibt für sehr kleine Werte trotzdem falsche Werte.
Schau dir mal den Formatspecifier %g an oder Versuch es mal mit log10.
-
außer einer viel zu umständlichen
und ungenauen aufteilung einer double zahl in ziffern hat das ja noch nicht allzu viel mit bcd zu tun, oder?
-
dr. arrogance schrieb:
außer einer viel zu umständlichen
und ungenauen aufteilung einer double zahl in ziffern...
Besser machen, nicht nur Sprüche klopfen! :p
rkhb schrieb:
...
Hier mal zu Weihnachten meine Version.
...Okay, weil Weihnachten ist,
lasse ich mich auch nicht lumpen.
Kommt mit unter den Weihnachtsbaum. :xmas1: :xmas2:
.oO Ein bisschen eigenartig die Aufgabe ... double to BCD ... .oO .oO .oO .. aber man gönnt sich ja sonst nichts!#include <stdio.h> #include <stdlib.h> struct bcd_number { int laenge, nachkommastellen; char vorzeichen, *ziffern; }; int double2bcd(struct bcd_number* pbcd, double x) { char buf[CHAR_BIT*sizeof(x)+2]; int len = sprintf(buf, "%lf", x); char *p = buf + len -1; x < 0 ? pbcd->vorzeichen = -1 : (pbcd->vorzeichen = 1); while ( p >= buf && '0' == *p ) p--; for ( ; p >= buf && *p >= '0' && *p <= '9'; p-- ) pbcd->laenge++, pbcd->nachkommastellen++; if ( p >= buf && '.' != *p ) pbcd->nachkommastellen = 0; else if ( p >= buf && '.' == *p ) p--; for ( ; p >= buf && *p >= '0' && *p <= '9'; p-- ) pbcd->laenge++; if ( NULL != (pbcd->ziffern = malloc ( pbcd->laenge ))) for ( p = buf, len = 0; len < pbcd->laenge; p++ ) if ( *p >= '0' && *p <= '9' ) pbcd->ziffern[len++] = *p; return NULL == pbcd->ziffern; // 1: Fehler, out of memory. 0: Okay. } double bcd2double(struct bcd_number* pbcd) { double number = 0, exp = 1; char* p = pbcd->ziffern + pbcd->laenge - pbcd->nachkommastellen -1, *q = p + 1; for ( ; p >= pbcd->ziffern; exp*=10, p--) number += (*p - '0') * exp; for ( exp = 1.0/10; q <= pbcd->ziffern + pbcd->laenge-1; q++, exp /= 10 ) number += (*q - '0') * exp; return number * pbcd->vorzeichen; } int main( void ) { double eingabe = -2345.2; struct bcd_number bcd = {0}; if (double2bcd(&bcd, eingabe)) return 0; else printf("%lf", bcd2double(&bcd)); free (bcd.ziffern); return 0; }
-
CJosef schrieb:
... if ( NULL != (pbcd->ziffern = malloc ( pbcd->laenge ))) for ( p = buf, len = 0; len < pbcd->laenge; p++ ) if ( *p >= '0' && *p <= '9' ) pbcd->ziffern[len++] = *p; return NULL == pbcd->ziffern; // 1: Fehler, out of memory. 0: Okay. }
Laut Wikipedia wird die Zahl 10 BCD mit (0001 0000) kodiert. Es handelt sich also um einen numerischen Code, der jede Ziffer einer Dezimalzahl einzeln dualkodiert.
Der vorliegende Code gibt das Ergbnis offensichtlich hexadezimal aus
Und da ausserdem Weihnachten ist sollte man auch etwas spendabler sein wenn
man eine Zeichenkette kodiert:if( NULL != (pbcd->ziffern = malloc ( pbcd->laenge +1))) { for( p = buf, len = 0; len < pbcd->laenge; p++ ) if( *p >= '0' && *p <= '9' ) pbcd->ziffern[len++] = *p; pbcd->ziffern[len] = 0; } return NULL == pbcd->ziffern; /* 1: Fehler, out of memory. 0: Okay. */ }
-
merano schrieb:
Der vorliegende Code gibt das Ergbnis offensichtlich hexadezimal aus
Ach was, daran ist nichts hexadezimal. Das ist nur eine Vereinfachung, anstatt
pbcd->ziffern[len++] = *p - '0';
zu schreiben.
Den Offset von '0' kann man sich ruhig gönnen(es ist Weihnachten :P), weil doch von den 8 Bit eines char sowieso nur 4 gebraucht werden.
Passt also rein.
Ob ich den Offset jetzt oder später abziehe ist doch Wurscht.
Okay, ein bisschen richtiger wäre es, ihn sofort zu subtrahieren.
Dann ist das eben eine ASCII Offset Verschlüsselungmerano schrieb:
Und da ausserdem Weihnachten ist sollte man auch etwas spendabler sein wenn
man eine Zeichenkette kodiert:if( NULL != (pbcd->ziffern = malloc ( pbcd->laenge +1))) { ...
Wer bin ich mir anzumaßen ein bereits designtes, festgelegtes Datenformat zu ändern?
Dabei soll jede einzelne Dezimalstelle einer Zahl n mit k Dezimalstellen separat gespeichert werden, sodass eine k-stellige Dezimalzahl durch einen k- dimensionalen Vektor n dargestellt wird.
:p
-
Vielen Dank für die tolle Hilfe! Ich hoffe ihr wurdet reichlich beschenkt! :xmas1:
Wenn ich das jetzt richtig sehe, kann ich den BCD-Code nicht wie eine normale Zahl (wie z.B. einen double oder int) verwenden oder? Jede Ziffer hat ja ihre eigene Belegung im Array.
Wie integriert man diesen BCD-Code, wenn ich noch eine erweiterte Funktion erstellen möchte bzw. muss, der mit diesem Code arbeiten soll?
-
kapitel funktionen in deinem c buch
-
Ich habe hier jetzt eine Funktion, mit der ich den BCD-Code von führenden und angehängten Nullen reinige.
struct bcd_number * clean_bcd(struct bcd_number *b){ int i,j=0,k=0; for (i=0; i < b->laenge; i++) { while (b->ziffern[i] == 0) { j++; } } for (i=0; i < b->laenge; i++){ b->ziffern[i] = b->ziffern[i+j]; } for (i=0; i < b->laenge; i++){ if( b->ziffern[i] == 0){ k++; } else k=0; } b->laenge = b->laenge - (j+k); b->nachkommastellen = j - k; return b; } int main( void ) { double eingabe = -2345.2; struct bcd_number* bcd; int i; bcd = string2bcd (eingabe); printf ("Eingabe: %f\n",eingabe); printf ("bcd.laenge: %u\n",bcd->laenge); printf ("bcd.nachkommastellen: %u\n",bcd->nachkommastellen); printf ("bcd.vorzeichen: %i\n",bcd->vorzeichen); printf ("bcd.ziffern: "); for (i=0; i<bcd->laenge; ++i) printf ("%i ",bcd->ziffern[i]); puts ("\n"); clean_bcd(bcd); printf ("Eingabe: %f\n",eingabe); printf ("bcd.laenge: %u\n",bcd->laenge); printf ("bcd.nachkommastellen: %u\n",bcd->nachkommastellen); printf ("bcd.vorzeichen: %i\n",bcd->vorzeichen); printf ("bcd.ziffern: "); for (i=0; i<bcd->laenge; ++i) printf ("%i ",bcd->ziffern[i]); puts ("\n"); free (bcd->ziffern); free (bcd); return 0; }
Leider steht da nach dem compilieren nichts für die werte nach
clean_bcd(bcd)
. Weiß jemand wo ich hier den Fehler habe?
-
Deine Funktion kann nicht funktionieren.
Wenn da wirklich ein 0 am Anfang ist, bleibst du bei dem j++ in einer Endlosschleife hängen.Die Nullen am Ende solltest du aber nur entfernen, wenn sie wirklich bei den Nachkommastellen sind.
Benutze den Debbuger oder baue dir Zwischenausgaben in deine Funktion ein.
-
Siegfried101 schrieb:
Ich habe hier jetzt eine Funktion, mit der ich den BCD-Code von führenden und angehängten Nullen reinige.
Wer zwingt Dich nur, vor Jahresende so etwas zu tun?
Ich hab Dir mal ein Prüfprogramm entworfen, damit Du auch ein paar Nullen zum Herumspielen hast:#include <stdio.h> struct bcd_number { unsigned int laenge; unsigned int nachkommastellen; signed char vorzeichen; unsigned char *ziffern; }; struct bcd_number * clean_bcd(struct bcd_number *b) { unsigned int i, j=0, imax, imin; /* Führende Vorkomma-Nullen eliminieren */ imax = b->laenge - b->nachkommastellen - 1; for (i=0; i < imax; ++i) { if (b->ziffern[i] == 0) { j++; } else break; } imax = b->laenge - j; for (i=0; i < imax; ++i) { b->ziffern[i] = b->ziffern[i+j]; } b->laenge -= j; /* Nachlaufende Nachkomma-Nullen eliminieren */ imin = b->laenge - b->nachkommastellen; for (i = b->laenge - 1; i >= imin; --i) { if (b->ziffern[i] == 0) { --b->nachkommastellen; --b->laenge; } else break; } return b; } /* Testziffern */ #define Z0 {0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0} /* 0.0 */ #define Z1 {0,0,0,0,0,0, 2,0,0,0,0,0,0,0,0,0} /* 0.2 (n=10)*/ #define Z2 {0,0,0,0,0,5, 2,0,0,0,0,0,0,0,0,0} /* 5.2 (n=10)*/ #define Z3 {0,0,0,0,0,5, 0,0,0,0,0,0,0,0,0,0} /* 5.0 (n=10)*/ #define Z4 {0,0,0,5,0,5, 0,0,0,0,0,0,0,0,0,0} /* 505.0 (n=10)*/ #define Z5 {0,0,0,5,0,5, 2,0,2,0,0,0,0,0,0,0} /* 505.202 (n=10)*/ #define Z6 {2,3,4,0,6,0, 0,8,9,0,1,3,5,7,9,2} /* 234060.0890135792 (n=10)*/ unsigned char testziffern[] = Z5; /* hier Z0, Z1, Z2... einsetzen */ int main( void ) { unsigned int i; struct bcd_number bcd = { sizeof(testziffern), 10, -1, testziffern }; clean_bcd(&bcd); printf ("bcd.laenge: %u\n",bcd.laenge); printf ("bcd.nachkommastellen: %u\n",bcd.nachkommastellen); printf ("bcd.vorzeichen: %i\n",bcd.vorzeichen); printf ("bcd.ziffern: "); for (i=0; i<bcd.laenge; ++i) printf ("%i ",bcd.ziffern[i]); puts ("\n"); return 0; }
Wenn Du noch IDE/Compiler/Betriebssystem angeben würdest, dann könnte man Tipps zum Debuggen geben. Debuggen zu können ist so wichtig wie programmieren zu können.
viele grüße
ralph
-
Debuggen zu können ist so wichtig wie programmieren zu können.
Ich würde fast behaupten, es ist noch wichtiger. Leider kann ichs auch nicht per Debugger
-
rkhb schrieb:
Wenn Du noch IDE/Compiler/Betriebssystem angeben würdest, dann könnte man Tipps zum Debuggen geben. Debuggen zu können ist so wichtig wie programmieren zu können.
Also ich benutze den qt creator auf mac os. Debuggen ist mir jetzt völlig neu. In meinem C Buch wird es auch nicht erwähnt. Kennt ihr eine Quelle wo man sich einlesen kann?
-
Siegfried101 schrieb:
Also ich benutze den qt creator auf mac os.
Aaarghhh, kalt erwischt: MacOS habe ich nicht. Und der QT-Creator-Debugger zickt auf meinem WinXP. Naja:
-
Du hast in QT-Creator eine Hilfe-Funktion: Entweder links ein Icon oder oben: Hilfe-Inhalt. Nun im Fenster "Inhalt" (linksoben) "QT Creator Manual 2- Debugging and...-Debugging" klicken (Auswahl öffnet sich mit Klick auf das Plus-Zeichen). Viel Spaß bei der englischen Lektüre.
-
Lade mal mein "Prüfprogramm" oben und lasse es kompilieren. Nun gehst Du mit dem Cursor in die Zeile 9 (
j++;
) und drückst auf F9. Damit hast Du einen Breakpoint (Haltepunkt) gesetzt. Du siehst einen roten Punkt an der linken Seite. Als nächstes drückst Du auf F5 (oder klickst oben auf Debuggen-Debuggen-Debuggen). Nach einer kleinen Weile stoppt das Programm und der Cursor blinkt Dich von Zeile 9 an. Im Fenster rechts daneben siehst Du, welche Werte die lokalen Variablen im Augenblick haben. Du kannst dort weitere Ausdrücke überwachen lassen, z.B: Rechtsklick in diesem Fenster, "Neuen Ausdruck einfügen", "b->ziffern[i]" eingeben. Nun kannst Du im "Einzelschritt" (immer nur eine Zeile per Tastendruck) mit F10 die Schleife durchgehen. Du siehst, wie sich die Werte für i, j und b->ziffern[i] verändern. Um hier einen eventuellen Fehler zu entdecken, musst Du Dir natürlich völlig im Klaren sein, was in der aktuellen Zeile passieren soll. -
Wenn Du dasselbe mit Deiner nicht funktionierenden
clean_bcd
-Funktion machst, wirst Du merken, dass Du Dich schnell in einer Endlosschleife befindest. Du weißt also schon mal, wo ein Fehler ist. Dann kannst Du Dir überlegen: Was tun? -
Ein Haltepunkt wird mit einem erneuten Druck auf F9 wieder gelöscht. Das nennt sich "Toggeln" oder "Umschalten". Haltepunkte kann man an jeder Zeile setzen, wo man einen Stop wünscht. Du kannst nach einem Stop das Programm auch mit F5 wieder anlaufen lassen, es hält dann wieder an, wenn es auf einen Haltepunkt stößt.
viele grüße
ralph
-
-
rkhb schrieb:
Aaarghhh, kalt erwischt: MacOS habe ich nicht. Und der QT-Creator-Debugger zickt auf meinem WinXP. Naja:
-
Du hast in QT-Creator eine Hilfe-Funktion: Entweder links ein Icon oder oben: Hilfe-Inhalt. Nun im Fenster "Inhalt" (linksoben) "QT Creator Manual 2- Debugging and...-Debugging" klicken (Auswahl öffnet sich mit Klick auf das Plus-Zeichen). Viel Spaß bei der englischen Lektüre.
-
Lade mal mein "Prüfprogramm" oben und lasse es kompilieren. Nun gehst Du mit dem Cursor in die Zeile 9 (
j++;
) und drückst auf F9. Damit hast Du einen Breakpoint (Haltepunkt) gesetzt. Du siehst einen roten Punkt an der linken Seite. Als nächstes drückst Du auf F5 (oder klickst oben auf Debuggen-Debuggen-Debuggen). Nach einer kleinen Weile stoppt das Programm und der Cursor blinkt Dich von Zeile 9 an. Im Fenster rechts daneben siehst Du, welche Werte die lokalen Variablen im Augenblick haben. Du kannst dort weitere Ausdrücke überwachen lassen, z.B: Rechtsklick in diesem Fenster, "Neuen Ausdruck einfügen", "b->ziffern[i]" eingeben. Nun kannst Du im "Einzelschritt" (immer nur eine Zeile per Tastendruck) mit F10 die Schleife durchgehen. Du siehst, wie sich die Werte für i, j und b->ziffern[i] verändern. Um hier einen eventuellen Fehler zu entdecken, musst Du Dir natürlich völlig im Klaren sein, was in der aktuellen Zeile passieren soll. -
Wenn Du dasselbe mit Deiner nicht funktionierenden
clean_bcd
-Funktion machst, wirst Du merken, dass Du Dich schnell in einer Endlosschleife befindest. Du weißt also schon mal, wo ein Fehler ist. Dann kannst Du Dir überlegen: Was tun? -
Ein Haltepunkt wird mit einem erneuten Druck auf F9 wieder gelöscht. Das nennt sich "Toggeln" oder "Umschalten". Haltepunkte kann man an jeder Zeile setzen, wo man einen Stop wünscht. Du kannst nach einem Stop das Programm auch mit F5 wieder anlaufen lassen, es hält dann wieder an, wenn es auf einen Haltepunkt stößt.
viele grüße
ralphBesten Dank Ralph! Man muss sich daran erstmal gewöhnen, aber mit bisschen Routine ist das wohl eine sehr große Hilfe.
Ich bastel hier an noch einer Funktion mit der ich zwei BCD-Codes addiere.
struct bcd_number *addition(struct bcd_number *a, struct bcd_number *b){ int maxkomma,minkomma,maxlaenge,minlaenge,i,k,m; struct bcd_number *c; if ((a->nachkommastellen > b->nachkommastellen) || (a->nachkommastellen == b->nachkommastellen)) { maxkomma = a->nachkommastellen; minkomma = b->nachkommastellen; } else maxkomma = b->nachkommastellen; minkomma = a->nachkommastellen; if ((a->laenge > b->laenge) || (a->laenge == b->laenge)) { maxlaenge = a->laenge; minlaenge = b->laenge; } else maxlaenge = b->laenge; minlaenge = a->laenge; k = (minlaenge-maxlaenge)+(maxkomma-minkomma); m = maxlaenge+k; for (i=0; i<m; i++) { if ((a->laenge > b->laenge) || (a->laenge == b->laenge)) { c->ziffern[m-i]=a->ziffern[maxlaenge-1-i]+b->ziffern[maxlaenge-1+i+k]; } else c->ziffern[m-i]=b->ziffern[maxlaenge-1-i]+a->ziffern[maxlaenge-1+i+k]; if (c->ziffern[maxlaenge - 1 -i] > 9) { c->ziffern[maxlaenge - 1 -i] = c->ziffern[maxlaenge - 1 -i] % 10; c->ziffern[maxlaenge - 2 -i] += c->ziffern[maxlaenge - 1 -i] / 10; } } c->nachkommastellen=maxkomma; return c; }
Es wird zwar fehlerfrei combiliert, aber leider werden keine Ergebnisse angezeigt. Eine Endlosschleife wird's diesmal nicht sein.
Ist das Prinzip nach dem ich hier vorgegangen bin vertretbar? Oder bin ich völlig auf dem Holzweg?
-
-
Initialisierung von c fehlt.
-
Bashar schrieb:
Initialisierung von c fehlt.
Oh Danke. Mit was für Werten sollte man c vorzugsweise initialisieren?
-
So wie bei string2bcd.
-
Siegfried101 schrieb:
Ich bastel hier an noch einer Funktion mit der ich zwei BCD-Codes addiere.
Ich habe mir die Funktion nur oberflächlich angeschaut und mir fällt auf,
dass der Index der Ziffern (z.B.: b->ziffern[maxlaenge-1+i+k]) zu groß werden kann.
Male Dir das Ganze mal auf Papier auf:0.406 + 2340.6091 1 1 =========== 2341.0151
Du siehst, dass an einigen Stellen eine Zahl gar keine Ziffern hat. Diese Fälle musst Du irgendwie abfedern.
Hier was zum Knobeln, falls Dir das Silvester-Fernsehprogramm zu langweilig ist:
#include <stdio.h> #include <stdlib.h> struct bcd_number { unsigned int laenge; unsigned int nachkommastellen; signed char vorzeichen; unsigned char *ziffern; }; struct bcd_number* addition (struct bcd_number *a, struct bcd_number *b) { unsigned int i; int pad_a, pad_b; unsigned char* az, * bz, * cz; unsigned char aa, bb, cc, ue; /* Stichwort: ternärer Operator */ unsigned int max_nachkomma = (a->nachkommastellen > b->nachkommastellen) ? a->nachkommastellen : b->nachkommastellen; unsigned int max_vorkomma = (a->laenge - a->nachkommastellen > b->laenge - b->nachkommastellen) ? a->laenge - a->nachkommastellen : b->laenge - b->nachkommastellen; struct bcd_number* c = malloc (sizeof (struct bcd_number)); /* free() nicht vergessen! */ c->laenge = max_vorkomma + max_nachkomma; c->nachkommastellen = max_nachkomma; c->vorzeichen = +1; /* provisorisch */ c->ziffern = malloc (c->laenge); /* free() nicht vergessen! */ pad_a = max_nachkomma - a->nachkommastellen; /* "Keine Nachkommastelle"-Indikator */ pad_b = max_nachkomma - b->nachkommastellen; /* "Keine Nachkommastelle"-Indikator */ az = a->ziffern + a->laenge - 1; /* auf letzte Ziffer zeigen */ bz = b->ziffern + b->laenge - 1; /* auf letzte Ziffer zeigen */ cz = c->ziffern + c->laenge - 1; /* auf letzte Ziffer zeigen */ ue = 0; /* Übertrag */ for (i = max_nachkomma + max_vorkomma; i > 0; --i) { aa = (pad_a-- > 0 || az < a->ziffern) ? 0 : *az--; /* 1. Fall: Keine Nachkommastelle, 2. Fall: Keine Vorkommastelle */ bb = (pad_b-- > 0 || bz < b->ziffern) ? 0 : *bz--; cc = aa + bb + ue; if (cc > 9) { ue = 1; cc -= 10; } else ue = 0; *cz-- = cc; } return c; } struct bcd_number * clean_bcd(struct bcd_number *b) { unsigned int i, j, imax, imin; imax = b->laenge - b->nachkommastellen - 1; for (j=0; j < imax && !b->ziffern[j]; ++j); imax = b->laenge - j; for (i=0; i < imax; ++i) b->ziffern[i] = b->ziffern[i+j]; b->laenge -= j; imin = b->laenge - b->nachkommastellen; for (i = b->laenge - 1; i >= imin && !b->ziffern[i]; --i, --b->nachkommastellen, --b->laenge); return b; } /* Testziffern */ #define Z0 {0,0,0,0,0,0, 4,0,6,0,0,0,0,0,0,0} /* 0.406 (n=10)*/ #define Z1 {0,0,2,3,4,0, 6,0,9,1,0,0,0,0,0,0} /* 2340.609 (n=10)*/ unsigned char testziffern1[] = Z0; unsigned char testziffern2[] = Z1; int main( void ) { unsigned int i; struct bcd_number a = { sizeof(testziffern1), 10, +1, testziffern1 }; struct bcd_number b = { sizeof(testziffern2), 10, +1, testziffern2 }; struct bcd_number* c; clean_bcd(&a); clean_bcd(&b); puts (" l | n | v | z"); puts ("-----------------------------------------------------"); printf ("a %3u | %3u | %2i | ", a.laenge, a.nachkommastellen, a.vorzeichen); for (i=0; i<a.laenge; ++i) printf ("%i ",a.ziffern[i]); puts (""); printf ("b %3u | %3u | %2i | ", b.laenge, b.nachkommastellen, b.vorzeichen); for (i=0; i<b.laenge; ++i) printf ("%i ",b.ziffern[i]); puts (""); c = addition (&a, &b); printf ("c %3u | %3u | %2i | ", c->laenge, c->nachkommastellen, c->vorzeichen); for (i=0; i<c->laenge; ++i) printf ("%i ",c->ziffern[i]); puts (""); free (c->ziffern); free (c); return 0; }
Guten Rutsch!
viele grüße
ralph