C++ Berechnen der größt möglichen Werte eines Datentyps

Diskutiere C++ Berechnen der größt möglichen Werte eines Datentyps im Developer Network Forum im Bereich Hardware & Software Forum; Hallo ihr lieben, wollte mal nachfragen, die man in C++ den größtmöglichen Wert einer Variable (also abhängig vom Datentyp) einfach erzeugen...
  • C++ Berechnen der größt möglichen Werte eines Datentyps Beitrag #1
T

TrµMAn

Bekanntes Mitglied
Dabei seit
23.10.2006
Beiträge
4.882
Reaktionspunkte
2
Ort
Wuppertal
Hallo ihr lieben,

wollte mal nachfragen, die man in C++ den größtmöglichen Wert einer Variable (also abhängig vom Datentyp) einfach erzeugen kann. (nicht errechnen!)

Also eine Möglichkeit (die wegen hoher Rechenleistung und zeitaufwand nicht in Frage kommt) wäre ja, die Variable solange zu erhöhen, bis sie Negativ wird und dann wieder einen davon abziehen (es geht übrigens um Short und Long, jeweils einmal mit und ohne Vorzeichen) Außerdem darf die Bit_anzahl_ nicht berücksichtigt werden.

Meine Überlegung war nun folgende:

Code:
include <iostream>

using namespace std;

void Main()
{
	short ssh = 0;
	cout << "groesster Shortint mit VZ: " << ~ssh << "\n";
	unsigned short ush = 0;
	cout << "groesster Shortint ohne VZ: " << ~ush << "\n";
	long sl = 0;
	cout << "groesster Longint mit VZ: " << ~sl << "\n";
	unsigned long ul = 0;
	cout << "groesster Longint ohne VZ: " << ~ul << "\n";
}

also einfach die Bitweise negation der 0, dies funktioniert leider nichtmal bei 2 Variablen ...

das Ergebniss sieht dann so aus:
groesster Shortint mit VZ: -1
groesster Shortint ohne VZ: -1
groesster Longint mit VZ: -1
groesster Longint ohne VZ: 4294967295

mal kurz mit dem Windows7 Taschenrechner rumprobiert um bei 4 Byte auf das richtige Ergebniss für den Longint zu kommen, passt

Allerdings müsste dies beim Shortint ohne VZ doch genau so klappen?

bei den mit VZ habe ich mir schon etwas überlegt, da das erste bit ja angeben sollte, welches vorzeichen die Variable hat, müsste ich doch nur eine Bit-weise verschiebung nach rechts machen, leider auch kein Erfolg...

so nun seid ihr gefragt: Wo liegt mein Fehler?

btw: ich benutze Microsoft Visual Studio 2005 Professional Edition
 
  • C++ Berechnen der größt möglichen Werte eines Datentyps Beitrag #2
Max11.111

Max11.111

Bekanntes Mitglied
Dabei seit
12.06.2008
Beiträge
2.416
Reaktionspunkte
0
Servus Trµman!

Hallo ihr lieben,
wollte mal nachfragen, die man in C++ den größtmöglichen Wert einer Variable (also abhängig vom Datentyp) einfach erzeugen kann. (nicht errechnen!)
Du musst du Werte nicht extra erzeugen. Die kannst du ganz einfach abrufen/auslesen, siehe: http://www.cplusplus.com/reference/clibrary/climits/
Oder gibt es einen Grund sie speziell zu "erzeugen"?

Also eine Möglichkeit (die wegen hoher Rechenleistung und zeitaufwand nicht in Frage kommt) wäre ja, die Variable solange zu erhöhen, bis sie Negativ wird und dann wieder einen davon abziehen (es geht übrigens um Short und Long, jeweils einmal mit und ohne Vorzeichen)

So lange wie du tust dauert das nicht. Welchen Rechner hast du, wenn man fragen darf?;);)
PHP:
#include <iostream>
#include <limits.h>

int main(void)
{
	int i=0;
	int j;
	for(;;)
	{
		j=i;
		i++;		
		if(i<j)
		{
			std::cout << "Max int (counted) is: " << j;
			std::cout << std::endl;
			std::cout << "Max int is (limits.h): " << INT_MAX;
			break;
		}
	}
	return 0; //Hier Breakpoint setzen...
}

