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

Rust与Go大整数除法结果差异原因及对齐方法问询

大整数除法:Rust与Go的取整差异及对齐方案

问题重现

当处理负数被除数的大整数除法时,Rust(使用num_bigint::BigInt)和Go(使用math/big.Int)的运算结果存在明显差异:

Rust 测试代码

use num_bigint::BigInt;
use std::str::FromStr;

fn main() {
    let n = BigInt::from_str("-4068122527548036313624952687320999183219209139149389824425650628448701979991259532638609685663741905551578447595775644964695361846038949186131821248175179900695219937607954907860922507949244416").unwrap();
    let d = BigInt::from_str(
        "115792089237316195423570985008687907852837564279074904382605163141518161494337",
    ).unwrap();
    let res = &n / &d;
    println!("res:{}", res);
}

Go 测试代码

package main

import "math/big"

func main() {
    var n, d, res big.Int
    n.SetString("-4068122527548036313624952687320999183219209139149389824425650628448701979991259532638609685663741905551578447595775644964695361846038949186131821248175179900695219937607954907860922507949244416", 10)
    d.SetString("115792089237316195423570985008687907852837564279074904382605163141518161494337", 10)
    res.Div(&n, &d)
    println("res:", res.String())
}

输出结果

  • Rust:-35132991850681684771865987637349505035135798334672277824131793024179346079627919418184483600280933255791109974931548(向零取整)
  • Go:-35132991850681684771865987637349505035135798334672277824131793024179346079627919418184483600280933255791109974931549(向负无穷取整)

差异原因

两种语言的大整数除法采用了不同的取整规则,这是语言设计阶段的明确决策:

  • Rust:num_bigint::BigInt的除法遵循向零取整(截断除法),直接舍弃小数部分,结果符号与被除数一致,和C、Python 2.x的整数除法行为对齐。
  • Go:math/big.Int.Div遵循向负无穷取整(地板除法),结果是小于等于真实商的最大整数,余数符号始终与除数一致,和Python 3+、Haskell等语言的规则一致,能保证a = (a/b)*b + a%b恒成立。

对齐方案

可以通过手动调整逻辑,让两种语言的除法行为统一到任意一种规则下:

方案1:统一为向负无穷取整(对齐Go的行为)

在Rust中,使用num_integer crate提供的div_floor方法,直接实现向负无穷取整的除法:

use num_bigint::BigInt;
use num_integer::Integer;
use std::str::FromStr;

fn main() {
    let n = BigInt::from_str("-4068122527548036313624952687320999183219209139149389824425650628448701979991259532638609685663741905551578447595775644964695361846038949186131821248175179900695219937607954907860922507949244416").unwrap();
    let d = BigInt::from_str("115792089237316195423570985008687907852837564279074904382605163141518161494337").unwrap();
    let res = n.div_floor(&d);
    println!("res:{}", res);
}

方案2:统一为向零取整(对齐Rust的行为)

在Go中,手动调整Div的结果:当被除数和除数符号不同且余数不为0时,将结果加1抵消地板除法的向下取整:

package main

import "math/big"

// divTowardsZero 实现向零取整的大整数除法
func divTowardsZero(n, d *big.Int) *big.Int {
    res := new(big.Int).Div(n, d)
    // 仅当被除数与除数符号不同,且余数不为0时调整结果
    if n.Sign() != d.Sign() {
        rem := new(big.Int).Rem(n, d)
        if rem.Sign() != 0 {
            res.Add(res, big.NewInt(1))
        }
    }
    return res
}

func main() {
    var n, d big.Int
    n.SetString("-4068122527548036313624952687320999183219209139149389824425650628448701979991259532638609685663741905551578447595775644964695361846038949186131821248175179900695219937607954907860922507949244416", 10)
    d.SetString("115792089237316195423570985008687907852837564279074904382605163141518161494337", 10)
    res := divTowardsZero(&n, &d)
    println("res:", res.String())
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 23:14:52