PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Wie kann man einen eigenden Datentyp definieren


Unregistered
2003-03-30, 20:17:47
Hi ,
ich habe festgestellt , als die Fibonacci Reihe programmiert habe , dass die Ergebnisse ab F46 falsch wahren.Damit diese richtig werden , möchste ich gern wissen , wie man einen Datentyp machen kann der 256 Bit genau ist.Ich programmieren mit dem Borland 6 C++ Builder

Xmas
2003-03-30, 22:19:09
Was meinst du mit F46? Das 46. Element der Reihe?
Welchen Datentyp verwendest du zur Zeit? (unsigned) int oder long? Wenn ja, kannst du mit 'unsigned long long' 64 Bit Integer verwenden.

Wenn du dann noch mehr Präzision brauchst, sag bescheid. Die Implementation eines Ganzzahltyps mit mehr als 64 Bit sowie die passende Addition (alles was du für Fibonacci brauchst) ist eigentlich sehr einfach.

aths
2003-03-31, 08:13:10
Originally posted by Xmas
Wenn du dann noch mehr Präzision brauchst, sag bescheid. Die Implementation eines Ganzzahltyps mit mehr als 64 Bit sowie die passende Addition (alles was du für Fibonacci brauchst) ist eigentlich sehr einfach. Ich würde gerne "lesen und lernen" und wäre froh, wenn du mal eine Klasse schreiben würdest, welche den 256-Bit-Integer-Datentyp und die Operation "+" bietet.

*Auf die Uhr guck* Ich sollte schleunigst los, ich Hund...

Unregistered
2003-03-31, 12:03:03
@Xmas

mit F46 meinte ich das 46 Erlement aus der Reihe.Ich hab schon unsigned long verwendet , aber weil die Präzition immer noch nicht groß genug ist , bitte ich dich mir zu erlären , wie man eine 256 Bit großen Datentyp machen kann.

x-dragon
2003-03-31, 14:14:38
Das könnte euch vielleciht helfen, habs aber selbst noch nicht getestet:
http://cplus.kompf.de/artikel/gmp.html

Xmas
2003-03-31, 15:56:23
Was ich meinte ist 'unsigned long long', dies wird von manchen Compilern als 64Bit Integer akzeptiert, ist aber leider kein ANSI Standardtyp.

Es gibt noch den compilerspezifischen Typ (unsigned) __int64, der unter anderem von BCB und VC++ unterstützt wird. Damit kommst du immerhin bis F90.


Für noch größere Zahlen geht folgendes:

class uint256
{
private:

unsigned int zahl[8];

public:

uint256(unsigned int val = 0)
{
zahl[0] = val;
for(i = 1; i < 8; i++)
zahl[i] = 0;
}

uint256 operator+ (uint256& rhs)
{
uint256 result(rhs);

unsigned int carry = 0, r;
for(int i = 0; i < 8; i++)
{
r = zahl[i] + result.zahl[i] + carry;
carry = ((r < zahl[i]) || (r < result.zahl[i])) ? 1 : 0;
result.zahl[i] = r;
}
return result;
}
};


Leider fällt mir nur gerade kein einfacher Weg ein das in eine Dezimalzahl zum Ausgeben umzuwandeln. Deshalb ist vielleicht diese Variante besser:


class bcd32
{
private:
char zahl[32];

public:
bcd32(unsigned int val = 0)
{
for(int i = 0; i < 32; i++)
{
zahl[i] = val % 10;
val = val / 10;
}
}

bcd32 operator+ (bcd32& rhs)
{
bcd32 result(rhs);
int carry = 0;
for(int i = 0; i < 32; i++)
{
result.zahl[i] += zahl[i] + carry;
carry = result.zahl[i] / 10;
result.zahl[i] = result.zahl[i] % 10;
}
return result;
}

friend ostream& operator<< (ostream& os, bcd32 val)
{
bool leadzero = false;
int j = 0;
char buffer[33];
for(int i = 31; i >= 0; i--)
{
if(val.zahl[i] > 0) leadzero = true;
if(leadzero || (i == 0))
{
buffer[j++] = val.zahl[i] | 0x30; // in ASCII-Zeichen umwandeln
}
}
buffer[j] = '\0';
os << buffer;
return os;
}
};


Mit Inline-ASM geht das nochmal etwas schneller und kürzer, aber das wäre wahrscheinlich nicht so verständlich;

Unregistered
2003-03-31, 17:27:28
Originally posted by Xmas

Für noch größere Zahlen geht folgendes:


uint256(unsigned int val = 0)
{
zahl[0] = val;
for(i = 1; i < 8; i++)
zahl[i] = 0;
}


Also wenn ich richtig verstanden habe , ist das der Konstruktor der Klasse uint256 und als Parameter erwartet einen unsigned int.Dieser übergebene wert wird in dem Array gespeichert. Val kann ich doch für den Wert von F1 und F2 benutzen oder ?


