You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何存储超出unsigned long long上限的数值解决大数求和溢出问题

问题原因分析

现有代码的异常本质来自两个问题:

  • 首先pow是浮点数运算函数,n较大时本身就会出现精度丢失,哪怕n还没到溢出阈值就可能输出错误的起始、结束数值
  • 核心问题是n≥18时,等差数列求和用到的(finish-start+1)*(start+finish)结果远大于unsigned long long的上限(2^64-1,约1.8e19),溢出截断后就会出现负数、0等异常结果。
解决方案

常用的实现思路有两种:

思路1:引入成熟的大整数运算库

如果允许使用第三方依赖,直接用已经封装好的任意精度整数类型即可,代码改动量最小。比如用Boost库的boost::multiprecision::cpp_int类型,原生支持常规的整数加减乘除运算,不需要自己处理进位逻辑。
修改后的代码示例:

#include <iostream>
#include <boost/multiprecision/cpp_int.hpp>

using namespace std;
using namespace boost::multiprecision;

int main() 
{
    int n;
    cin >> n;
    // 用循环乘10代替pow,避免浮点数精度误差
    cpp_int start = 1;
    for (int i = 0; i < n-1; ++i) start *= 10;
    cpp_int finish = start * 10 - 1;
    cpp_int sum = ((finish - start + 1) * (start + finish)) / 2;
    cout << sum << endl;
    return 0;
}

思路2:手动实现大整数运算(无第三方依赖)

如果不能引入外部库,可以用数组/字符串模拟大整数的运算逻辑。我们可以先简化求和公式减少运算量:
原等差数列的项数为9*10^(n-1),首项加末项为10^(n-1) + (10^n - 1) = 11*10^(n-1) - 1,因此总和公式可以简化为:
(9*10^(n-1) * (11*10^(n-1) - 1)) / 2
只需要实现大整数乘小整数、大整数减1、大整数除以2、两个大整数相乘这几个基础逻辑即可,纯原生实现示例如下:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

// 大整数(低位在前存储)乘小整数
vector<int> multiply(const vector<int>& num, int x) {
    vector<int> res;
    int carry = 0;
    for (int digit : num) {
        long long product = (long long)digit * x + carry;
        res.push_back(product % 10);
        carry = product / 10;
    }
    while (carry > 0) {
        res.push_back(carry % 10);
        carry /= 10;
    }
    return res;
}

// 大整数减1
vector<int> subtract_one(const vector<int>& num) {
    vector<int> res = num;
    int i = 0;
    res[i] -= 1;
    while (i < res.size() && res[i] < 0) {
        res[i] += 10;
        i++;
        res[i] -= 1;
    }
    if (res.size() > 1 && res.back() == 0) res.pop_back();
    return res;
}

// 大整数除以2
vector<int> divide_by_two(const vector<int>& num) {
    vector<int> res;
    int carry = 0;
    for (int i = num.size() - 1; i >= 0; --i) {
        int current = carry * 10 + num[i];
        res.push_back(current / 2);
        carry = current % 2;
    }
    reverse(res.begin(), res.end());
    while (res.size() > 1 && res.back() == 0) res.pop_back();
    return res;
}

int main() {
    int n;
    cin >> n;
    // 构造10^(n-1),低位在前存储
    vector<int> pow10_n_1(n, 0);
    pow10_n_1[n-1] = 1;
    // 计算第一个项:9*10^(n-1)
    auto term1 = multiply(pow10_n_1, 9);
    // 计算第二个项:11*10^(n-1) -1
    auto temp = multiply(pow10_n_1, 11);
    auto term2 = subtract_one(temp);
    // 两个大整数相乘
    vector<long long> temp_res(term1.size() + term2.size(), 0);
    for (int i = 0; i < term1.size(); ++i) {
        for (int j = 0; j < term2.size(); ++j) {
            temp_res[i+j] += (long long)term1[i] * term2[j];
        }
    }
    // 处理乘积的进位
    vector<int> product;
    long long carry = 0;
    for (long long num : temp_res) {
        long long total = num + carry;
        product.push_back(total % 10);
        carry = total / 10;
    }
    while (carry > 0) {
        product.push_back(carry % 10);
        carry /= 10;
    }
    // 除以2得到最终结果
    auto sum = divide_by_two(product);
    // 逆序输出结果
    for (int i = sum.size() - 1; i >= 0; --i) {
        cout << sum[i];
    }
    cout << endl;
    return 0;
}

该实现没有任何外部依赖,只要内存足够,支持的n值可以达到非常大的量级。

补充注意点

不要用pow函数计算整数次幂,浮点数的精度限制会导致n≥17时计算的10^n就已经出现误差,用循环乘法或者大整数幂运算更可靠;另外等差数列的项数和首末项之和必然是一奇一偶,因此除以2的时候不会出现小数,不需要额外处理余数问题。

内容的提问来源于stack exchange,提问作者SmallTimeCppUserr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 20:57:00