• 10706阅读
  • 4回复

mpmath高精度浮点数四则运算、比较、格式化简单封装 [复制链接]

上一主题 下一主题
离线XChinux
 

只看楼主 倒序阅读 楼主  发表于: 2012-09-22
在PHP中常用到bcmath库的bc_add, bc_sub, bc_mul, bc_div, bc_comp等函数以进行金钱计算,以保证精度,在Qt/C++中以前一直没有专门处理过,现在遇到一个应用,使用double计算会出现不可完全避免的误差,所以对GMP库的浮点数四则运算进行了下简单封装。

附件中共有下面几个文件
libgmp\gmp.h                   Win32 GMP库(4.1.0)头文件
libgmp\gmp.lib                  Win32 GMP库(4.1.0).lib文件
libgmp\gmp.dll                  Win32 GMP库(4.1.0).dll文件
mpmath.hpp
mpmath.cpp

如果是Linux下,那直接将libgmp-dev包安装上即可,或者可到官网http://gmplib.org下载自行编译(在Windows下编译比较麻烦,所以附件中提供了现成库),mpmath.hpp中的函数的数字参数,都是字符串型的(char *, std::string, QString)十进制数字,共有六类函数:

mp_add(arg1, arg2, prec)                          //return arg1 + arg2,结果保留prec位小数
mp_sub(arg1, arg2, prec)                          //return arg1 - arg2, 结果保留prec位小数
mp_mul(arg1, arg2, prec)                          //return arg1 * arg2, 结果保留prec位小数
mp_div(arg1, arg2, prec)                           //return arg1 / arg2, 结果保留prec位小数,如果arg2为0,则返回空字符串
mp_fmt(arg, prec, show_thousand_digit_symbol = false)                   //将arg格式化显示,保留prec位小数,第三个参数表示是否显示千分位
mp_comp(arg1, arg2)                              //比较arg1和arg2,小于、等于、大于时分别返回-1, 0, 1

mpmath.hpp和mpmath.cpp的代码跟帖附上。
附件: mpmath.zip (131 K) 下载次数:62
二笔 openSUSE Vim N9 BB10 XChinux@163.com 网易博客 腾讯微博
承接C++/Qt、Qt UI界面、PHP及预算报销系统开发业务
离线XChinux

只看该作者 1楼 发表于: 2012-09-22
mpmath.hpp
  1. /**
  2. * mpmath浮点数精确计算简单封装, 依赖于GMP库
  3. * (C) 2012 by XChinux@163.com
  4. */
  5. #ifndef CHINUXTEAM_MPMATH_HPP
  6. #define CHINUXTEAM_MPMATH_HPP
  7. #include <string>
  8. #include <QtCore/QString>
  9. namespace ChinuxTeam
  10. {
  11. std::string mp_add(const char *arg1, const char *arg2, int prec);
  12. std::string mp_sub(const char *arg1, const char *arg2, int prec);
  13. std::string mp_mul(const char *arg1, const char *arg2, int prec);
  14. std::string mp_div(const char *arg1, const char *arg2, int prec);
  15. std::string mp_fmt(const char *arg1, int prec, bool show_thousand_digit_symbol = false);
  16. int mp_comp(const char *arg1, const char *arg2);
  17. //-------------------------------------------------------------------------
  18. QString mp_add(const QString &arg1, const QString &arg2, int prec);
  19. QString mp_sub(const QString &arg1, const QString &arg2, int prec);
  20. QString mp_mul(const QString &arg1, const QString &arg2, int prec);
  21. QString mp_div(const QString &arg1, const QString &arg2, int prec);
  22. QString mp_fmt(const QString &arg1, int prec, bool show_thousand_digit_symbol = false);
  23. int mp_comp(const QString &arg1, const QString &arg2);
  24. //------------------------------------------------------------------------
  25. std::string mp_add(const std::string &arg1, const std::string &arg2, int prec);
  26. std::string mp_sub(const std::string &arg1, const std::string &arg2, int prec);
  27. std::string mp_mul(const std::string &arg1, const std::string &arg2, int prec);
  28. std::string mp_div(const std::string &arg1, const std::string &arg2, int prec);
  29. std::string mp_fmt(const std::string &arg1, int prec, bool show_thousand_digit_symbol = false);
  30. int mp_comp(const std::string &arg1, const std::string &arg2);
  31. }
  32. #endif
