2011-01-25 7 views
16

Sto cercando una classe C++ che possa fare aritmetica decimale in virgola mobile. Guardando attraverso http://speleotrove.com/decimal/ ci sono collegamenti a tutti i tipi di classi che le persone hanno scritto e non mantenuto. Scavando attraverso la roba decNumber ++ mi ha portato ad alcune e-mail che mostrano che GCC alla fine supporterà questa funzionalità. (Formalmente conosciuto come ISO/IEC TR 24733)Esiste un C++ equivalente a BigDecimal di Java?

Sto cercando qualcosa che possa essere usato come rimpiazzo sostitutivo per float o double, qualcosa che altre persone usano nei propri progetti. Speriamo che l'open source.

Grazie!

EDIT: Vorrei sottolineare che sto cercando di utilizzare questo per rappresentare i prezzi. Quindi ho bisogno di decimali ESATTI, non di enormi decimali.

+1

gmplib forse? http://gmplib.org/ – Anycorn

+0

non dovresti usare il doppio o il float per i prezzi ... –

+7

JH Lo so, ecco perché sto cercando qualcosa come BigDecimal. – poindexter

risposta

12

esiste una enorme libreria chiamata GMP (GNU multiple precision library) che supporta questo e ha anche binding C++, anche se ad essere onesti l'interfaccia C++ è un po 'traballante e obsoleto.

Un esempio dalla documentazione, la seguente crea un galleggiante chiamato f con almeno 500 bit di precisione:

mpf_class f(1.5, 500); 
+2

Simile a BigDecimal mpf_class richiede un costruttore di stringhe. La versione di gmpxx fornita con Ubuntu 10.4 utilizza la specializzazione parziale del modello, quindi potrebbe essere un allungamento chiamarla obsoleta. Penso di poter ottenere questo per fare la mia offerta. Congratulazioni, ottieni un cookie, il segno di spunta di Erhm. – poindexter

+1

@poindexter: quello che intendevo con "obsoleto" è principalmente il nome: dai, che tipo di nome di classe è "mpf_class" ?! Avrebbero dovuto chiamarlo 'gmp :: big_float' o qualcosa del genere. –

+0

Penso che sia una dura battaglia con le convenzioni di denominazione GNU. :) La sezione delle librerie – poindexter

1

Probabilmente "MAPM, una biblioteca matematica di precisione arbitraria portatile in C" è quello che stai cercando. Esso comprende anche C++ wrapper:

http://www.tc.umn.edu/~ringx004/mapm-main.html

+0

FAIL: "Notare che la libreria MAPM predefinita NON è thread-safe Le strutture di dati interne MAPM potrebbero essere danneggiate se più funzioni MAPM sono attive contemporaneamente L'utente dovrebbe garantire che solo un thread sta eseguendo le funzioni MAPM. raggiunto da una chiamata al sistema operativo per ottenere un "semaforo" o una "sezione di codice critica" in modo che il sistema operativo garantisca che solo un thread MAPM sia attivo alla volta. " – poindexter

4

Se avete bisogno di fare operazioni con valori decimali enormi vorrei suggerire di utilizzare http://gmplib.org/ libreria . L'ho usato molto con C e C++.

8

Fai la tua scelta. Ci sono un sacco di loro là fuori. Ad esempio, è possibile consultare lo list on Wikipedia.

+1

è stata rimossa. – Alex

3

Usa GMP e conserva tutto come centesimi. Se sai che non passerai 2^32 cents (42,949673 milioni di dollari) usa un int unsigned a 32 bit (o usa un int unsigned a 64 bit) e mantienilo semplice.

+0

JH, questa non è una buona idea. Scorri fino alla sezione "Financial Computing" per alcuni esempi di come questo può fallire. http://introcs.cs.princeton.edu/91float/ – poindexter

+0

Probabilmente è una cattiva idea se hai bisogno di quei calcoli specifici e non capisci cosa stai facendo, altrimenti per rappresentare "prezzi" i fluttuanti/doppi sembrano sopravvalutati e sbagliati. –

+0

