【问题标题】:Why is Dart BigInt overflowing?为什么 Dart BigInt 会溢出?
【发布时间】:2021-10-28 10:53:05
【问题描述】:

docs 中明确表示

第三个整数表示,bigint,包含一个任意大的有符号整数。

是的,如果我这样做了

BigInt.parse('1401361620244348303075010764053798750806699051384896657186984262080729392169468490123546840166223286924678557627464612464171446377618435568706501027067406794991226499183297227160622976110894228304766631654633074535516079503916674556805715032127374387087475009709090')

那确实有效。

但是当我创建一个 BigInt.from(0) 并重复添加一些东西以转换这个 base64 编码的数字时

EwnG/GyyyZR6cgLrLuY+cvvRMlNqIr0GgyqWYmrpvsWwNbVcRQ7FWJFuGWFON81W7FbX0wMyjRV7WsMmk0zisj2baRl3v3Y1LPA8ncXU9vVfqCyeXVmUgv1T9wi1k41Zjr6h7WTjZJvyQC4YpaYpZdOJcuYm8yVOlfUKJ10lm2p9yxPJLtStvwJFZy4uCF2p/sfDATIv9Vyny3Ewx/B85Ae+eg2nlRcDmZdu5ByoqOfEYaU6H1fzzHvUSUBZvHv9zBLQ6PrLG6DhYhXzxol3zpbV02NGq3WfeBLhfl4DOUiVEDi0HSLw3xyJU+rw8rS1hoQeYcyogZ8p0I3BiNRs1Q==`, 

对于 BigInt,它很快就会溢出:

...
543848068542839930
1120308820846263418
3426151830059957370
-5797220206794818438
-5797220206794818438
-5797220206794818438
...

然后卡在-5797220206794818438。为什么会这样,然后如何将 base64 编码的数字转换为 BigInt?我很困惑。

这是将base64转换为BigInt的代码:

/// Bytes are assumed to be BigEndian.
BigInt bytesToBigInt(List<int> bytes) {
  BigInt result = BigInt.from(0);
  int e = 0;
  for (int i in bytes.reversed) {
    for (int c = 0; c < 8; c++) {
      int include = i & 1;
      i = i >> 1;
      e++;
      if (include == 1) {
        final val = pow(2, e);
        result += BigInt.from(include * val);
        print(' $result');
      }
    }
  }
  return result;
}

【问题讨论】:

  • pow(2, e) 最终不会溢出吗?您可能应该使用BigInt.pow。此外,如果您正在处理字节列表,那么您可以一次移动和累积 8 位,而不是单独处理每个位。此外,BigInt supports bitwise operators.
  • 如果要避免溢出,则需要在所有中间计算中避免溢出...。如果你做的事情可能会溢出,仅仅有一个不溢出的结果是不够的。
  • 天哪!感谢@jamesdlin 和 underscore_d,尽管在这里坐了 2 个小时,但我不知何故对此完全视而不见。天哪,这让我感到头疼。
  • 我不确定是现在删除这个问题还是回答它......

标签: dart integer-overflow bigint


【解决方案1】:

您的具体问题是由使用pow(2, e)(一旦e 变大很容易溢出)而不是BigInt.pow(2, e) 引起的。

此外,您的bytesToBigInt 实现似乎比必要的复杂。正如我在评论中指出的那样,如果您正在处理字节列表,则处理每个位都是浪费的,并且BigInt 直接支持按位运算符,因此从字节序列创建BigInt 可能很简单:

/// Creates a [BigInt] from a sequence of [bytes], which is assumed to be in
/// big-endian order.
BigInt bytesToBigInt(Iterable<int> bytes) {
  BigInt result = BigInt.zero;
  for (int byte in bytes) {
    result = (result << 8) | BigInt.from(byte);
  }
  return result;
}

或:

BigInt bytesToBigInt(Iterable<int> bytes) => bytes.fold(
      BigInt.zero,
      (resultSoFar, byte) => (resultSoFar << 8) | BigInt.from(byte),
    );

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-29
    • 2017-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-29
    • 1970-01-01
    • 2021-06-18
    相关资源
    最近更新 更多