wenn long long nicht mehr reicht

Gast #2136987
Lesenswert?

Hi,
um einen 48 Bit DDS Synthesizer anzusteuern brauche ich eine eine 
Division mit 48 Bit Ergebnis.
Ich habe das im Moment so gelöst:
1
//**********************************************************************
2
//***** Ergebnis(48-Bit) = Frequenz(40-Bit) * 2^48 / Ref(40-Bit) *******
3
//**********************************************************************
4
void Set_DDS_Freq(unsigned long long Frequenz) // in Millihertz!!!
5
{
6
const unsigned long long int Ref=300000000000; // in Millihertz!!!
7
unsigned short int Dummy;
8
unsigned char ACC,Byte[11],Teiler[5];
9
struct
10
{
11
  unsigned char CY:1;
12
  unsigned char F0:1;
13
}PSW;
14

15
Byte[10] = Frequenz >> 32;
16
Byte[9]  = Frequenz >> 24;
17
Byte[8]  = Frequenz >> 16;
18
Byte[7]  = Frequenz >> 8;
19
Byte[6]  = Frequenz >> 0;
20
Byte[5]  = 0x00;
21
Byte[4]  = 0x00;
22
Byte[3]  = 0x00;
23
Byte[2]  = 0x00;
24
Byte[1]  = 0x00;
25
Byte[0]  = 0x00;
26
Teiler[4] = Ref >> 32;
27
Teiler[3] = Ref >> 24;
28
Teiler[2] = Ref >> 16;
29
Teiler[1] = Ref >> 8;
30
Teiler[0] = Ref >> 0;
31

32
for(unsigned char n=48;n;n--)
33
{
34
  PSW.CY=0;
35
  for(unsigned char i=0;i <= 10;i++)
36
  {
37
    ACC = Byte[i];
38
      Dummy = ACC + ACC + PSW.CY;  //8051 RLC_A nachbilden
39
      ACC = Dummy;
40
      PSW.CY = Dummy >> 8;
41
    Byte[i] = ACC;
42
  }
43
  PSW.F0 = PSW.CY;
44
  if(PSW.CY == 0)
45
  {
46
    for(unsigned char i=0;i <= 4;i++)
47
    {
48
      ACC = Byte[i + 6];
49
        Dummy = ACC - Teiler[i] - PSW.CY; //8051 SUBB nachbilden
50
        ACC = Dummy;
51
        PSW.CY = Dummy >> 8;
52
    }
53
  }
54
  if(PSW.F0==1 || PSW.CY==0)
55
  {
56
    PSW.CY = 0;
57
    for(unsigned char i=0;i <= 4;i++)
58
    {
59
      ACC = Byte[i + 6];
60
        Dummy = ACC - Teiler[i] - PSW.CY; //8051 SUBB nachbilden
61
        ACC = Dummy;
62
        PSW.CY = Dummy >> 8;
63
      Byte[i + 6] = ACC;
64
    }
65
    Byte[0] |= 0x01;
66
  }
67
}
68
//************** 48-Bit Ergebnis an DDS senden  ************************
69
Set_DDS_Reg(0x04,Byte[5]); // Frequency Tuning Word 1 <47:40>
70
Set_DDS_Reg(0x05,Byte[4]); // Frequency Tuning Word 1 <39:32>
71
Set_DDS_Reg(0x06,Byte[3]); // Frequency Tuning Word 1 <31:24>
72
Set_DDS_Reg(0x07,Byte[2]); // Frequency Tuning Word 1 <23:16>
73
Set_DDS_Reg(0x08,Byte[1]); // Frequency Tuning Word 1 <15:8>
74
Set_DDS_Reg(0x09,Byte[0]); // Frequency Tuning Word 1 <7:0>
75
}
Ein 88-Bit Word wird durch ein 40-Bit Word geteilt, das Ergebnis hat 
48-Bit. Es funktioniert sogar!

