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