+1: In realtà questa risposta ha più senso per me della maggior parte degli altri, che suggeriscono GMP o MAPM. Quelle librerie arbitrarie di precisione usano la base 2, il che significa che un valore come '0.1' non può mai essere rappresentato esattamente, qualunque precisione tu possa impostare. Memorizzare tutto come centesimi, in altre parole moltiplicare tutto per 100 e usare 'int64_t' mi sembra una soluzione perfettamente accettabile. Almeno tutte le aggiunte saranno esatte. –

1

Potrebbe essere troppo tardi per questo, ma i decimali a 128 bit funzionano? Questi sono stati accettati in C++ e almeno gcc loro da allora ha gcc-4.5 (stiamo iniziando 4.9 ora:

#include <iostream> 
#include <decimal/decimal> 

using namespace std; 

int main() 
{ 
    { 
    std::decimal::decimal32 dn(.3), dn2(.099), dn3(1000), dn4(201); 
    dn-=dn2; 
    dn*=dn3; 
    cout << "decimal32 = " << (dn==dn4) << " : " << decimal32_to_double(dn) << endl; 
    } 

    { 
    std::decimal::decimal64 dn(.3), dn2(.099), dn3(1000), dn4(201); 
    dn-=dn2; 
    dn*=dn3; 
    cout << "decimal64 = " << (dn==dn4) << " : " << decimal64_to_double(dn) << endl; 
    } 

    { 
    std::decimal::decimal128 dn(.3), dn2(.099), dn3(1000), dn4(201); 
    dn-=dn2; 
    dn*=dn3; 
    cout << "decimal128 = " << (dn==dn4) << " : " << decimal128_to_double(dn) << endl; 
    } 

    return 0; 
} 

Nota c'è decimal32 uguale per dimensioni a stare a galla, decimal64 stesse dimensioni più doppia. Quindi decimal128 è abbastanza grande: da Wikipedia: Decimal128 supporta 34 cifre decimali di significante e un intervallo esponenziale da -6143 a +6144, ovvero ± 0,000000000000000000000000000000000 × 10-6143 a ± 9,9999999999999999999999999999999999 × 106144. (Equivalentemente, ± 0000000000000000000000000000000000 × 10-6176 a ± 999999999999999999999999999999999999 × 106111.)

La libreria mpfr è un punto mobile binario di precisione arbitraria - non decimale di precisione arbitraria. C'è una differenza.

1

Ecco una implementazione di BCMath da PHP a C++. Esistono due versioni, una per Qt e l'altra per l'utilizzo esclusivo di STL.

Fonte: https://github.com/DesarrollosCuado/BCMath-for-Cpp

BCMath::bcscale(4); //Num Decimals 
BCMath test("-5978"); 

test^=30; //Pow, only integers. Not work decimals. 
std::cout<<"Result BigDecimal 1: "<<test.toString().c_str()<<std::endl; 

test-=1.23; //sub 
std::cout<<"Result BigDecimal 2: "<<test.toString().c_str()<<std::endl; 

test*=1.23; //mul 
std::cout<<"Result BigDecimal 3: "<<test.toString().c_str()<<std::endl; 

test*=-1.23; //mul 
std::cout<<"Result BigDecimal 4: "<<test.toString().c_str()<<std::endl; 

BCMath::bcscale(70); //Num Decimals 

BCMath randNum("-5943534512345234545.8998928392839247844353457"); 
BCMath pi("3.1415926535897932384626433832795028841971693993751058209749445923078164062862"); 

BCMath result1 = randNum + pi; 
BCMath result2 = randNum - pi; 
BCMath result3 = randNum * pi; 
BCMath result4 = randNum/pi; 

std::cout<<"Result Super Precision 1: "<<result1.toString().c_str()<<std::endl; 
std::cout<<"Result Super Precision 2: "<<result2.toString().c_str()<<std::endl; 
std::cout<<"Result Super Precision 3: "<<result3.toString().c_str()<<std::endl; 
std::cout<<"Result Super Precision 4: "<<result4.toString().c_str()<<std::endl; 

//Other example 
BCMath::bcscale(4); //Num Decimals 
std::cout<<"Other 1: "<<BCMath::bcmul("1000000.0134", "8.0234").c_str()<<std::endl; 
std::cout<<"Other 2: "<<BCMath::bcadd("1000000.0134", "8.0234").c_str()<<std::endl; 

std::cout<<"Compare 1: "<<BCMath::bccomp("1", "2")<<std::endl; 
std::cout<<"Compare 2: "<<BCMath::bccomp("1.00001", "1", 3)<<std::endl; 
std::cout<<"Compare 3: "<<BCMath::bccomp("1.00001", "1", 5)<<std::endl; 
std::cout<<"Compare 4: "<<(BCMath("1")< BCMath("2"))<<std::endl; 
std::cout<<"Compare 5: "<<(BCMath("1")<=BCMath("2"))<<std::endl; 
std::cout<<"Compare 6: "<<(BCMath("1")> BCMath("2"))<<std::endl; 
std::cout<<"Compare 7: "<<(BCMath("1")>=BCMath("2"))<<std::endl; 
std::cout<<"Compare 8: "<<(BCMath("2")< BCMath("2"))<<std::endl; 
std::cout<<"Compare 9: "<<(BCMath("2")<=BCMath("2"))<<std::endl; 
std::cout<<"Compare 10: "<<(BCMath("2")> BCMath("2"))<<std::endl; 
std::cout<<"Compare 11: "<<(BCMath("2")>=BCMath("2"))<<std::endl; 

std::cout<<"Round 1: "<<BCMath::bcround("123.01254").c_str()<<std::endl; 
std::cout<<"Round 2: "<<BCMath::bcround("-123.01254", 3).c_str()<<std::endl; 
std::cout<<"Round 3: "<<BCMath::bcround("123.01254", 2).c_str()<<std::endl; 
pi.round(3); 
std::cout<<"Round 4: "<<pi.toString().c_str()<<std::endl; 

BCMath part1("-.123"); 
BCMath part2(".123"); 
BCMath part3("123"); 
std::cout<<"Int part 1: "<<part1.getIntPart().c_str()<<std::endl; 
std::cout<<"Dec part 1: "<<part1.getDecPart().c_str()<<std::endl; 
std::cout<<"Int part 2: "<<part2.getIntPart().c_str()<<std::endl; 
std::cout<<"Dec part 2: "<<part2.getDecPart().c_str()<<std::endl; 
std::cout<<"Int part 3: "<<part3.getIntPart().c_str()<<std::endl; 
std::cout<<"Dec part 3: "<<part3.getDecPart().c_str()<<std::endl; 

Risultato:

Result BigDecimal 1: 198005530669253749533290222782634796336450786581284861381777714804795900171726938603997395193921984842256586113024 
Result BigDecimal 2: 198005530669253749533290222782634796336450786581284861381777714804795900171726938603997395193921984842256586113022.7700 
Result BigDecimal 3: 243546802723182111925946974022640799493834467494980379499586589209898957211224134482916796088524041355975600919018.0071 
Result BigDecimal 4: -299562567349513997668914778047848183377416395018825866784491504728175717369805685413987659188884570867849989130392.1487 

Result Super Precision 1: -5943534512345234542.7583001856941315459727023167204971158028306006248941790250554076921835 
Result Super Precision 2: -5943534512345234549.0414854928737180228979890832795028841971693993751058209749445923078164 
Result Super Precision 3: -18672164360341183116.9114783895073349180904753962992796943871920962352436079118338887287186 
Result Super Precision 4: -1891885794154043400.2804849527556211973567525043250278948318788149660700494315139982452600 

Other 1: 8023400.1075 
Other 2: 1000008.0368 

Compare 1: -1 
Compare 2: 0 
Compare 3: 1 
Compare 4: true 
Compare 5: true 
Compare 6: false 
Compare 7: false 
Compare 8: false 
Compare 9: true 
Compare 10: false 
Compare 11: true 

Round 1: 123.0125 
Round 2: -123.013 
Round 3: 123.01 
Round 4: 3.142 

Int part 1: -0 
Dec part 1: 123 
Int part 2: 0 
Dec part 2: 123 
Int part 3: 123 
Dec part 3: 0