【问题标题】:Wrong logarithm of BigInteger when size of BigInteger exceeds ¼ gigabyte当 BigInteger 的大小超过 ¼ GB 时,BigInteger 的对数错误
【发布时间】:2013-01-18 16:08:31
【问题描述】:

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

  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,我们必须有一个零对数,对于介于01 之间的数字,我们必须有一个负对数(没有整数)。我上面的数字i1i2 大于1,因为按照惯例,当最高有效字节在0127 之间时,这意味着正BigInteger

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

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

PS!大小超过2 ^^ 31 位意味着BigInteger 的实际值超过2 ^^ (2 ^^ 31),或近似为circa 8.8E+646456992


更新:我向 Microsoft Connect 发送了 a bug report。阅读讨论后,我也意识到由于BigInteger 的设计和单个对象大小的上限为 2 GB,BigInteger 永远不会超过 2 GB(无论有多少内存你有)。因此,当BigInteher 介于 ¼ 和 2 GB 之间时,就会发生此错误。

【问题讨论】:

  • 32 位还是 64 位架构?
  • 这能回答你的问题吗? stackoverflow.com/questions/12003719/log-of-a-very-large-number 或者可能相关?
  • @Pete 很好的发现,但我认为这就是他初始化一个额外字节的原因。除非字节数组需要以某种方式以 1 成为符号字符的方式终止。
  • @Jeppe Stig Nielsen 你能告诉我们 log2 的实际输出是什么,还是每次都不一样?
  • @glace:当我测试它时,它似乎是可靠的-1313491238.4757

标签: c# .net biginteger logarithm base-class-library


【解决方案1】:

让我猜一下:值是

-1.3134912384757032e9

(计算对数时取模的微小变化)?

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

8*300000000 = 2400000000 > 2147483647

所以索引环绕为负数,即-1894967296,并且

-1894967296 * log 2 = -1.3134912384757032e9

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

【讨论】:

  • 其实我认为这是设计使然。你必须使用Array.CreateInstanceallocate an array taking up more space than int.MaxValue。但是,如果您确实将Array.CreateInstance 与长索引重载一起使用,由于per-object max size limit,您会得到OutOfMemoryException。因此,OP 创建的数组实际上甚至不是 300,000,001 元素。
  • 但这只是 bits 的数量超过了这个限制。该数组只需要大约 300MB,这根本不成问题。
  • 嗯。我敢打赌,内部发生了一些中间过程,它正在生成一个太大的对象。我的机器上有 6GB 的可用 RAM,所以它似乎应该可以工作。
  • 这个答案解释了发生了什么,我猜。我正在考虑提交该错误报告。该值是您引用的值(除了在我的示例中它被格式化为没有e9 符号的字符串,但您得到了正确的数字)。
  • @mellamokb 数组 3亿和1个元素(每个元素是一个字节)。所以它超过 2 GB,但不超过 2 GB(这个系数是 8,这就是我写 ¼ GB 的原因)。但是,如果内部使用的数组(BigInteger)限制为 2 GB,那么这就对BigInteger 的大小设置了有效限制,而我已经超过了该级别的八分之一(如果存在的话)。
猜你喜欢
  • 2011-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多