【问题标题】:Is there a C++ equivalent to Java's BigDecimal?是否有与 Java 的 BigDecimal 等效的 C++?
【发布时间】:2011-01-25 21:02:39
【问题描述】:

我正在寻找可以进行十进制浮点运算的 C++ 类。通过http://speleotrove.com/decimal/ 可以找到人们编写但未维护的各种类的链接。挖掘 decNumber++ 的内容后,我收到了一些电子邮件,表明 GCC 最终将支持此功能。 (正式名称为 ISO/IEC TR 24733)

我正在寻找可以用来替代 float 或 double 的东西,其他人在他们自己的项目中使用的东西。希望开源。

谢谢!

编辑:我应该指出我试图用它来表示价格。所以我需要精确的小数,而不是巨大的小数。

【问题讨论】:

  • gmplib 也许? gmplib.org
  • 您不应该使用双精度或浮点数来计算价格...
  • JH 我知道这一点,这就是为什么我要寻找像 BigDecimal 这样的东西。

标签: c++ bigdecimal


【解决方案1】:

存在一个名为 GMP (GNU multiple precision library) 的庞大库,它支持这一点并且还具有 C++ 绑定,但老实说,C++ 接口有点古怪和过时。

文档中的一个示例,以下创建了一个名为 f 的浮点数,精度至少为 500 位:

mpf_class f(1.5, 500);

【讨论】:

  • 类似于 BigDecimal mpf_class 采用字符串构造函数。 Ubuntu 10.4 附带的 gmpxx 版本使用部分模板专业化,因此称其为过时可能有点牵强。我想我可以得到这个来做我的竞标。恭喜你,你得到了一个 cookie,呃,复选标记。
  • @poindexter:我所说的“过时”主要是命名:拜托,“mpf_class”是什么样的类名?!他们应该叫它gmp::big_float 或类似的名字。
  • 我认为这是一场与 GNU 命名约定的艰苦战斗。 :)
【解决方案2】:

任你选。那里有很多。例如,您可以咨询list on Wikipedia。

【讨论】:

  • 库部分已被删除。
【解决方案3】:

这个问题有点老了,但对于其他有同样需求的人来说:Boost.multiprecision 可能是你正在寻找的。​​p>

http://www.boost.org/doc/libs/1_57_0/libs/multiprecision/doc/html/boost_multiprecision/tut/floats/cpp_dec_float.html

这是一个任意精度库,可以处理基于 10 的小数。

【讨论】:

  • 我想警告你不要使用cpp_dec_float,因为我在尝试使用它时遇到了不好的体验。当我试图在31250000 上划分59999996874999999999999999831 时,cpp_dec_float 给了我0.00000003199...99946064282(中间有很多9)而不是正确的0.000000032。当我使用std::locale::globat() 调用更改默认语言环境时,转换为字符串完全失败,因为它依赖于“经典”语言环境的行为,但不要强制它。不要使用。
【解决方案4】:

如果您需要使用巨大的十进制值进行操作,我建议您使用http://gmplib.org/ 库。我在 C 和 C++ 中经常使用它。

【讨论】:

    【解决方案5】:

    使用 GMP 并将所有内容存储为美分。如果您知道您不会超过 2^32 美分(4294.9673 万美元),请使用 32 位无符号整数(或使用 64 位无符号整数)并保持简单。

    【讨论】:

    • JH,这不是一个好主意。浏览“金融计算”部分,了解如何失败的一些示例。 introcs.cs.princeton.edu/91float
    • 如果你需要那些特定的计算并且不明白你在做什么,这可能是个坏主意,否则表示“价格”浮动/双精度似乎被高估和不正确。
    • +1:实际上,这个答案对我来说比大多数其他人更有意义,建议 GMP 或 MAPM。那些任意精度库使用基数 2,这意味着像 0.1 这样的值永远无法准确表示,无论您设置什么精度。将所有内容存储为美分,换句话说,将所有内容乘以 100 并使用 int64_t 对我来说似乎是一个完全可以接受的解决方案。至少所有添加都是准确的。
    • 对我上一条评论的更正:MAPM 确实在内部使用十进制数字,因此它能够准确地表示 0.1。
    • @poindexter 提供的链接好像消失了,但是it's still available via the WayBack Machine
    【解决方案6】:

    我可能为时已晚,但 128 位小数可以工作吗? 这些已经被 C++ 接受了,至少 gcc 从 gcc-4.5 开始就有了(我们现在开始 4.9:

    #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;
    }
    

    注意,decimal32 的大小等于 float,decimal64 的大小等于大多数 double。所以 decimal128 相当大。从Wikipedia:Decimal128 支持 34 位十进制有效数位和 -6143 到 +6144 的指数范围,即 ±0.0000000000000000000000000000000000×10−6143 到 ±9.999999999999999999999999999999999 (等效地,±0000000000000000000000000000000000×10−6176 到 ±99999999999999999999999999999999999×106111。)

    mpfr 库是任意精度的二进制浮点 - 不是任意精度的十进制。有区别。

    【讨论】:

      【解决方案7】:

      您可能正在寻找“MAPM,C 语言中的便携式任意精度数学库”。它还包括 C++ Wrappers:

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

      【讨论】:

      • FAIL: "请注意,默认 MAPM 库不是线程安全的。如果多个 MAPM 函数同时处于活动状态,则 MAPM 内部数据结构可能会损坏。用户应保证只有一个线程在执行MAPM 函数。这通常可以通过调用操作系统来获得“信号量”或“关键代码段”来实现,因此操作系统将保证一次只有一个 MAPM 线程处于活动状态。"
      【解决方案8】:

      这是 BCMath PHP 到 C++ 的实现。有两个版本,一个用于 Qt,另一个仅用于 STL。

      来源: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;
      

      结果:

      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
      

      【讨论】:

        【解决方案9】:

        您可以使用 BigDecimal 的下一个 cpp 实现:

        https://github.com/Sam-bit/BigDecimal-CPP

        最好的问候。

        【讨论】:

          猜你喜欢
          • 2010-12-23
          • 1970-01-01
          • 2013-07-25
          • 2018-11-20
          • 2011-04-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-04-30
          相关资源
          最近更新 更多