Nun meine Frage:
1. Kann man das auch anders lösen? Eventuel wirklich Assembler 
einbinden, anstatt einen alten 8051-Code in C nachzubilden?

2. Ist diese Division überhaupt nötig?
#2137035
Lesenswert?

Die Rechnung benutzt am Anfang eine 88-Bit-Zahl, also wesentlich mehr 
als 64 Bit (long long). Eine Möglichkeit - Voraussetzung: ausreichend 
lange Mantisse entsprechender Floating-Point-Zahlen - besteht darin, mit 
Floating-Point-Zahlen (Frequenz ebenfalls in MilliHertz!!!) zu rechnen 
und die Zahlen zur Ausgabe nach long long umzuformen. Das war zu Zeiten 
der 16-Bit PCs im Bankenbereich recht elegant: Beträge wurden definiert 
als Pfennige und in double gerechnet.

Bernhard
Persönliche Seite #2137076
Lesenswert?

Karl Heinz Buchegger schrieb:
> Bernhard R. schrieb:
>
>> der 16-Bit PCs im Bankenbereich recht elegant: Beträge wurden definiert
>> als Pfennige und in double gerechnet.
>
> Ganz sicher nicht.
> double hat im Bankbereich überhaupt nichts zu suchen. Jedes Finanzamt
> oder Bankenaufischt schmeisst dir so einen Code (mit Recht) sofort um
> die Ohren.

Ist da eigentlich decimal float erlaubt?
#2137094
Lesenswert?

Karl Heinz Buchegger schrieb:
> Ganz sicher nicht.
> double hat im Bankbereich überhaupt nichts zu suchen. Jedes Finanzamt
> oder Bankenaufischt schmeisst dir so einen Code (mit Recht) sofort um
> die Ohren.

Es wurde tatsächlich so gemacht und lief fehlerfrei. Wenn Du z.B. 50 
Millionen DM mit 0,01 DM addierst, geschieht:
5.000.000.000,0 Pfennige
+           1,0 Pfennig
sind

5.000.000.001,0 Pfennig. Versuche das bitte mit 32-Bit-Integer zu 
rechnen.

Zur Umwandlung in menschenlesbare Werte waren nicht einmal spezielle 
Routinen erforderlich.

Dieses Verfahren war in mehr als nur einer Bank üblich.

Allerdings widersprechen sich auf den ersten flüchtigen Blick das 
Zahlenformat "double" und kaufmännische Anforderungen.

Bernhard
#2137096
Lesenswert?

Bernhard R. schrieb:
> Karl Heinz Buchegger schrieb:
>> Ganz sicher nicht.
>> double hat im Bankbereich überhaupt nichts zu suchen. Jedes Finanzamt
>> oder Bankenaufischt schmeisst dir so einen Code (mit Recht) sofort um
>> die Ohren.
>
> Es wurde tatsächlich so gemacht und lief fehlerfrei. Wenn Du z.B. 50
> Millionen DM mit 0,01 DM addierst, geschieht:
> 5.000.000.000,0 Pfennige
> +           1,0 Pfennig
> sind
>
> 5.000.000.001,0 Pfennig. Versuche das bitte mit 32-Bit-Integer zu
> rechnen.

Dann nimmt man längere Integer bzw ein Format das mit BCD arbeitet.

Aber spätestens nach dem Versuch 10 Stück 0.1 zu addieren und da kommt 
dann nicht 1.0 heraus, ist double auf ganzer Linie gescheitert.

Buchhaltungsprogrammierer (genauso wie Bänker) haben Monate gesucht um 
fehlende Pfennige in ihren Programmen zu finden, die sie irgendwo bei 
Zinseszinsrechnungen verloren haben.

double mag für den Berater ok sein, der dir auf seinem Excel mal schnell 
die Ratenbelastung für einen Kredit ausrechnet. Aber auf dem 
Grossrechner, der die Konten führt, gibts kein double.
#2137105
Lesenswert?

