问题 当BigInteger的大小超过¼千兆字节时,BigInteger的对数错误


当我有一个 BigInteger 其大小超过2千兆位(即¼千兆字节;我通过反复试验找到了这个阈值),对数方法给出了错误的答案。这个简单的代码说明:

  byte[] bb;

  bb = new byte[150000001];
  bb[150000000] = 1;  // sets most significant byte to one
  var i1 = new BigInteger(bb);
  double log1 = BigInteger.Log(i1);
  Console.WriteLine(log1);   // OK, writes 831776616.671934

  bb = new byte[300000001];
  bb[300000000] = 1;  // sets most significant byte to one
  var i2 = new BigInteger(bb);
  double log2 = BigInteger.Log(i2);
  Console.WriteLine(log2);   // Broken, gives negative number, should be twice 831776616.671934

当然,我们必须有一个超过数字的正数日志 1,数字的零日志 1,以及之间数字的负数日志 0 和 1 (那里没有整数)。我的号码 i1 和 i2 以上都大于 1 因为按照惯例,当最重要的字节介于两者之间时 0 和 127,这意味着积极的 BigInteger

现在,如果您阅读了文档 BigInteger.Log,他们声称,如果对数“超出Double数据类型的范围”,它可能会抛出。现在,显然需要一台内存存储量超过的计算机 1E+300 字节,可观察的宇宙太小,不能包含这样的计算机,所以我想这绝不会发生。

那么为什么这不起作用呢?

PS!大小超过 2 ^^ 31 位意味着实际值 BigInteger 结束了 2 ^^ (2 ^^ 31)或大约 circa 8.8E+646456992


更新:我送了 一个错误报告 到Microsoft Connect。在阅读了讨论之后,我也意识到由于设计的原因 BigInteger 并且对于一个单个对象的大小,上限为2千兆字节 BigInteger 永远不会超过2千兆字节(无论你有多少内存)。因此,当这个错误发生时 BigInteher 介于¼和2千兆字节之间。


11747
2018-01-18 16:08


起源

32位还是64位架构? - DWright
这回答了你的问题了吗? stackoverflow.com/questions/12003719/log-of-a-very-large-number 或者也许相关? - Pete
@Pete很好找,但我认为这就是为什么他要初始化一个额外的字节。除非字节数组需要以某种方式终止字符,否则1将成为符号字符。 - B L
@Jeppe Stig Nielsen您能否告诉我们log2的输出实际是什么,或者每次都不同? - B L
@glace:看起来很可靠 -1313491238.4757 当我测试它。 - mellamokb


答案:


让我猜一下:价值是

-1.3134912384757032e9

(计算对数的模数变化很小)?

最高设置位的索引存储并传入 int,和

8*300000000 = 2400000000 > 2147483647

所以索引包裹到一个负数,即 -1894967296,和

-1894967296 * log 2 = -1.3134912384757032e9

哎呀。有人应该提交错误报告。


11
2018-01-18 17:09



实际上我认为这是设计的。你必须使用 Array.CreateInstance 至 分配一个占用更多空间的数组 int.MaxValue。但是,如果你使用 Array.CreateInstance 随着长指数超载,你得到一个 OutOfMemoryException 因为 每个对象的最大大小限制。因此,由OP创建的数组实际上不是偶数 300,000,001 首先是元素。 - mellamokb
但它只是数量 位 超过这个限制。该阵列只需要约300MB,这根本不应该是一个问题。 - Daniel Fischer
嗯。我敢打赌,内部存在一些中间产生的东西,它产生的对象太大了。我的机器上有6GB的可用内存,所以它看起来应该有效。 - mellamokb
我猜这个答案解释了发生了什么。我正在考虑提交错误报告。该值是您引用的值(除非它被格式化为没有的字符串 e9 在我的例子中的符号,但你得到了正确的数字)。 - Jeppe Stig Nielsen
@mellamokb数组 是 300万和1个元素(每个元素是一个字节)。所以它超过2千兆位,但不超过2千兆字节(这个因素是8,这就是我写¼千兆字节的原因)。但如果数组内部使用(通过 BigInteger)限制为2千兆字节,然后设置一个有效的限制 BigInteger 可以成为,我超过该级别的八分之一(如果它存在)。 - Jeppe Stig Nielsen