Gruß, Max.
 
  • C++ Berechnen der größt möglichen Werte eines Datentyps Beitrag #3
T

TrµMAn

Bekanntes Mitglied
Dabei seit
23.10.2006
Beiträge
4.882
Reaktionspunkte
2
Ort
Wuppertal
das ganze soll ohne eine zusätzliche Bibliothek gelöst werden und es soll auf einem recht alten schulrechner laufen!

außerdem müsste das ganze ja 4 mal hintereinander berechnet werden ...

und da haben wir auch den Grund, warum ich die erzeugen möchte ^^ ich hab ne liste von Aufgaben von unserem Lehrer im Internet und wollte schonmal etwas vorarbeiten, es sind auch jeweils erklärungen dabei (also das ist noch recht weit am anfang, erklärung zu Datentypen und Operatoren (deswegen komm ich auf den bitweise nach rechts operator ^^))
 
  • C++ Berechnen der größt möglichen Werte eines Datentyps Beitrag #4
Max11.111

Max11.111

Bekanntes Mitglied
Dabei seit
12.06.2008
Beiträge
2.416
Reaktionspunkte
0
Aber die Werte sind doch Fix! Auch in Limits.h stehen die einfach rein geschrieben:


Edit: Oder ist das eine Schulische Aufgabenstellung?:idee:
 
  • C++ Berechnen der größt möglichen Werte eines Datentyps Beitrag #5
T

TrµMAn

Bekanntes Mitglied
Dabei seit
23.10.2006
Beiträge
4.882
Reaktionspunkte
2
Ort
Wuppertal
Edit: Oder ist das eine Schulische Aufgabenstellung?:idee:

steht doch oben: nicht schulisch, aber unser lehrer hat ne art Sammlung von alten Aufgaben zu bestimmten themen (in dem Fall ging es lt. ihm um Operatoren). Deswegen glaube ich auch, dass man das mit bitweise operatoren machen könnte ...

Wenn die irgendwo nur fix eingetragen sind, hab ich ja keinen wirklichen Lerneffekt ^^ einfache Ausgaben gabs schon im ersten Teil ^^
 
  • C++ Berechnen der größt möglichen Werte eines Datentyps Beitrag #6
fox99

fox99

Bekanntes Mitglied
Dabei seit
27.11.1999
Beiträge
3.948
Reaktionspunkte
27
Ort
Omicron Persei 8
könnte das funktionieren? min und max enthalten am ende den kleinsten und größten möglichen wert.
Code:
tmp=1;

max=tmp;
while (tmp >0){
   max += tmp;
   tmp *= 2;
}
min = tmp;
 
  • C++ Berechnen der größt möglichen Werte eines Datentyps Beitrag #7
cmddegi

cmddegi

Bekanntes Mitglied
Dabei seit
12.07.2001
Beiträge
4.740
Reaktionspunkte
0
Ort
Austria
Eigentlich sollte dein Ansatz soweit schon stimmen. Ich vermute aber mal, dass da ein implizieter Cast vor dem Einfügen in den Stream dein Ergebnis zunichte macht.
Einfacher berechnen lässt sich sowas aber mit einem Bitshift. Der höchste Wert für einen unsigned char ist z.B. 255, das ist 2^8-1 (2^8 wäre der Stellenwert des 9ten bits; darum eins weniger). Bei zwei Byte dann entsprechend 2^16-1 = 65535, usw. Den Wert für 2^8 z.B. kriegt man ohne mathematische Operationen mit dem Bitshift 1<<8; also eine 1 um 8 Stellen nach Links geschoben. Für signed-Datentypen ist die obere Grenze, wie du richtig vermutest, ein Bit weniger. Die negative Grenze ist um eins größer, wegen dem 2er-Komplement. Ein 2-Byte-int geht z.B. von -32768 bis 32767.
Obwohl diese Berechnungen bei Ganzzahlen relativ einfach sind, gibt es ein recht großes Problem: Bei C sind die Breiten der Datentypen nicht exakt definiert. Ein normaler int entspricht für gewöhnlich der Maschinenregisterbreite, also auf einem 32bit-System 4 Byte; während er auf einem 16bit-Mikrocontroller nur 2 Byte groß ist. Long ist so definiert, dass er mindestens gleich breit oder breiter als int ist, und short gleich oder weniger breit, wenn ich mich da recht entsinne. Entgegen diesem Standard ist der int bei meinen 8bit-Controllern aber auch 16bit, wenn ich mich recht entsinne. Aus diesem Grund verwenden portable Anwendungen oft eigene Datentypen, die so definiert sind, dass sie immer gleich breit sind; die heißen dann z.B. uint16, oder so.

