【问题标题】:GMP most significant digitsGMP最高有效位
【发布时间】:2015-03-25 22:02:28
【问题描述】:

我正在使用 GNU 多精度 (GMP) 库对任意精度整数执行一些计算。然后我需要结果的十进制数字。但不是全部:只是,比方说,一百个最重要的数字(即数字开头的数字)或数字中间的选定数字范围(例如,1000 中的数字 100..200 -数字)。

在 GMP 中有没有办法做到这一点?

我在文档中找不到任何函数来提取一系列十进制数字作为字符串。将mpz_t 转换为字符串的转换函数总是转换整个数字。只能指定基数,不能指定起始/结束数字。

除了将整个数字转换成一个巨大的字符串,只取出一小部分并丢弃其余部分之外,还有什么更好的方法吗?

编辑:我需要的不是控制我的数字的精度或将其限制为特定的固定位数,而是从任意数量的数字字符串中选择一个数字子集精度。

这是我需要的示例:

71316831 = 19821203202357042996...2076482743

实际号码有 1112852 位,我将其收缩为 ...
现在,我只需要这个庞大的数字字符串中任意选择的子字符串。例如,十个最重要数字(在本例中为1982120320)。或者从 1112841th 到 1112849th 的数字(在这种情况下为21203202)。或者只是 1112841th 位置的一个数字(在本例中为2)。

如果我首先使用mpz_get_str 将我的 GMP 数字转换为十进制数字字符串,我将不得不为这些数字分配大量内存,仅使用其中的一小部分并丢弃其余数字。 (更不用说二进制表示的原始mpz_t 数字已经吃掉了很多。)

【问题讨论】:

  • 我已经将结果计算并分配为二进制表示。我现在唯一需要的是提取其数字范围。我不会对这个数字做任何额外的计算,所以这里对速度的担忧是无关紧要的。如果需要,提取这些数字甚至可能需要几分钟,我不在乎,我只需要以某种方式获取它们。但由于答案似乎开始偏离目标,我想没有办法做到这一点(因为人们通常会尽其所能避免手头的问题并开始挑剔一些不相关的部分)。
  • 另外,分配 1MB 可能是可以忍受的,但我并没有说我想停留在这么大的数字上。 “任意精度”通常意味着它们在需要时可以更大,然后它可能开始成为问题。

标签: c gmp arbitrary-precision significant-digits


【解决方案1】:

我认为你不能在 GMP 中做到这一点。但是你可以使用Boost Multiprecision Library

根据数字类型,精度可能是任意大的(仅受可用内存限制),在编译时固定(例如 50 或 100 个十进制数字),或在运行时控制的变量-成员函数的时间。这些类型启用了表达式模板,以提供比简单的用户定义类型更好的性能。

强调我的

另一种选择是ttmath 类型为ttmath::Big<e,m>,您可以控制所需的精度。只要您只需要最高有效数字,任何固定精度类型都可以工作,因为它们都会像floatdouble 一样删除低有效数字。这些数字不会影响结果的高位,因此可以安全地省略。例如,如果您需要高 20 位,则使用可以存储 20 位及更多位的类型,以便为以后正确舍入提供足够的数据

为了演示,让我们以 77 = 823543 的简单示例为例,您只需要前 2 位数字。使用 4 位类型进行计算你会得到这个

  • 75 = 16807 => 舍入到 1681×10¹ 并存储
  • 75×7 = 1681×101×7 = 11767*10¹ ≈ 1177×102
  • 75×7×7 = 1177×102×7 = 8232×102

正如您所见,即使不需要获得完整的确切结果,顶部的数字也是相同的。使用 GMP 计算全精度不仅浪费大量时间,而且还浪费内存。考虑一下在 2 个 bigint 上存储另一个操作的结果以获得所需数字所需的内存量。通过固定精度而不是将其设置为无限,您将显着降低 CPU 和内存使用率。

如果您需要 100th 到 200th 高位数字,则使用有足够空间容纳 201 位或更多位的类型,并在计算后提取这 101 位数字.但这会更加浪费,因此您可能需要更改为任意精度(或固定精度)类型,该类型使用 10 次方的基数 作为其四肢(我使用的是 GMP 表示法这里)。例如,如果类型使用基数 109,则每个肢体代表十进制输出中的 9 位数字,您可以直接获得十进制中的任意数字,而无需从二进制到十进制的任何转换。这意味着字符串的零浪费。我不确定哪个库使用 base 10n,但您可以查看使用 base 109write it yourselfMini-Pi 的实现。这样它也可以有效地获得高位数

【讨论】:

  • @Vĩnh PhúcL 我不是在谈论将 precision 限制为固定位数。我说的是从数字字符串中的随机位置读取一个数字或一系列数字。我在我的问题中添加了一个我需要的示例。
  • 您是否建议从整数运算切换到浮点运算?请注意,有许多数字不能有限地表示为浮点表示,例如1/10 或 1/3,当一个人尝试这样做时,会出现舍入错误。 (PS:我不能用 StackOverflow 引用你的昵称 - 由于非标准字符,它会从评论中删除它。)
  • 只需按“at sign”,然后按Tab。如果您使用整数算术,那么您的值中没有 1/10 或 1/3。那么你为什么要关心这个呢?对于大的正指数,则该值始终为整数
  • 其实你应该认为它是一个带刻度的int,而不是一个浮点值
  • @L:很好的比喻!谢谢。关于分数的好点。至于“标签”技巧......这就是重点:它不起作用。它只是将焦点移动到“添加评论”按钮。
【解决方案2】:

如果您事先知道x = 7^1316831 的十进制位数,例如 1112852。那么您会得到更低的位数,例如 10 位数:

x % (10^10),前 20 位数字为:

x / (10^(1112852 - 20)).

注意,我得到的是19821203202357042995 后者;最后是5,而不是6

【讨论】:

  • 谢谢,虽然我知道模数的技巧(我已经用它来提取 least 有效数字)和除法,但我希望我已经可以使用结果计算以某种方式使用 GMP 的功能提取其数字。但无论如何,谢谢,如果唯一的方法是一些巧妙的算法来移动和掩盖十进制数字,那么我会这样做。谢谢你的主意。是的,我预先知道位数(例如,我可以计算十进制对数并将其整个部分加 1)。
  • 感谢NULL 的提示。它可能会节省一些不需要的计算(除非 GMP 在内部无论如何都会这样做以获取位数)。
  • @SasQ - 对不起,我错了。如果str == NULL,它分配一块内存并执行完全转换。你想要 mpz_sizeinbase ,它本质上就是你正在做的事情。
  • @SasQ 以更高的精度 (98*65 = 6370) 执行此操作并正确舍入结果,您将获得期望值 (6)
  • 坦克,这似乎是解决这个问题的更好方法,而不是计算整个数字只是为了得到它的一些数字。现在我只需要想办法将它推广到其他算术运算(尤其是求幂),而不会涉及太多的计算复杂性......
猜你喜欢
  • 2021-11-12
  • 1970-01-01
  • 2020-09-07
  • 2013-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多