You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Int64数学公式转BigInteger等效实现的技术求助

解决BigInteger计算溢出与结果不符的问题

我来帮你理清楚问题所在,以及怎么用BigInteger正确实现你想要的计算。

首先,先拆解你原来的需求:你要计算的是 (1 / price) * 10^18,这个式子等价于 10^18 / price——但直接用浮点数计算会遇到两个问题:一是价格过低时结果超过Int64的最大值(9,223,372,036,854,775,807)导致溢出;二是浮点数本身的精度损失会让结果有误差。

你尝试用BigInteger是对的,但之前的代码犯了一个关键错误:你把小数价格直接转成了一个大整数,丢失了它的小数比例关系。比如0.2015不是201500000000000000,而是2015/10000(分子2015,分母10000)。直接用1e18除以201500000000000000,本质上是在计算1e18 / 2.015e17,得到的结果自然和预期不符。

正确的实现思路

要避免精度损失和溢出,我们需要把小数价格转换为分数形式(分子+分母的整数对),然后用BigInteger做整数运算:
10^18 / price = 10^18 * 分母 / 分子

下面分两种场景给你代码示例:


场景1:从JSON获取价格字符串(推荐,无精度损失)

如果你的JSON返回的价格是字符串形式(比如"0.2015"),直接拆分整数和小数部分来构造分数:

// 从JSON中获取价格字符串(避免先转成double带来的精度损失)
string priceStr = jObject["market_data"]["current_price"]["usd"].ToString();

// 拆分整数和小数部分
var priceParts = priceStr.Split('.');
long numerator;
long denominator;

if (priceParts.Length == 1)
{
    // 价格是整数,比如"1"
    numerator = long.Parse(priceParts[0]);
    denominator = 1;
}
else
{
    // 拼接整数和小数部分作为分子,分母是10的小数位数次方
    numerator = long.Parse(priceParts[0] + priceParts[1]);
    denominator = (long)Math.Pow(10, priceParts[1].Length);
}

// 计算10^18 * 分母 / 分子
BigInteger tenTo18 = BigInteger.Parse("1000000000000000000");
BigInteger result = tenTo18 * denominator / numerator;

场景2:只能用double类型的价格

如果已经把价格转成了double,那我们需要尽量减少精度损失,把double转换为分数:

double price = jObject["market_data"]["current_price"]["usd"].Value<double>();

// 将double转换为字符串(保留17位小数,覆盖double的最大精度)
string priceStr = price.ToString("F17").TrimEnd('0').TrimEnd('.');
var priceParts = priceStr.Split('.');

long numerator = long.Parse(priceParts.Length == 1 ? priceParts[0] : priceParts[0] + priceParts[1]);
long denominator = priceParts.Length == 1 ? 1 : (long)Math.Pow(10, priceParts[1].Length);

BigInteger tenTo18 = BigInteger.Parse("1000000000000000000");
BigInteger result = tenTo18 * denominator / numerator;

验证你的测试案例

用0.2015来测试:

  • 分子是2015,分母是10000
  • 计算1e18 * 10000 / 2015 = 1e22 / 2015 ≈ 4967741935483970223,和你之前用Int64得到的结果接近(差异来自浮点数的精度损失)。

当价格是0.1时:

  • 分子是1,分母是10
  • 计算1e18 *10 /1 =1e19,这个值远大于Int64的最大值,但BigInteger可以轻松存储。

这样就完美解决了溢出和结果不符的问题啦!

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

火山引擎 最新活动