二笔 openSUSE Vim N9 BB10 XChinux@163.com 网易博客 腾讯微博
承接C++/Qt、Qt UI界面、PHP及预算报销系统开发业务
离线XChinux

只看该作者 2楼 发表于: 2012-09-22
mpmath.cpp
  1. /**
  2. * mpmath浮点数精确计算简单封装, 依赖于GMP库
  3. * (C) 2012 by XChinux@163.com
  4. */
  5. #include <sstream>
  6. #include <gmp.h>
  7. #include "mpmath.hpp"
  8. namespace ChinuxTeam
  9. {
  10. enum mp_op_t {op_add, op_sub, op_mul, op_div};
  11. std::string mp_op(mp_op_t op, const std::string &arg1,
  12.         const std::string &arg2, int prec);
  13. std::string mp_add(const char *arg1, const char *arg2, int prec)
  14. {
  15.     return mp_op(op_add, std::string(arg1), std::string(arg2), prec);
  16. }
  17. std::string mp_sub(const char *arg1, const char *arg2, int prec)
  18. {
  19.     return mp_op(op_sub, std::string(arg1), std::string(arg2), prec);
  20. }
  21. std::string mp_mul(const char *arg1, const char *arg2, int prec)
  22. {
  23.     return mp_op(op_mul, std::string(arg1), std::string(arg2), prec);
  24. }
  25. std::string mp_div(const char *arg1, const char *arg2, int prec)
  26. {
  27.     return mp_op(op_div, std::string(arg1), std::string(arg2), prec);
  28. }
  29. std::string mp_fmt(const char *arg1, int prec,
  30.         bool show_thousand_digit_symbol)
  31. {
  32.     return mp_fmt(std::string(arg1), prec, show_thousand_digit_symbol);
  33. }
  34. int mp_comp(const char *arg1, const char *arg2)
  35. {
  36.     return mp_comp(std::string(arg1), std::string(arg2));
  37. }
  38. //-------------------------------------------------------------------
  39. QString mp_add(const QString &arg1, const QString &arg2, int prec)
  40. {
  41.     return QString::fromStdString(mp_op(op_add, arg1.toStdString(),
  42.                 arg2.toStdString(), prec));
  43. }
  44. QString mp_sub(const QString &arg1, const QString &arg2, int prec)
  45. {
  46.     return QString::fromStdString(mp_op(op_sub, arg1.toStdString(),
  47.                 arg2.toStdString(), prec));
  48. }
  49. QString mp_mul(const QString &arg1, const QString &arg2, int prec)
  50. {
  51.     return QString::fromStdString(mp_op(op_mul, arg1.toStdString(),
  52.                 arg2.toStdString(), prec));
  53. }
  54. QString mp_div(const QString &arg1, const QString &arg2, int prec)
  55. {
  56.     return QString::fromStdString(mp_op(op_div, arg1.toStdString(),
  57.                 arg2.toStdString(), prec));
  58. }
  59. QString mp_fmt(const QString &arg1, int prec,
  60.         bool show_thousand_digit_symbol)
  61. {
  62.     return QString::fromStdString(mp_fmt(arg1.toStdString(), prec,
  63.                 show_thousand_digit_symbol));
  64. }
  65. int mp_comp(const QString &arg1, const QString &arg2)
  66. {
  67.     return mp_comp(arg1.toStdString(), arg2.toStdString());
  68. }
  69. //----------------------------------------------------------------------
  70. std::string mp_add(const std::string &arg1, const std::string &arg2, int prec)
  71. {
  72.     return mp_op(op_add, arg1, arg2, prec);
  73. }
  74. std::string mp_sub(const std::string &arg1, const std::string &arg2, int prec)
  75. {
  76.     return mp_op(op_sub, arg1, arg2, prec);
  77. }
  78. std::string mp_mul(const std::string &arg1, const std::string &arg2, int prec)
  79. {
  80.     return mp_op(op_mul, arg1, arg2, prec);
  81. }
  82. std::string mp_div(const std::string &arg1, const std::string &arg2, int prec)
  83. {
  84.     return mp_op(op_div, arg1, arg2, prec);
  85. }
  86. int mp_comp(const std::string &arg1, const std::string &arg2)
  87. {
  88.     std::string::size_type pos1 = arg1.find_last_of(".");
  89.     std::string::size_type pos2 = arg2.find_last_of(".");
  90.     int prec1 = pos1 == std::string::npos ? 0 : (arg1.size() - pos1 - 1);
  91.     int prec2 = pos2 == std::string::npos ? 0 : (arg2.size() - pos2 - 1);
  92.     mpf_t f1, f2;
  93.     mpf_init2(f1, prec1);
  94.     mpf_init2(f2, prec2);
  95.     mpf_set_str(f1, arg1.c_str(), 10);
  96.     mpf_set_str(f2, arg2.c_str(), 10);
  97.     int ret = mpf_cmp(f1, f2);
  98.     mpf_clear(f1);
  99.     mpf_clear(f2);
  100.     return ret;
  101. }
  102. std::string mp_fmt(const std::string &arg1, int prec,
  103.         bool show_thousand_digit_symbol)
  104. {
  105.     mpf_t f1;
  106.     mpf_init2(f1, prec);
  107.     mpf_set_str(f1, arg1.c_str(), 10);
  108.     std::ostringstream fmt;
  109.     fmt << "%." << prec << "Ff";
  110.     char *ret;
  111.     int len = gmp_asprintf(&ret, fmt.str().c_str(), f1);
  112.     mpf_clear(f1);
  113.     std::string str(ret);
  114.     __gmp_free_func(ret, len);
  115.     ret = NULL;
  116.     if (!show_thousand_digit_symbol)
  117.     {
  118.         return str;
  119.     }
  120.     int pos = str.size() - (prec > 0 ? (4 + prec) : 3);
  121.     while (pos > 0)
  122.     {
  123.         str.insert(pos, 1, ',');
  124.         pos -= 3;
  125.     }
  126.     return str;
  127. }
  128. std::string mp_op(mp_op_t op, const std::string &arg1,
  129.         const std::string &arg2, int prec)
  130. {
  131.     std::string::size_type pos2 = arg2.find_last_of(".");
  132.     int prec2 = pos2 == std::string::npos ? 0 : (arg2.size() - pos2 - 1);
  133.     mpf_t f2;
  134.     mpf_init2(f2, prec2);
  135.     mpf_set_str(f2, arg2.c_str(), 10);
  136.     if (op == op_div)
  137.     {
  138.         if (mpf_cmp_si(f2, 0) == 0)
  139.         {
  140.             mpf_clear(f2);
  141.             return std::string();
  142.         }
  143.     }
  144.     
  145.     std::string::size_type pos1 = arg1.find_last_of(".");
  146.     int prec1 = pos1 == std::string::npos ? 0 : (arg1.size() - pos1 - 1);
  147.     mpf_t f1, f3;
  148.     mpf_init2(f1, prec1);
  149.     mpf_init2(f3, prec);
  150.     mpf_set_str(f1, arg1.c_str(), 10);
  151.     switch (op)
  152.     {
  153.         case op_add:
  154.             mpf_add(f3, f1, f2);
  155.             break;
  156.         case op_sub:
  157.             mpf_sub(f3, f1, f2);
  158.             break;
  159.         case op_mul:
  160.             mpf_mul(f3, f1, f2);
  161.             break;
  162.         case op_div:
  163.             mpf_div(f3, f1, f2);
  164.             break;
  165.         default:;
  166.     }
  167.     std::ostringstream fmt;
  168.     fmt << "%." << prec << "Ff";
  169.     char *ret;
  170.     int len = gmp_asprintf(&ret, fmt.str().c_str(), f3);
  171.     mpf_clear(f1);
  172.     mpf_clear(f2);
  173.     mpf_clear(f3);
  174.     std::string str(ret);
  175.     __gmp_free_func(ret, len);
  176.     ret = NULL;
  177.     return str;
  178. }
  179. }
二笔 openSUSE Vim N9 BB10 XChinux@163.com 网易博客 腾讯微博
承接C++/Qt、Qt UI界面、PHP及预算报销系统开发业务
离线toby520

只看该作者 3楼 发表于: 2012-10-08
好东西,收藏之
QtQML多多指教开发社区 http://qtclub.heilqt.com
将QtCoding进行到底
关注移动互联网,关注金融
开发跨平台客户端,服务于金融行业
专业定制界面
群号:312125701   373955953(qml控件定做)
离线soulcxf

只看该作者 4楼 发表于: 2013-12-16
感觉以后会用到,谢谢 。
快速回复
限100 字节
 
上一个 下一个