Nochmal spaßiger wird das bei Gleitkommazahlen; wobei man da glücklicherweise selten an die Grenzen stößt. Die selbe Problematik haben aber zum Glück auch schon andere Programmierer erkannt und bei den meisten neueren Sprachen fixe Konstanten mit den Grenzen der Datentypen eingebaut.
 
  • C++ Berechnen der größt möglichen Werte eines Datentyps Beitrag #8
U

UnimatrixZero

Bekanntes Mitglied
Dabei seit
27.06.2001
Beiträge
645
Reaktionspunkte
0
Nur als Ergänzung:

Deshalb sind in der stdint.h auch Typen der Form "intN_t" definiert, wobei N die Bitbreite angibt. Je nach Compiler/System werden diese Typen so definiert, daß sie der angegebenen Bitbreite entsprechen. Ein uint16_t wäre dann also ein 16 Bit Integer ohne Vorzeichen. Weiteres dazu ist in der Norm ISO/IEC 9899 zu finden.

Man sollte sich unbedingt mal Gedanken darüber machen, was beim casten von verschiedenen Typen genau passiert. Da ist durchaus der eine oder andere AHA-Effekt dabei ,-)
Weitere Infos: https://www.securecoding.cert.org/confluence/display/seccode/04.+Integers+(INT)

Gleitkommzahlen sind ein ganz anderes Kaliber (wenn man genauer hinsieht).
 
  • C++ Berechnen der größt möglichen Werte eines Datentyps Beitrag #9
T

TrµMAn

Bekanntes Mitglied
Dabei seit
23.10.2006
Beiträge
4.882
Reaktionspunkte
2
Ort
Wuppertal
also kann mir denn jemand von euch erklären, wo der Fehler liegt bei dem ~ssh etc?

kann es sein, dass dabei einfach zu viele Bits benutzt werden, als die Variable eigentlich fassen kann und somit die Variable überläuft und deswegen -1 rauskommt?
 
  • C++ Berechnen der größt möglichen Werte eines Datentyps Beitrag #10
U

UnimatrixZero

Bekanntes Mitglied
Dabei seit
27.06.2001
Beiträge
645
Reaktionspunkte
0
Angenommen, short ist 16 Bit breit, dann ist ~0 = 0xFFFF und das ist in der üblichen 2er-Komplement-Darstellung -1. Damit sind die beiden signed-Typen klar. Bleibt noch der unsigned short. Da kommt vermutlich eine implizite Umwandlung zu 32-Bit signed int zum Tragen. 0xFFFF als unsigned short ist 65536 und als signed int 0xFFFFFFFF und das ist -1.
Wenn Du der Ausgabe den invertierten Wert wieder in ein unsigned short castest, dann solltest Du 65536 bekommen.
 
  • C++ Berechnen der größt möglichen Werte eines Datentyps Beitrag #11
T

TrµMAn

Bekanntes Mitglied
Dabei seit
23.10.2006
Beiträge
4.882
Reaktionspunkte
2
Ort
Wuppertal
Wenn Du der Ausgabe den invertierten Wert wieder in ein unsigned short castest, dann solltest Du 65536 bekommen.

werde ich mal ausprobieren, aber wie sieht das denn mit der verschiebung der bits beim signed int aus? also praktisch

ssh = ~ssh
ssh >= ssh

leider hab ich noch nicht so häufig mit den bitweise-operatoren gearbeitet
 
  • C++ Berechnen der größt möglichen Werte eines Datentyps Beitrag #12
T

TrµMAn

Bekanntes Mitglied
Dabei seit
23.10.2006
Beiträge
4.882
Reaktionspunkte
2
Ort
Wuppertal
also ich habe es nun hinbekommen bei dem unsigned short...

es hat hier ausgereicht, dass ich vor der ausgabe geschrieben habe

Code:
ush = ~ush;