U.R. Schmitt schrieb:
> Hallo Karl Heinz,
> ich arbeite (mit Unterbrechung) schon 20J in Unternehmen, die Software
> für Banken schreiben.
> Das (double als Zahlenformat) wurde (und wird immer noch zum Teil)
> gemacht. Mir haben sich da auch schon öfter die Fussnägel aufgerollt.
> Dabei gibts doch - wie du schon gesagt hast- BCD Zahlen.

Und das geile daran: die gibt es von Anfang an. Waren in COBOL schon 
gang und gäbe und wurden extra für diesen Zweck eingebaut.
#2137119
Lesenswert?

DirkB schrieb:
> Karl Heinz Buchegger schrieb:
>> Aber spätestens nach dem Versuch 10 Stück 0.1 zu addieren und da kommt
>> dann nicht 1.0 heraus, ist double auf ganzer Linie gescheitert.
>
> Warum sollte man das denn machen?

Weil es in Banken nun mal nicht so selten vorkommt, dass viele Zahlen 
addiert werden müssen? Und diese Zahlen durch Zinsberechnung schon auch 
mal krumme Werte ergeben?

> Es geht um Pfennige/Cent. Und bei
> Integern geht das auch nicht (0,1 Cent addieren).

Warum nimmt man dann nicht gleich entsprechend große Integer?
Persönliche Seite #2137132
Lesenswert?

Und wie machen Banken eine Division? Die geht doch meist nicht als 
Integer auf.
Transzendente oder zumindest irrationale Zahlen?? Zinzeszins? Verwenden 
die wenigstens Brüche als interne Darstellung? Gibts einen Standard, der 
die Anforderungen und letztendlichen Ungenauigkeiten definiert?
Und eine Geldsumme, die insgesamt begrenzt ist, würde mich auch wundern.
#2137167
Lesenswert?

Abdul K. schrieb:
> Transzendente oder zumindest irrationale Zahlen??

Warum sollte ein double Format solche solche Zahlen besser darstellen?
Und Divisionen lassen sich mit BCD genauso rechnen wie mit double.
Dass die Division von float und doubles von der Hardware unterstützt 
ist, und deshalb schneller ist, hat aber mit dem Prinzip nichts zu tun.
Gast #2137343
Lesenswert?

brushless schrieb:
> @ kleiner Programmierer,
>
> schau Dir mal das an:
> Beitrag "große Zahl (lomg long) und trotzdem genau ?"
>
> Gruß Mattias

Hallo Mattias,
du hast damals zuletzt dieses gehabt:
1
#define X (2814749767107)
2
unsigned (long long) t_word;
3
unsigned int i,j,k,l,m;
4

5

6
t_word =
7
(i * X) +
8
(j * (X / 1000)) +
9
(unsigned long) (
10
(k * (X / 1000000)) +
11
(l * (X / 1000000000)) +
12
(m * (X / 1000000000000)));
Die Nano-Hertz lässt du (zu recht?) unter den Tisch fallen.
Bei der Berechnung der µHz ergibt
2814749767107/1000000000000 = 2
Hier verschenkst du Auflösung, der DDS hat immerhin eine Auflösung von
100MHz (Ref) / 2^48 = 355 nHz

Da ich nicht nur einen DDS-Baustein programmieren will, sondern meinen 
Programmierstil noch verbessern wollte, zielt dieser Thread eher darauf, 
ob das Programmiertechnisch alles OK ist, ob man da noch was ändern 
sollte.
#2137570
Lesenswert?

