浮点高精度

简单封装了一下浮点加法乘法,未验证

struct BigFloat {
    static const int N = 100, n = 16; //位数,保留位数
    vector<int> integer;//整数部分(逆序存储)123. -->321.
    vector<int> decimal;//小数部分(正序存储).456 -->.456
    int integerSize;//整数长度
    int decimalSize;//小数长度
    BigFloat() {
        init();
    }
    BigFloat(const string& s) {
        init();
        *this = s;
    }
    BigFloat(const double& val) {
        init();
        *this = val;
    }
    void init() {
        integer.reserve(N); decimal.reserve(N);
        integer.resize(N); decimal.resize(N);
        integerSize = 0; decimalSize = 0;
    }
    BigFloat operator = (const double& value) {
        (*this).init();
        ostringstream oss;
        oss << fixed << setprecision(n) << value;//保留精度
        *this = oss.str();
        return *this;
    }
    BigFloat operator = (const string &s) {
        (*this).init();
        int idx;
        for (idx = 0; s[idx] != '.'; idx ++); //定位小数点下标
        int len = (int)s.size();
        for (int i = idx + 1 ; i < len ; i++) { //正序存储小数部分
            decimal[decimalSize++] = s[i] - '0';
        }
        for (int j = idx - 1; j >= 0 ; j--) { //逆序存储整数部分
            integer[integerSize++] = s[j] - '0';
        }
        return *this;
    }
    BigFloat operator + (const BigFloat &a) { //重载加法运算符
        BigFloat ret;//保存返回结果
        int qLen = decimalSize > a.decimalSize ? decimalSize : a.decimalSize;//小数长度
        int carry = 0;//保存进位,以及小数到整数部分的进位
        ret.decimalSize = qLen;
        for (int i = qLen - 1 ; i >= 0 ; i--) { //小数部分相加
            int tmp = decimal[i] + a.decimal[i] + carry;
            ret.decimal[--qLen] = tmp % 10; //保存结果
            carry = tmp / 10; //更新进位
        }
        int pLen = integerSize > a.integerSize ? integerSize : a.integerSize;//整数长度
        for (int j = 0 ; j < pLen ; j++) { //整数部分相加
            int tmp = integer[j] + a.integer[j] + carry;
            ret.integer[ret.integerSize++] = tmp % 10; //保存结果
            carry = tmp / 10; //更新进位
        }
        if (carry != 0) { //当前进位不为0,进位并保存下来
            ret.integer[ret.integerSize++] = carry;
        }
        return ret;
    }
    BigFloat operator += (const BigFloat& a) {
        *this = *this + a;
        return *this;
    }
    BigFloat operator * (const string& num2) {
        string num1 = str();
        *this = mul(num1, num2);
        return *this;
    }
    BigFloat operator * (double value) {
        ostringstream num2;
        num2 << fixed << setprecision(n) << value;//保留精度
        string num1 = str();
        *this = mul(num1, num2.str());
        return *this;
    }
    BigFloat operator * (BigFloat num2) {
        string num1 = str();
        *this = mul(num1, num2.str());
        return *this;
    }
    string str() {
        string res = "";
        int i = integerSize - 1;
        while (integer[i] == 0 && i >= 0 )i--; //移除高位的0
        if (i == -1) {
            res += "0";
        } else {
            while (i >= 0) { //倒序输出整数部分
                res += integer[i--] + '0';
            }
        }
        int j = decimalSize - 1;
        while (decimal[j] == 0 && j >= 0) j--; //移除小数部分低位0,并保存小数部分有效长度
        if (j != -1) {
            res += ".";
            for (int k = 0; k <= j; k ++) { //输出小数部分
                res += decimal[k] + '0';
            }
        }
        return res;
    }
    friend ostream& operator << (ostream& out, const BigFloat& x) {
        int i = x.integerSize - 1;
        while (x.integer[i] == 0 && i >= 0 )i--; //移除高位的0
        if (i == -1) {
            out << "0";
        } else {
            while (i >= 0) { //倒序输出整数部分
                out << x.integer[i--];
            }
        }
        int j = x.decimalSize - 1;
        while (x.decimal[j] == 0 && j >= 0) j--; //移除小数部分低位0,并保存小数部分有效长度
        if (j != -1) {
            out << ".";
            for (int k = 0; k <= j; k ++) {
                out << x.decimal[k];
            }
        }
        return out;
    }
    friend istream& operator >> (istream& in, BigFloat& x) {
        string s;
        in >> s;
        x = s;
        return in;
    }
    // 将字符串形式的数字(带小数点)转换为倒序存储的整数数组,并记录小数点位置
    pair<vector<int>, int> stringToVector(const string& num) {
        vector<int> result;
        int decimalPos = 0;
        bool isDecimal = false;

        for (int i = num.size() - 1; i >= 0; --i) {
            if (num[i] == '.') {
                isDecimal = true;
                decimalPos = num.size() - 1 - i;
            } else {
                result.push_back(num[i] - '0');
            }
        }
        if (!isDecimal) decimalPos = 0;
        return {result, decimalPos};
    }
    // 将倒序存储的整数数组转换为字符串形式的数字,并处理小数点位置
    string vectorToString(const vector<int>& num, int decimalPos) {
        string result;
        bool leadingZero = true;

        for (int i = num.size() - 1; i >= 0; --i) {
            if (leadingZero && num[i] == 0 && i >= decimalPos) continue;
            leadingZero = false;
            if (i == decimalPos - 1 && i != 0) {
                result.push_back('.');
            }
            result.push_back(num[i] + '0');
        }

        if (leadingZero) return "0";
        if (decimalPos == 0) return result;
        if (result.size() <= decimalPos) result.insert(result.begin(), decimalPos - result.size(), '0');

        return result;
    }
    // 高精度浮点数乘法
    string mul(const string& num1, const string& num2) {
        auto [n1, d1] = stringToVector(num1);
        auto [n2, d2] = stringToVector(num2);
        vector<int> result(n1.size() + n2.size(), 0);

        for (size_t i = 0; i < n1.size(); ++i) {
            for (size_t j = 0; j < n2.size(); ++j) {
                result[i + j] += n1[i] * n2[j];
                if (result[i + j] >= 10) {
                    result[i + j + 1] += result[i + j] / 10;
                    result[i + j] %= 10;
                }
            }
        }

        // 计算小数点位置
        int decimalPos = d1 + d2;

        // 去掉前导0
        while (result.size() > 1 && result.back() == 0) {
            result.pop_back();
        }

        return vectorToString(result, decimalPos);
    }
};
posted @ 2024-08-13 21:20  Ke_scholar  阅读(24)  评论(0编辑  收藏  举报