bei den signed typen komm ich allerdings auch nicht mit ssh >>= 1; weiter ...
 
  • C++ Berechnen der größt möglichen Werte eines Datentyps Beitrag #13
cmddegi

cmddegi

Bekanntes Mitglied
Dabei seit
12.07.2001
Beiträge
4.740
Reaktionspunkte
0
Ort
Austria
ssh = ~ssh
ssh >= ssh
Dir ist bewusst, dass das eine eine Zuweisung ist, während das andere einen Vergleich darstellt?
Wenn du mit Bitoperationen noch nicht soviel Erfahrung hast, würde ich davon abraten, die verkürzte Schreibweise ala ~= zu verwenden. Verwende am besten Variablen des passenden Datentyps für die Ausgabe und weise denen die berechneten Werte zu.

Ein kleines Beispielprogramm zur Aufhellung der Situation
Code:
#include "stdafx.h"
#include <conio.h>
#include <stdio.h>

// zeigt nBytes an der Adresse p an
// bReverseBytes dreht die Reihenfolge um, damit
// die Zahl auf LittleEndian-Systemen lesbar ist
void printMem(void *p, int nBytes, bool bReverseBytes) {
	unsigned char ucByte;
	int iIndex;

	for(int i=0; i<nBytes; i++) {
		iIndex = bReverseBytes ? (nBytes-1-i) : i;

		ucByte = ((unsigned char*)p)[iIndex];
		printf("0x%02x ", ucByte);
	}
	printf("\n");
}

int main(int argc, char* argv[])
{
	unsigned int imaxpos1, imaxpos2, imaxpos3, imaxpos4;
	signed int imaxpossigned, imaxnegsigned;

	// erstmal die Datentypbreiten ausgeben:
	printf("Datentypbreiten:\nChar: %u\nShort %u\nInt %u\nLong %u\n\n", sizeof(char), sizeof(short), sizeof(int), sizeof(long));

	// das hier funktioniert zwar, ist aber falsch, weil die 1 innerhalb der Klammer ein int ist,
	// und mit einem Shift um 32 Bits aus dem Datentyp rausgeschoben wird; die Rechnung lautet
	// daher dann 0 - 1
	imaxpos1 = (1 << 32) - 1;

	// hier wird der unsigned int im zweiten Fall automatisch als signed interpretiert
	// wie man sieht liefern alle vier das gleiche Ergebnis
	printf("imaxpos1 unsigned: %u signed: %i\n", imaxpos1, imaxpos1);

	// hier der Beweis
	printf("(1 << 32) = %u\n", (unsigned int)(1<<32) );	

	// daher funktioniert auch das
	imaxpos2 = (unsigned int) -1;
	printf("imaxpos2 unsigned: %u signed: %i\n", imaxpos2, imaxpos2);

	// richtigerweise müsste man intern mit einem breiteren Datentyp rechnen
	// 1ul bedeutet, dass die 1 ein unsigned long-wert ist; die Rechnung in der Klammer also
	// mit einem unsigned long gerechnet wird.
	// Problem: long und int sind hier gleich breit, es passiert also das gleiche wie zuvor!
	imaxpos3 = (unsigned int)((1ul << 32) - 1);
	printf("imaxpos3 unsigned: %u signed: %i\n", imaxpos3, imaxpos3);

	// ... wie man hier sieht:
	unsigned long ltemp = (1l << 32);
	printf("((unsigned long)(1 << 32) = %u\n", ltemp);
	ltemp = ltemp-1;
	imaxpos4 = (unsigned int)ltemp;		
	printf("imaxpos4 unsigned: %u signed: %i\n", imaxpos4, imaxpos4);

	printf("\nSigned Typen:\n");

	// Rechnung mit signed
	imaxpossigned = (signed int)( ((unsigned int)1 << 31) - 1 );
	imaxnegsigned = -(imaxpossigned+1);

	printf("imaxpossigned unsigned: %u signed: %i\n", imaxpossigned, imaxpossigned);
	printf("imaxnegsigned unsigned: %u signed: %i\n", imaxnegsigned, imaxnegsigned);

	// Speicherbereich der Variablen in Hex
	printf("\nSpeicherbereiche:\n");
	printf("imaxpos1:      "); printMem(&imaxpos1, 4, true);
	printf("imaxpossigned: "); printMem(&imaxpossigned, 4, true);
	printf("imaxnegsigned: "); printMem(&imaxnegsigned, 4, true);

	_getch();
	return 0;
}

