查看完整版本: [-- mpmath高精度浮点数四则运算、比较、格式化简单封装 --]

QTCN开发网 -> Qt代码秀 -> mpmath高精度浮点数四则运算、比较、格式化简单封装 [打印本页] 登录 -> 注册 -> 回复主题 -> 发表主题

XChinux 2012-09-22 18:24

mpmath高精度浮点数四则运算、比较、格式化简单封装

在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的代码跟帖附上。

XChinux 2012-09-22 18:30
mpmath.hpp

  1. /**
    * mpmath浮点数精确计算简单封装, 依赖于GMP库
    * (C) 2012 by XChinux@163.com
    */
    #ifndef CHINUXTEAM_MPMATH_HPP
    #define CHINUXTEAM_MPMATH_HPP

    #include <string>
    #include <QtCore/QString>

    namespace ChinuxTeam
    {

    std::string mp_add(const char *arg1, const char *arg2, int prec);
    std::string mp_sub(const char *arg1, const char *arg2, int prec);
    std::string mp_mul(const char *arg1, const char *arg2, int prec);
    std::string mp_div(const char *arg1, const char *arg2, int prec);
    std::string mp_fmt(const char *arg1, int prec, bool show_thousand_digit_symbol = false);
    int mp_comp(const char *arg1, const char *arg2);

    //-------------------------------------------------------------------------

    QString mp_add(const QString &arg1, const QString &arg2, int prec);
    QString mp_sub(const QString &arg1, const QString &arg2, int prec);
    QString mp_mul(const QString &arg1, const QString &arg2, int prec);
    QString mp_div(const QString &arg1, const QString &arg2, int prec);
    QString mp_fmt(const QString &arg1, int prec, bool show_thousand_digit_symbol = false);
    int mp_comp(const QString &arg1, const QString &arg2);
    //------------------------------------------------------------------------

    std::string mp_add(const std::string &arg1, const std::string &arg2, int prec);
    std::string mp_sub(const std::string &arg1, const std::string &arg2, int prec);
    std::string mp_mul(const std::string &arg1, const std::string &arg2, int prec);
    std::string mp_div(const std::string &arg1, const std::string &arg2, int prec);
    std::string mp_fmt(const std::string &arg1, int prec, bool show_thousand_digit_symbol = false);
    int mp_comp(const std::string &arg1, const std::string &arg2);
    }

    #endif