Zunächst einmal:
Ich habe mich offensichtlich mißverständlich ausgedrückt. In 
Bankanwendungen - wo es um Geld zählen geht, werden Berechnungen mit 
recht großen Integer-Werten benötigt. Vor knapp 30 Jahren, zu Zeiten von 
16-Bit CPUs im PC, besaß die größte darstellbare Integer-Zahl vieler 
C-Compiler 32 Bit; das entsprach ca. 40 Millionen DM - nicht genug.
Eine einfache Methode, Integer-Werte mit mehr als 32 Bit darzustellen, 
bestand darin, mit double-Werten zu arbeiten - sorgfältigst skaliert, um 
ja nicht in Rundungsprobleme hineinzulaufen. Das war immer noch 
wesentlich weniger aufwendig, als eine entsprechende Library mit 
längeren Integern zu implementieren!

U.R. Schmitt schrieb:
> ich arbeite (mit Unterbrechung) schon 20J in Unternehmen, die Software
> für Banken schreiben.
> Das (double als Zahlenformat) wurde (und wird immer noch zum Teil)
> gemacht. Mir haben sich da auch schon öfter die Fussnägel aufgerollt.
> Dabei gibts doch - wie du schon gesagt hast- BCD Zahlen.

Auf dem Host - z.B. IBM 309x, heute Z-Series - wurden diese Beträge aus 
bereits damals historischen Gründen zum Teil sogar als "POV" (gepackt 
ohne Vorzeichen) gespeichert und ausschließlich für Berechnungen in ein 
von der CPU bearbeitbares Format überführt.

Zurück zum Problem des TO:
Ich würde diese eine Berechnung mit Floating-Point-Arithmetik lösen, 
sofern der Datentyp "double" eine ausreichende Anzahl signifikanter Bits 
zur Verfügung stellt. Ein kleiner Kommentar mit Erläuterung der 
Genauigkeitsanforderungen dürfte zu verständlichem Code führen.

Bernhard
Gast #2138045
Lesenswert?

Bernhard R. schrieb:
> Karl Heinz Buchegger schrieb:
>> Ganz sicher nicht.
>> double hat im Bankbereich überhaupt nichts zu suchen. Jedes Finanzamt
>> oder Bankenaufischt schmeisst dir so einen Code (mit Recht) sofort um
>> die Ohren.
>
> Es wurde tatsächlich so gemacht und lief fehlerfrei. Wenn Du z.B. 50
> Millionen DM mit 0,01 DM addierst, geschieht:
> 5.000.000.000,0 Pfennige
> +           1,0 Pfennig
> sind
>
> 5.000.000.001,0 Pfennig. Versuche das bitte mit 32-Bit-Integer zu
> rechnen.
>
> Zur Umwandlung in menschenlesbare Werte waren nicht einmal spezielle
> Routinen erforderlich.
>
> Dieses Verfahren war in mehr als nur einer Bank üblich.
>
> Allerdings widersprechen sich auf den ersten flüchtigen Blick das
> Zahlenformat "double" und kaufmännische Anforderungen.

Nicht nur auf den ersten Blick, jedenfalls für Leute die wissen was sie 
tun. Man kann entweder garantieren dass die Rechnung stimmt oder es 
ist per Definition Pfusch. Wer sagt denn dass ein paar Mios ausreichen, 
die Bilanzsumme einer Bank kann ja theoretisch beliebig gross sein?

Mit Double ist schon das GDP der USA oder der EU zu gross wenn man in 
Cent rechnet (man braucht normalerweise auch Centbruchteile) - Epic 
Fail.

Das Stichwort hier wäre BigInt-Library (i.e. Integer unbegrenzter 
Länge), gibt es schon seit den Zeiten der Dinosaurier oder so.
Gast #2138151
Lesenswert?

Matthias Lipinsky schrieb:
>>Buchhaltungsprogrammierer (genauso wie Bänker) haben Monate gesucht um
>>fehlende Pfennige in ihren Programmen zu finden, die sie irgendwo bei
>>Zinseszinsrechnungen verloren haben.
>
> GAbs da nicht mal einen Fall, wo ein Banker diese fehlenden Bruchteile
> von Pfennigen auf sein Konto umgeleitet hat?

Es gab mal einen Film, in dem das die Handlung war.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren