Permalänk

c++ hjälp datatypes

Hejsan allihopa

Jag är nybörjare på c++ och har en liten fråga.
Jag undrar hur man skall göra om man till exempel multiplicerar två maximalt stora double värden som för mig verkar vara den största datatypen?

För det finns ingen datatype som kan lagra svaret så vitt jag har hittat.

Permalänk
Medlem

Varför behöver du tal större än 1.7*10^308 ?

Visa signatur

Intel Core i7-3770K | NVIDIA Geforce GTX 980 | 16 GB DDR3 | DELL P2415Q | DELL U2711 | DELL U2410

Permalänk

Jag bara väntade på den frågan. Det är så typiskt ! Frågan är inte varför utan om det är möjligt och i såfall hur! Har programmering i c++ gränser ?!
Förresten hur kom du fram till 1.7*10^308 ? vad jag vet så är det 15 siffrors noggrannhet med double men ,, samtidigt så står det 1.7e^308 ?!
här är länken jag kollar på Variables. Data Types. .

Personligen för jag bara 20 siffrors noggrannhet jag använder Anjuta i linux Debian lenny 64-bit och det är långt ifrån 1.7*10^308 för det skulle vara med 308 siffrors noggrannhet om jag inte har fel.

Permalänk
Medlem
Skrivet av Mysticsam:

Hejsan allihopa

Jag är nybörjare på c++ och har en liten fråga.
Jag undrar hur man skall göra om man till exempel multiplicerar två maximalt stora double värden som för mig verkar vara den största datatypen?

För det finns ingen datatype som kan lagra svaret så vitt jag har hittat.

Som MagnusL antydde kan man fråga sig om du verkligen behöver större tal (eller större precision). Speciellt då du är nybörjare. Men skulle det behövas finns i allmänhet två möjligheter:

  • long double - inbyggd datatyp, som är större eller lika med double. Internet antyder att
    sizeof(long double) == sizeof(double) på 32-bitars Visual Studio, vilket gör det till en mindre portabel lösning.

  • Bignum-bibliotek. Exempel är GMP (C/C++) och NTL (C++). Dessa tillåter godtyckligt stora tal med godtycklig precision, och finns till flertalet plattformar. Detta är därför mer portabelt, och kan vara bättre hursomhelst i många fall (man kanske inte vet i förväg exakt vilken storlek/precision man behöver).

Visa signatur

Vill du ha svar? Citera mig gärna.

Permalänk
Medlem

med

#include <iostream> int main(int argc, char* argv[]) { printf("%d, %d, %d, %d",sizeof(int), sizeof (long int),sizeof(double), sizeof(long double)); getchar(); return 0; }

får jag 4,4,8,8 hur jag än kompilerar, vs08, vista x64...

Permalänk
Avstängd

Det går ju att deklarera datatyper själv så teoretiskt ska man kunna göra hur stora datatyper som helst. Angående long double så är det inte en bra ide för implementationen av det på olika plattformar är väldigt mystisk.

Du behöver inte deklarera typerna själv utan kan använda något bibliotek. Jag har använt GMP för detta flera gånger.

Men om du ska göra högprecisionskalkyl så är ett tipps att använda dig av något som är gjort för det. I fall vi med precision menar stora flyttal och ge en bra approximation så ät matlab eller mathematica superbra. I fall vi menar att körningen ska vara effektiv och snabb så är fortran ett bra val.

Permalänk

Hur deklarerar man datatyper själv ?

Permalänk
Avstängd
Skrivet av Mysticsam:

Hur deklarerar man datatyper själv ?

Det finns flera sätt, men då du vill använda c++ så är väll att deklarera en klass en bra idé.

Permalänk

Hur kommer det att hjälpa mig jag saknar fortfarande en datatype för att lagra något större än double?
Edit: än en long double tydligen.

Skrivet av Dalton Sleeper:

med

#include <iostream> int main(int argc, char* argv[]) { printf("%d, %d, %d, %d",sizeof(int), sizeof (long int),sizeof(double), sizeof(long double)); getchar(); return 0; }

får jag 4,4,8,8 hur jag än kompilerar, vs08, vista x64...

Jag får 4 8 8 16 vilket skulle betyda att min long double är 16 byte eller 128 bitar, den det konstiga är att jag bara får 20 siffrors noggrannhet , 128 bitar borde göra att jag kan behandla mycket större tal än 20 siffrors noggrannhet.

Glömde att nämna detta innan jag använder bara iostream headern i min cpp fil , kan det vara felet , saknar jag en header för att använda alla 128 bitarna i long double?

Permalänk
Medlem
Skrivet av Mysticsam:

Hur kommer det att hjälpa mig jag saknar fortfarande en datatype för att lagra något större än double?

Det han tänker på är nog grejer som GMP och NTL. Han nämnde att han själv använt GMP. Bibliotek av denna typ går att implementera själv (i NTL är det gjort som klasser), men du vill nog använda ett existerande bibliotek.

Visa signatur

Vill du ha svar? Citera mig gärna.

Permalänk

Jag gjorde ett litet expriment precis.

// declaring variables: long int b, a; long double c; // process: a = 9223372036854775807; b = 1; c = a * b; cout << c << endl ;

Om nu en long int är 8 byte så blir det 8*8= 64 bitar . För att få ut det största talet en 64 bitar datatye kan hålla så tog jag 2^64 = 18446744073709551616 . I och med att det är hälften + och hälften - så delade jag med 2 och fick 9223372036854775808. Så jag testade först med det talet i "a" och fick svaret -9.22337e+18 vilket inte stämmer så jag minskade talen med 1 och då fick jag talet att bli positivt. Sen ändrade jag värdet på "b" till 2 och då fick jag svaret 0 . jag tycker att detta kan väll inte stämma för en long double ska kunna rymma 128 bitar med information? är det någon som kan hjälpa mig att förklara detta fenomen?

Permalänk
Medlem
Skrivet av Mysticsam:

Personligen för jag bara 20 siffrors noggrannhet jag använder Anjuta i linux Debian lenny 64-bit och det är långt ifrån 1.7*10^308 för det skulle vara med 308 siffrors noggrannhet om jag inte har fel.

Det är skillnad på hur stora tal som kan lagras i en double och med vilken precision de kan lagras. 1.7*10^308 har ju 17 och 307 nollor efter, så det är bara 2 siffrors noggrannhet. Benämningen på float och double är ju flyttal, vilket syftar på att decimalpunkten kan "flyta" och placeras vart som helst mellan de signifikanta siffrorna. Så du kan representera väldigt små och väldigt stora tal med flyttal, men endast med en viss precision (en dubbel har 53 bitars precision, ~16 signifikanta siffror i bas 10). Det som händer om du på något sätt skapar ett tal större än ungefär 1.8*10^308 som är max för en double så får du ett speciellt värde som signalerar oändlighet.

Som du redan märkt så implementerar vissa kompilatorer long double som en 128-bitars typ, vilket ger ungefär 34 signifikanta siffror. Att du inte får så bra precision kan möjligtvis bero på att iostream inte skriver ut så många decimaler. Du kan testa att sätta precisionen högre med setprecision. Men long double finns som sagt bara till vissa kompilatorer, så om du vill skriva portabel kod så bör du nog undvika det.

Det går som sagt att skriva sin egen flyttals-implementation där du helt enkelt får uttföra alla operationer själv på bitnivå, men enklast är nog att bara använda något färdigt bibliotek.

Skrivet av Mysticsam:

Om nu en long int är 8 byte så blir det 8*8= 64 bitar . För att få ut det största talet en 64 bitar datatye kan hålla så tog jag 2^64 = 18446744073709551616 .

Det största talet en 64-bitars variabel kan hålla är (2^64)-1. Tänk dig t.ex. att du istället har 2 bitar. Två bitar kan representera 00 = 0, 01 = 1, 10 = 2 och 11 = 3. 2^2 = 4 är ju 100, dvs. ett mer än två bitar kan hålla.

Permalänk
Medlem
Skrivet av Mysticsam:

Jag gjorde ett litet expriment precis.

long int b, a; long double c; ... c = a * b;

Aritmetiken sker mellan två long int. Cast:a ena till long double så bör du få ett annat resultat.

Visa signatur

Vill du ha svar? Citera mig gärna.

Permalänk

Japp det stämmer jag får 8589934590 vilket är mycket mindre än 2 multiplicerat med 9223372036854775807.

HAHA jag gjorde lite fel jag flyttade över b och inte a hehe ,, nu blev det rätt tack för hjälpen .

För er som vill vet svaret så blev det 18446744073709551614.

Permalänk
Medlem

Här är ett litet program jag knåpade ihop:

#include <iomanip> #include <iostream> #include <limits> int main() { double d = 0.123456789123456789123456789123456789123456789; long double ld = 0.123456789123456789123456789123456789123456789L; std::cout << (std::numeric_limits<double>::digits10) << std::endl; std::cout << (std::numeric_limits<long double>::digits10) << std::endl; std::cout << std::setprecision(50); std::cout << d << std::endl; std::cout << ld << std::endl; } Utskrift: 15 18 0.12345678912345678379658409085095627233386039733887 0.12345678912345678912272726318599680439547228161246

Som du kan se så kan en double bara representera 15 signifikanta siffror enligt numeric_limits, medan en long double har 18. Så det verkar som att även om long double har 128 bitar så används bara 64 bitar till precision (till skillnad mot double som har 53).

Permalänk

Jag tror att jag är utan efter stora heltals data typer dock tror jag att jag är rätt nöjd med antalet siffror jag får av. jag testade en annan datatype nämligen "long long" det var så jag fick fram alla siffrorna testade senare med long double då fick jag svaret 1.84467e19.

Sen är det som så att jag är en person som så fort jag ser en begränsning så vill jag komma förbi den, jag vill inte ha något som begränsar även om det i praktiken inte finns någon större anledning till att gå över gränsen . Jag hoppas att ni förstår vad jag menar.

Permalänk
Medlem
Skrivet av Mysticsam:

Jag tror att jag är utan efter stora heltals data typer dock tror jag att jag är rätt nöjd med antalet siffror jag får av. jag testade en annan datatype nämligen "long long" det var så jag fick fram alla siffrorna testade senare med long double då fick jag svaret 1.84467e19.

Att du får ut 1.84467e19 beror ju på att iostream endast skriver ut 6 decimaler som standard och därför förkortar talet. 1.84467e19 betyder ju 1.84467*10^19 om du inte visste det redan. Om du använder setprecision så kan du ändra hur många decimaler som ska skrivas ut

Notera förresten att du bör använda L efter konstanter när du tilldelar long-variabler, som i mitt exempel ovan. Annars så tolkas konstanten som en int eller double, och du förlorar då precision direkt vid tilldelningen.

Permalänk
Medlem
Skrivet av Mysticsam:

Sen är det som så att jag är en person som så fort jag ser en begränsning så vill jag komma förbi den, jag vill inte ha något som begränsar även om det i praktiken inte finns någon större anledning till att gå över gränsen . Jag hoppas att ni förstår vad jag menar.

Det är bra att vara intresserad av hur man kommer runt begränsningar. Har du inget direkt behov av det borde du dock troligtvis inte utnyttja dessa lösningar. De leder till lägre prestanda, till förmån för... ja, det finns egentligen ingen fördel, om nu inte behovet finns. Behovet finns om du skriver ett program där användaren ska kunna utföra godtyckliga beräkningar, men det är mindre sannolikt att det finns ett behov om du bara ska lagra hur mycket pengar en spelare har i ett spel.

Jag var inte säker på vad du menade med att du "vill komma förbi begränsningen".

Visa signatur

Vill du ha svar? Citera mig gärna.

Permalänk

jo e visste jag betydde 10. Jag kom precis på ,, finns det inte en header fil som heter "math.h" kan inte den vara något att använda i såfall?

Jag får inte rätt på setprecision var skall jag skriva in det och måste limits headern vara med för att den skall funka?

Permalänk

Jag skriver i en annan tråd om ett spel "Capitalism plus" och hur jag upplever dom många buggar som finns i det, Jag har spelat detta spel väldigt länge som jag har lyckats komma upp i till vissa begänsningar som spelet har som till exempel mängden pengar man kan ha innan det flippar ut och presenterar ett konstigt värde, antalet andelar som man har delar ut och det har blivit knasigt plus en hel del annat. Då har jag räknat bort alla buggar som gör att man blir utkastad ifrån spelet. Så jag har funderingar kring att utveckla ett nytt Capitalism plus. Jag tycker att Capitalism 2 är en dålig efterföljare. Så det är väl därför ajg har ställt dessa frågor för att skapa utrymme för användaren att använda programmet utan att riskera att komma på en begränsning i spelet.

För mer info om capitalism plus :

Capitalism (video game) - Wikipedia, the free encyclopedia
Capitalism Plus

bilder från spelet:

http://www.juegomania.org/Capitalism%2BPlus/foto/pc/0/69/69_t...
http://www.juegomania.org/Capitalism%2BPlus/foto/pc/0/69/69.j...
http://gamedemo.networkextreme.com/games/strategy/Capitalism_...
http://media.gamerevolution.com/images/games/pc/capitalism_pl...

Permalänk
Medlem
Skrivet av Mysticsam:

Jag kom precis på ,, finns det inte en header fil som heter "math.h" kan inte den vara något att använda i såfall?

math.h är för C, i C++ så bör du hellre använda cmath som definierar samma funktioner fast i std-namespacet. cmath definierar en del vanliga matte-funktioner som t.ex. sin och cos. Jag vet inte riktigt vad du tänkt använda dem till, men de har inget med precision att göra i alla fall.

Skrivet av Mysticsam:

Jag får inte rätt på setprecision var skall jag skriva in det och måste limits headern vara med för att den skall funka?

setprecision är definierad i iomanip-headern, och används som i mitt exempel ovan. setprecision är en manipulator för iostream-strömmar, så om du skickar en setprecision till t.ex. cout så kommer cout därefter att använda den angivna precisionen.

Angående dina planer på att skapa ett spel så känns det inte som att du behöver oroa dig så mycket. Att spel ibland får problem när t.ex. poängen blir för hög är bara dålig programmering där programmeraren inte förutsett att en spelare kan få så hög poäng att det inte längre går att lagra i poäng-variabeln. Lösningen på detta är helt enkelt att antingen sätta en begränsning på t.ex. hur mycket poäng spelaren kan få och sedan kontrollera detta, alternativt att lagra poängen i en datastruktur som kan ha godtycklig precision (men hur skulle du visa en sån siffra för spelaren?). Om du verkligen behöver lagra tal som är större än de ca. 2 miljarder som får plats i ett 32-bitars heltal så kanske det är dags att börja fundera på om det inte är speldesignen som är problemet, och inte begränsningar i koden.

Permalänk

oki Så då har jag ingen användning av den header filen.

Permalänk
Avstängd

För att förklara hur det faktiskt ligger till.

Det du söker är inte en del av C++ eller dess standardbibliotek (och det verkar vara därför du söker det). Du kan använda något annat bibliotek som någon annan redan har gjort vilket har nänts högre upp. Det dessa gör är att de bygger ut språket med nya funktioner och klasser som du kan använda precis som du använder de inbyggda.

I fall du vill uppfinna hjulet igen går det utmärkt att göra samma jobb som de redan har gjort och skriva ett eget BIGNUM-bibliotek. Det lättaste sättet att få ett hum om hur du gör det är att kolla på koden till GMP. Men i teorin kan du göra hur stora tal du vill så länge processorn klarar av att hantera dem och det är enormt stora tal. Tänk dock på att det ALLTID kommer att bli decimalfel p.g.a. att talen representeraras med basen 2 (binärt) i datorn.

Det binära talsystenet är egentligen inte speciellt lämpligt att konvertera till bas 10 så därför kommer det alltid att bli avrundningsfel.