为什么 Dart BigInt 会溢出?
Why is Dart BigInt overflowing?
它在 docs 中明确表示
The third integer representation, bigint, holds an arbitrarily large signed integer.
是的,如果我这样做
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)
(一旦 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),
);
它在 docs 中明确表示
The third integer representation, bigint, holds an arbitrarily large signed integer.
是的,如果我这样做
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)
(一旦 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),
);