XChinux 2012-09-22 18:32
mpmath.cpp

  1. /**
    * mpmath浮点数精确计算简单封装, 依赖于GMP库
    * (C) 2012 by XChinux@163.com
    */
    #include <sstream>
    #include <gmp.h>
    #include "mpmath.hpp"

    namespace ChinuxTeam
    {
    enum mp_op_t {op_add, op_sub, op_mul, op_div};
    std::string mp_op(mp_op_t op, const std::string &arg1,
            const std::string &arg2, int prec);


    std::string mp_add(const char *arg1, const char *arg2, int prec)
    {
        return mp_op(op_add, std::string(arg1), std::string(arg2), prec);
    }

    std::string mp_sub(const char *arg1, const char *arg2, int prec)
    {
        return mp_op(op_sub, std::string(arg1), std::string(arg2), prec);
    }

    std::string mp_mul(const char *arg1, const char *arg2, int prec)
    {
        return mp_op(op_mul, std::string(arg1), std::string(arg2), prec);
    }

    std::string mp_div(const char *arg1, const char *arg2, int prec)
    {
        return mp_op(op_div, std::string(arg1), std::string(arg2), prec);
    }

    std::string mp_fmt(const char *arg1, int prec,
            bool show_thousand_digit_symbol)
    {
        return mp_fmt(std::string(arg1), prec, show_thousand_digit_symbol);
    }

    int mp_comp(const char *arg1, const char *arg2)
    {
        return mp_comp(std::string(arg1), std::string(arg2));
    }

    //-------------------------------------------------------------------

    QString mp_add(const QString &arg1, const QString &arg2, int prec)
    {
        return QString::fromStdString(mp_op(op_add, arg1.toStdString(),
                    arg2.toStdString(), prec));
    }

    QString mp_sub(const QString &arg1, const QString &arg2, int prec)
    {
        return QString::fromStdString(mp_op(op_sub, arg1.toStdString(),
                    arg2.toStdString(), prec));
    }

    QString mp_mul(const QString &arg1, const QString &arg2, int prec)
    {
        return QString::fromStdString(mp_op(op_mul, arg1.toStdString(),
                    arg2.toStdString(), prec));
    }

    QString mp_div(const QString &arg1, const QString &arg2, int prec)
    {
        return QString::fromStdString(mp_op(op_div, arg1.toStdString(),
                    arg2.toStdString(), prec));
    }

    QString mp_fmt(const QString &arg1, int prec,
            bool show_thousand_digit_symbol)
    {
        return QString::fromStdString(mp_fmt(arg1.toStdString(), prec,
                    show_thousand_digit_symbol));
    }

    int mp_comp(const QString &arg1, const QString &arg2)
    {
        return mp_comp(arg1.toStdString(), arg2.toStdString());
    }

    //----------------------------------------------------------------------

    std::string mp_add(const std::string &arg1, const std::string &arg2, int prec)
    {
        return mp_op(op_add, arg1, arg2, prec);
    }

    std::string mp_sub(const std::string &arg1, const std::string &arg2, int prec)
    {
        return mp_op(op_sub, arg1, arg2, prec);
    }

    std::string mp_mul(const std::string &arg1, const std::string &arg2, int prec)
    {
        return mp_op(op_mul, arg1, arg2, prec);
    }

    std::string mp_div(const std::string &arg1, const std::string &arg2, int prec)
    {
        return mp_op(op_div, arg1, arg2, prec);
    }

    int mp_comp(const std::string &arg1, const std::string &arg2)
    {
        std::string::size_type pos1 = arg1.find_last_of(".");
        std::string::size_type pos2 = arg2.find_last_of(".");
        int prec1 = pos1 == std::string::npos ? 0 : (arg1.size() - pos1 - 1);
        int prec2 = pos2 == std::string::npos ? 0 : (arg2.size() - pos2 - 1);

        mpf_t f1, f2;
        mpf_init2(f1, prec1);
        mpf_init2(f2, prec2);
        mpf_set_str(f1, arg1.c_str(), 10);
        mpf_set_str(f2, arg2.c_str(), 10);
        int ret = mpf_cmp(f1, f2);
        mpf_clear(f1);
        mpf_clear(f2);
        return ret;
    }

    std::string mp_fmt(const std::string &arg1, int prec,
            bool show_thousand_digit_symbol)
    {
        mpf_t f1;
        mpf_init2(f1, prec);
        mpf_set_str(f1, arg1.c_str(), 10);

        std::ostringstream fmt;
        fmt << "%." << prec << "Ff";

        char *ret;
        int len = gmp_asprintf(&ret, fmt.str().c_str(), f1);

        mpf_clear(f1);

        std::string str(ret);
        __gmp_free_func(ret, len);
        ret = NULL;

        if (!show_thousand_digit_symbol)
        {
            return str;
        }

        int pos = str.size() - (prec > 0 ? (4 + prec) : 3);
        while (pos > 0)
        {
            str.insert(pos, 1, ',');
            pos -= 3;
        }
        return str;
    }

    std::string mp_op(mp_op_t op, const std::string &arg1,
            const std::string &arg2, int prec)
    {
        std::string::size_type pos2 = arg2.find_last_of(".");
        int prec2 = pos2 == std::string::npos ? 0 : (arg2.size() - pos2 - 1);

        mpf_t f2;
        mpf_init2(f2, prec2);
        mpf_set_str(f2, arg2.c_str(), 10);

        if (op == op_div)
        {
            if (mpf_cmp_si(f2, 0) == 0)
            {
                mpf_clear(f2);
                return std::string();
            }
        }
        
        std::string::size_type pos1 = arg1.find_last_of(".");
        int prec1 = pos1 == std::string::npos ? 0 : (arg1.size() - pos1 - 1);

        mpf_t f1, f3;
        mpf_init2(f1, prec1);
        mpf_init2(f3, prec);
        mpf_set_str(f1, arg1.c_str(), 10);
        switch (op)
        {
            case op_add:
                mpf_add(f3, f1, f2);
                break;
            case op_sub:
                mpf_sub(f3, f1, f2);
                break;
            case op_mul:
                mpf_mul(f3, f1, f2);
                break;
            case op_div:
                mpf_div(f3, f1, f2);
                break;
            default:;
        }

        std::ostringstream fmt;
        fmt << "%." << prec << "Ff";

        char *ret;
        int len = gmp_asprintf(&ret, fmt.str().c_str(), f3);

        mpf_clear(f1);
        mpf_clear(f2);
        mpf_clear(f3);

        std::string str(ret);
        __gmp_free_func(ret, len);
        ret = NULL;
        return str;
    }
    }


toby520 2012-10-08 15:33
好东西,收藏之

soulcxf 2013-12-16 13:40
感觉以后会用到,谢谢 。


查看完整版本: [-- mpmath高精度浮点数四则运算、比较、格式化简单封装 --] [-- top --]



Powered by phpwind v8.7 Code ©2003-2011 phpwind
Gzip disabled