用线性顺序表(数组)计算大实数加法与大实数乘法

在银行系统及天文运算中,可能存在超出精度的情况。于是,借助特殊的数据存储方式进行大实数运算显得尤为重要。多数开源社区给出的代码为大整数的四则运算,对于含有小数点的实数不适用,于是特此编写大实数的加法与乘法。

鉴于笔者能力有限,程序使用数组与长度标记组成顺序表、按位存储大实数。实数的整数部分与小数部分分别存储,各提供25位的存储精度,实数整体提供50位存储精度。笔者的问题背景不涉及减法与除法,所以没有对上述功能予以实现。

//存储结构定义
#pragma once
#include <iostream>
#include <algorithm>
#include <string>
constexpr auto PRECISION = 25; //最大精度(小数与整数保留同样长度)
using namespace std;

class Tax
{
  private:
    bool isNeg;               //符号标记(非正数)
    short integer[PRECISION]; //大整数
    short decimal[PRECISION]; //小数
    short ADP_Prec;           //小数精度
    short INT_Prec;           //整数精度

  public:
    Tax();                //无参构造函数
    Tax(string str);      //有参构造函数
    Tax operator+(Tax B); //加法重载
    Tax operator*(Tax B); //乘法重载
    void display() const; //小数显示
};
//存储结构实现
#include "TaxRate.hpp"

Tax::Tax()
{
    isNeg = 0;
    ADP_Prec = 0;
    INT_Prec = 0;
    for (int i = 0; i < PRECISION; i++)
    {
        decimal[i] = 0;
        integer[i] = 0;
    }
}

Tax::Tax(string str)
{
    isNeg = 0;
    ADP_Prec = 0;
    INT_Prec = 0;
    for (int i = 0; i < PRECISION; i++)
    {
        decimal[i] = 0;
        integer[i] = 0;
    }
    int in = 0;
    for (in = 0; str[in] != '.'; in++)
        ;
    for (int i = (in - 1); i >= 0; i--)
        if (str[i] >= '0' && str[i] <= '9')
        {
            integer[in - i - 1] = short(str[i] - '0');
            INT_Prec++;
        }
    for (int j = (INT_Prec + 1); j < str.length(); j++)
        if (str[j] >= '0' && str[j] <= '9')
        {
            decimal[j - INT_Prec - 1] = short(str[j] - '0');
            ADP_Prec++;
        }
}

Tax Tax::operator+(Tax B)
{
    short extra = 0;                                                                 //进位标记
    Tax result;                                                                      //结果
    result.ADP_Prec = ((this->ADP_Prec > B.ADP_Prec) ? this->ADP_Prec : B.ADP_Prec); //结果小数位
    for (int i = result.ADP_Prec - 1; i >= 0; i--)
    {
        short temp = this->decimal[i] + B.decimal[i] + extra;
        result.decimal[i] = temp % 10;
        extra = temp / 10;
    }
    int j = 0;
    while (j < this->INT_Prec && j < B.INT_Prec)
    {
        short temp = this->integer[j] + B.integer[j] + extra;
        result.integer[j] = temp % 10;
        extra = temp / 10;
        j++;
    }
    for (; j < this->INT_Prec; j++)
    {
        short temp = this->integer[j] + extra;
        result.integer[j] = temp % 10;
        extra = temp / 10;
    }
    for (; j < B.INT_Prec; j++)
    {
        short temp = B.integer[j] + extra;
        result.integer[j] = temp % 10;
        extra = temp / 10;
    }
    result.INT_Prec = ((this->INT_Prec > B.INT_Prec) ? this->INT_Prec : B.INT_Prec) + extra;
    if (extra)
        result.integer[result.INT_Prec - 1] = 1;
    return result;
}

Tax Tax::operator*(Tax B)
{
    short ANoDot[2 * PRECISION] = {0};      //被乘数(去掉小数点)
    short BNoDot[2 * PRECISION] = {0};      //乘数(去掉小数点)
    short resultNoDot[4 * PRECISION] = {0}; //结果(去掉小数点)
    for (int i = 0; i < PRECISION; i++)
    {
        ANoDot[i] = this->integer[PRECISION - 1 - i]; //被乘数第0~24位对应整数部分第24~0位
        ANoDot[PRECISION + i] = this->decimal[i];     //被乘数第25~59位对应小数部分第0~24位
        BNoDot[i] = B.integer[PRECISION - 1 - i];     //乘数第0~24位对应整数部分第24~0位
        BNoDot[PRECISION + i] = B.decimal[i];         //乘数第25~59位对应小数部分第0~24位
    }
    //笛卡尔乘法
    for (int i = 0; i < (this->ADP_Prec + this->INT_Prec); i++)
    {
        for (int j = 0; j < (B.ADP_Prec + B.INT_Prec); j++)
        {
            resultNoDot[2 * PRECISION + this->ADP_Prec + B.ADP_Prec - i - j - 1] += ANoDot[PRECISION + this->ADP_Prec - i - 1] * BNoDot[PRECISION + B.ADP_Prec - j - 1];
        }
    }
    //进位清算
    short extra = 0;
    for (int i = (4 * PRECISION - 1); i >= 0; i--)
    {
        short temp = resultNoDot[i] + extra;
        resultNoDot[i] = temp % 10;
        extra = temp / 10;
    }
    //结果转存
    Tax result;
    for (int i = 0; i < PRECISION; i++)
    {
        result.decimal[i] = resultNoDot[2 * PRECISION + i];
        result.integer[i] = resultNoDot[2 * PRECISION - i - 1];
    }
    result.INT_Prec = this->INT_Prec + B.INT_Prec;
    if (!result.integer[result.INT_Prec - 1])
        result.INT_Prec--;
    result.ADP_Prec = this->ADP_Prec + B.ADP_Prec;
    return result;
}

void Tax::display() const
{
    for (int i = (INT_Prec - 1); i >= 0; i--)
        cout << integer[i];
    cout << ".";
    for (int j = 0; j < ADP_Prec; j++)
        cout << decimal[j];
    cout << endl;
}

由于加法与乘法的实现都采用了运算符重载,以上算法依旧存在精度溢出的可能(2个乘数的位数长度分别为a和b,则相加结果的位数至少是max{a, b}、相乘结果的位数至少是a + b - 1)。在实际使用时,可以通过修改宏PRECISION的值来满足运算精度。

因为只是算法样例,笔者不提供主函数代码,有需要的朋友可以自行编写主函数进行实际运用。

【2018年9月23日完成 数据结构(C++)】

发布了11 篇原创文章 · 获赞 8 · 访问量 4767

猜你喜欢

转载自blog.csdn.net/u011367208/article/details/82825717