uint256 operator+ (uint256& rhs)
{
uint256 result(rhs);

unsigned int carry = 0, r;
for(int i = 0; i < 8; i++)
{
r = zahl[i] + result.zahl[i] + carry;
carry = ((r < zahl[i]) || (r < result.zahl[i])) ? 1 : 0;
result.zahl[i] = r;
}
return result;
}
};


Hier wird der + operator überlagert.Wozu ist rhs da? Ist das dafür das Adresse von f1 oder f2 kennt ?
]



class bcd32
{
private:
char zahl[32];


Wieso ist für den Zahl die Zahl 32 übergeben? Ist das für die Anzahl der Bits ?



bcd32(unsigned int val = 0)
{
for(int i = 0; i < 32; i++)
{
zahl[i] = val % 10;
val = val / 10;
}
}


Wieso wird hier Modolo 10 gerechnet und val dann durch 10 geteilt?


bcd32 operator+ (bcd32& rhs)
{
bcd32 result(rhs);
int carry = 0;
for(int i = 0; i < 32; i++)
{
result.zahl[i] += zahl[i] + carry;
carry = result.zahl[i] / 10;
result.zahl[i] = result.zahl[i] % 10;
}
return result;
}


Hier noch mal die Frage warum durch bzw Modolo 10 gerechnet wird


friend ostream& operator<< (ostream& os, bcd32 val)
{
bool leadzero = false;
int j = 0;
char buffer[33];
for(int i = 31; i >= 0; i--)
{
if(val.zahl[i] > 0) leadzero = true;
if(leadzero || (i == 0))
{
buffer[j++] = val.zahl[i] | 0x30; // in ASCII-Zeichen umwandeln
}
}
buffer[j] = '\0';
os << buffer;
return os;
}
};



Die Friendfunktion tut es nicht , der Compilier sagt , das friend funktion Klassen oder Funktion sein müsssen. Benutzt du hier die Friend Funktion damit du auf die geschützten Bereiche einer Klasse zugreifen kannst oder warum?
unsigned int o=3222
Wenn ich z.B uint256::uint256(o) eingebe ist das schon eine 256 Bit Zahl ? Kann ich den ofstream der zurückgeliefert wird , auch mit Memo Feldern benutzen?
Sory für die vielen Fragen und großes thx für die Mühe die du dir gemacht hast.

Xmas
2003-03-31, 18:08:24
Lassen wir mal die uint256 weg, weil sie keine dezimale Ausgabe ermöglicht.


Folgender Code (diesmal mit mehr Kommentaren) gibt die ersten 200 Fibonacci-Zahlen aus.


#include <iostream>
using namespace std;

class bcd32
{
private:
char zahl[32]; // Dieses Array speichert bis zu 32 Stellen, pro Stelle 1 char

public:
// Konstruktor: akzeptiert einen int-Wert und wandelt ihn in einzelne Ziffern um
bcd32(unsigned int val = 0)
{
for(int i = 0; i < 32; i++)
{
zahl[i] = val % 10; // Einerziffer ermitteln
val = val / 10; // Eine Ziffer nach Rechts
}
}

bcd32 operator+ (bcd32& rhs)
{
bcd32 result(rhs);
int carry = 0;
for(int i = 0; i < 32; i++)
{
result.zahl[i] += zahl[i] + carry;
// Falls Ergebnis >= 10, dann "Rest hin, 1 im Sinn"
carry = result.zahl[i] > 9 ? 1 : 0; // geändert, da einfacher
result.zahl[i] = result.zahl[i] % 10;
}
return result;
}

friend ostream& operator<< (ostream& os, bcd32 val)
{
bool leadzero = false;
int j = 0;
char buffer[33];
for(int i = 31; i >= 0; i--)
{
if(val.zahl[i] > 0) leadzero = true;
if(leadzero || (i == 0)) // führende Nullen nicht ausgeben, außer es ist die letzte Ziffer
{
buffer[j++] = val.zahl[i] | 0x30; // in ASCII-Zeichen umwandeln
}
}
buffer[j] = '\0'; // String abschließen
os << buffer; // und ausgeben
return os;
}
};


int main() {
bcd32 a = 1, b = 1, c;
for(int i = 0; i < 200; i++)
{
c = a;
a = b;
b = b + c;
cout << b << endl;
}
int d;
cin >> d;
return 0;
}

Xmas
2003-03-31, 18:55:07
Originally posted by Unregistered
Also wenn ich richtig verstanden habe , ist das der Konstruktor der Klasse uint256 und als Parameter erwartet einen unsigned int.Dieser übergebene wert wird in dem Array gespeichert. Val kann ich doch für den Wert von F1 und F2 benutzen oder ?

Das ist der Konstruktor, er akzeptiert einen int-Wert zum Initialisieren, oder 0 als Standardwert.

Du kannst Variablen dieses Typs auf folgende Arten initialisieren:

uint256 extralangezahl(666);
uint256 nochnezahl = 93;


Wieso ist für den Zahl die Zahl 32 übergeben? Ist das für die Anzahl der Bits ?

32 ist die Größe des char-Arrays. Pro char wird eine Ziffer gespeichert.

Wieso wird hier Modolo 10 gerechnet und val dann durch 10 geteilt?

Hier noch mal die Frage warum durch bzw Modolo 10 gerechnet wird

Weil ich in dieser Klasse dezimalziffernweise rechne. Mit Division durch 10 schneide ich eine Ziffer ab und mit Modulo 10 bekomme ich nur die letzte Ziffer.


Die Friendfunktion tut es nicht , der Compilier sagt , das friend funktion Klassen oder Funktion sein müsssen. Benutzt du hier die Friend Funktion damit du auf die geschützten Bereiche einer Klasse zugreifen kannst oder warum?
Die Funktion ist friend, damit sie auf die private Member zugreifen kann. Der Compilerfehler kommt vielleicht davon, dass <iostream> nicht eingebunden ist und somit ostream noch nicht deklariert.


[/size]unsigned int o=3222
Wenn ich z.B uint256::uint256(o) eingebe ist das schon eine 256 Bit Zahl ? Kann ich den ofstream der zurückgeliefert wird , auch mit Memo Feldern benutzen?
Sory für die vielen Fragen und großes thx für die Mühe die du dir gemacht hast. [/SIZE]
Der ostream, der zurückgeliefert wird, ist lediglich der ostream, der auf der linken Seite des << Operators steht. Nur deswegen kannst du << Operatoren verketten.

Unregistered
2003-03-31, 20:29:22
thx , das Prog funzt jetzt.Einfacherhalber hab ich aus deiner operator << Methode eine Methode gemacht , die einen AnsiString zurückliefert.
SO hier dein bzw mein gesamter Quelltext

_fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{

}
//---------------------------------------------------------------------------
bcd32::bcd32(unsigned int val )
{
for(int i = 0; i < 128; i++)
{
zahl[i] = val % 10; // Einerziffer ermitteln
val = val / 10; // Eine Ziffer nach Rechts
}
}

bcd32 bcd32::operator+ (bcd32& rhs)
{
bcd32 result(rhs);
int carry = 0;
for(int i = 0; i < 128; i++)
{
result.zahl[i] += zahl[i] + carry;
// Falls Ergebnis >= 10, dann "Rest hin, 1 im Sinn"
carry = result.zahl[i] > 9 ? 1 : 0; // geändert, da einfacher
result.zahl[i] = result.zahl[i] % 10;
}
return result;
}


AnsiString ausgabe ( bcd32 val)
{
bool leadzero = false;
int j = 0;
char buffer[129];
for(int i = 127; i >= 0; i--)
{
if(val.zahl[i] > 0) leadzero = true;
if(leadzero || (i == 0)) // führende Nullen nicht ausgeben, außer es ist die letzte Ziffer
{
buffer[j++] = val.zahl[i] | 0x30; // in ASCII-Zeichen umwandeln
}
}
buffer[j] = '\0'; // String abschließen
AnsiString alt=buffer;
// os << buffer; // und ausgeben
return alt;
}

void TForm1::berechne()
{

double zeit,zeit2;
//_int64 f1,f2;
//unsigned __int64 f1,f2,ergneu;
unsigned long a1,a2;

int fl;



AnsiString aus;
int bis;
bcd32 f1 , f2 = 1, ergneu;
if (txtbis->Text!=""&&txtf1->Text!=""&&txtf2->Text!="")
{
a1=StrToInt(txtf1->Text);
a2=StrToInt(txtf2->Text);
f1=a1;
f2=a2;
bis=StrToInt(txtbis->Text);
zeit=GetTickCount();
memaus->Lines->Add("F1="+AnsiString(a1));
memaus->Lines->Add("F2="+AnsiString(a2));

for (int i=2;i<bis;i++)
{
ergneu=f1+f2;
aus="F"+AnsiString(i+1);
AnsiString akt;



memaus->Lines->Add(aus+"="+ausgabe(ergneu));
f2=f1;
f1=ergneu;
zeit2=GetTickCount();

}
int d;
cin >> d;
zeit2=zeit2-zeit;
zeit2=zeit2/1000;
memaus->Lines->Add("Gebrauchte Zeit:" +AnsiString(zeit2));

}
else
{

fl=Application->MessageBoxA("Sie haben nicht alles ausgefüllt!Wollen Sie das Programm beenden?","Ausnahmefehler",MB_YESNO);
}
}
if (fl==6)
{

delete btnstart;
delete lblanzahl;
delete lblf1;
delete lblf2;
delete memaus;
delete txtbis;
delete txtf1;
delete txtf2;
Form1->Close();
}

}






//---------------------------------------------------------------------------





void __fastcall TForm1::btnstartClick(TObject *Sender)
{
berechne();
}