Für die faulen Leute hier die Ausgabe ;)
Code:
Datentypbreiten:
Char: 1
Short 2
Int 4
Long 4

imaxpos1 unsigned: 4294967295 signed: -1
(1 << 32) = 0
imaxpos2 unsigned: 4294967295 signed: -1
imaxpos3 unsigned: 4294967295 signed: -1
((unsigned long)(1 << 32) = 0
imaxpos4 unsigned: 4294967295 signed: -1

Signed Typen:
imaxpossigned unsigned: 2147483647 signed: 2147483647
imaxnegsigned unsigned: 2147483648 signed: -2147483648

Speicherbereiche:
imaxpos1:      0xff 0xff 0xff 0xff
imaxpossigned: 0x7f 0xff 0xff 0xff
imaxnegsigned: 0x80 0x00 0x00 0x00
 
  • C++ Berechnen der größt möglichen Werte eines Datentyps Beitrag #14
T

TrµMAn

Bekanntes Mitglied
Dabei seit
23.10.2006
Beiträge
4.882
Reaktionspunkte
2
Ort
Wuppertal
Dir ist bewusst, dass das eine eine Zuweisung ist, während das andere einen Vergleich darstellt?

ja, ich "verschlucke" immer mal wieder ein > und mir ist aufgefallen das auf der rechten seite eine 1 stehen müsste oder?

Und nochetwas, du verwendest ja auch die internen Breiten der Typen (mit Sizeof() ) und ich suche noch irgend einen anderen Weg das zu lösen ...

also was ist denn an dem Ansatz falsch, aus 0000, 1111 zu machen und dann alles um 1 Bit nach rechts zu verschieben, damit das erste (fürs Vorzeichen) Bit 0 wird?

Ich möchte das jetzt nicht irgendwie schaffen sondern auch im großen und ganzen, wie im detail verstehen ...
 
  • C++ Berechnen der größt möglichen Werte eines Datentyps Beitrag #15
cmddegi

cmddegi

Bekanntes Mitglied
Dabei seit
12.07.2001
Beiträge
4.740
Reaktionspunkte
0
Ort
Austria
Jepp, die Zahl auf der rechten Seite ist die Anzahl der Bits, um die geshiftet wird.
Dein Ansatz, die 0 zu invertieren, um lauter 1en zu kriegen, und nach rechts zu schieben ist an sich nicht falsch, um das positive Maximum einer signed-Zahl zu bekommen. Wenn du allerdings schon die Berechnung in einem signed durchführst, könnte es sein, dass der Bitshift links keine 0 reinschiebt, sondern eine 1, um das Vorzeichenbit zu bewahren. Da müsste man aber nachlesen; ich hab nur von Assembler sowas im Kopf, dass es das gibt.
Es gibt natürlich eine Menge Methoden, wie man das lösen kann. Meine gezeigte Methode z.B. setzt das nächsthöhere Bit und zieht eins ab. Das ist allerdings nicht besonders elegant und dient eher dem Beispiel hier, um die Problematik zu zeigen. Du kannst aber für die Signed-Typen sicher eine 1 ins Vorderste Bit schieben und diesen Wert invertieren ~(1<<31). Das sollte funktionieren, hab ich jetzt aber nicht getestet.

Die sizeof()-Methode verwende ich in meinem Programm übrigens nirgends zur Berechnung; die dient nur am Anfang zur Anzeige. Und um zu verdeutlichen, dass auf einem 32bit-System int und long gleich breit sind.
 
  • C++ Berechnen der größt möglichen Werte eines Datentyps Beitrag #16
T

TrµMAn

Bekanntes Mitglied
Dabei seit
23.10.2006
Beiträge
4.882
Reaktionspunkte
2
Ort
Wuppertal
Die sizeof()-Methode verwende ich in meinem Programm übrigens nirgends zur Berechnung; die dient nur am Anfang zur Anzeige. Und um zu verdeutlichen, dass auf einem 32bit-System int und long gleich breit sind.

aber du gehst im nachhinein einfach von einer bestimmten Anzahl an bits aus ;)

genau wie hier mit dem " ~(1 << 31) "
 
  • C++ Berechnen der größt möglichen Werte eines Datentyps Beitrag #17
cmddegi

cmddegi

Bekanntes Mitglied
Dabei seit
12.07.2001
Beiträge
4.740
Reaktionspunkte
0
Ort
Austria
Natürlich; alles andere wäre ja ziemlich sinnfrei. Ich programmiere ja nicht mit einer Sprache, bei der ich nicht weiß, wie breit die Datentypen sind. Und falls ich es wirklich nicht weiß, ist die sizeof-Funktion genau dafür da.
Wenn du das aber unbedingt durch ausprobieren rausfinden willst, brauchst du nur bei den jeweiligen unsigned typen die 0 invertieren und hast deinen Maximalwert. Die jeweiligen Signed-Typen sind immer gleich breit. Du könntest natürlich auch in einer Schleife eine 1 von rechts nach links schieben und mitzählen, bis sie verschwindet.

Wie gesagt, zumindest ein paar deiner Probleme kommen ziemlich sicher durch implizite Typumwandlungen; z.B. siehst du ja, dass bei meiner printf-Funktion was anderes rauskommt, je nach Format. Da du bei den Stream-Routinen keinen Typ angibst, macht das Ding natürlich irgendwas damit. Was genau, steht sicher in irgendeiner Doku. :)

Und wie unimatrixzero schon angemerkt hat ist es sehr nützlich, sich mit sowas genau auseinanderzusetzen. C macht einige Dinge, die man nicht erwarten würde; z.B. ist das Ergebnis einer Rechnung mit einem signed und einem unsigned ein un(!)signed. Unschwer zu erkennen, dass das sehr schnell zu abenteuerlichen Dingen führen kann. Speziell muss man wissen, dass solche Umwandlungen ja innerhalb von Ausdrücken vorkommen, und dass auch Konstanten bestimmte Typen haben.
 
Zuletzt bearbeitet:
  • C++ Berechnen der größt möglichen Werte eines Datentyps Beitrag #18
U

UnimatrixZero

Bekanntes Mitglied
Dabei seit
27.06.2001
Beiträge
645
Reaktionspunkte
0
Dass das mit dem unsigned short nicht ging liegt an der Integer promotion. C/C++ rechnet vorzugsweise mit int. Wenn Du also ~ush schreibst, dann macht C ush zu einem int und wendet dann ~ darauf an. Dasselbe passiert beispielsweise beim unären +.
Probier mal folgenden code:

Code:
char x = 'a';
cout << x << endl;
cout << +x << endl;
 
  • C++ Berechnen der größt möglichen Werte eines Datentyps Beitrag #20
T

TrµMAn

Bekanntes Mitglied
Dabei seit
23.10.2006
Beiträge
4.882
Reaktionspunkte
2
Ort
Wuppertal
So lange wie du tust dauert das nicht. Welchen Rechner hast du, wenn man fragen darf?;);)
PHP:
#include <iostream>
#include <limits.h>

int main(void)
{
	int i=0;
	int j;
	for(;;)
	{
		j=i;
		i++;		
		if(i<j)
		{
			std::cout << "Max int (counted) is: " << j;
			std::cout << std::endl;
			std::cout << "Max int is (limits.h): " << INT_MAX;
			break;
		}
	}
	return 0; //Hier Breakpoint setzen...
}

Gruß, Max.

ich habs mal auf meinem Arbeitsrechner ausprobiert, mit dem Signed Long Int ... und ich sage dir, DAS DAUERT ... Dualcore prozi mit 2,1 GHz pro Kern und 2 GB arbeitsspeicher, ich glaube, da träumt unsere schule von ^^

folgendes läuft da deutlich schneller:
PHP:
long sl = 0;	
while ((sl+1) >= 0)
{
	sl <<= 1;
	sl++;
}
std::cout << "Größter long Int: " << sl << "\n";
 
Zuletzt bearbeitet:
Thema:

C++ Berechnen der größt möglichen Werte eines Datentyps

ANGEBOTE & SPONSOREN

https://www.mofapower.de/

Statistik des Forums

Themen
213.180
Beiträge
1.579.174
Mitglieder
55.879
Neuestes Mitglied
stonetreck
Oben