【问题标题】:Implementation of a floating point library of any precision任意精度浮点库的实现
【发布时间】:2019-04-02 15:52:15
【问题描述】:

我必须实现任何精度的浮点库,因此指数和尾数必须是无限正整数。稍后我必须使用处理器的 x86 功能创建加法和减法函数等。我必须使用 C++/C(我可以使用程序集插入),我可以使用现成的库。

一开始我有问题: 1. 用什么类型存储无限大的正整数? 2. 哪些库/函数可以让我使用处理器的功能并可以使用上述数据类型?

【问题讨论】:

  • 无限大的正整数世界上所有的计算都不足以存储无限大的正整数
  • 你为什么不使用现有的库——比如GNU GMP?从头开始自己编写类似的东西是一项大量(可能需要多年)的工作。
  • 1.您必须自己编写该类型。请注意,任意大的数字可能会消耗任意数量的内存。 2. 它们都以某种方式使用处理器的功能。但是你必须自己做所有的数学运算,在我所知道的任何处理器中都没有对任意精度浮点数学的内置支持。
  • @Amadeus 没有整数是“无限”大的。
  • 这是一个练习,还是用于生产?在后一种情况下,不要浪费你的时间去寻找一个现有的图书馆。寻找“任意精度数学”。我想到了 GMP 和 MPIR。

标签: c++ c assembly


【解决方案1】:
  1. 用什么类型来存储无限大的正整数?

整数向量。就像一个固定大小的整数由字节组成——它们本身就像更小的整数——这个大整数由更小的部分组成。然而,与固定大小的整数不同,向量可以任意增长(直到内存耗尽)。

您可以将向量包装在 C++ 中的自定义类型中,以提供面向对象的接口。

2. 哪些库/函数可以让我使用处理器的功能并可以使用上述数据类型?

如果您创建自定义类型,其他库将无法直接支持它。但是,如果您的类提供兼容的接口,则可以使用通用模板库。

例如,如果您提供比较运算符和赋值运算符,那么使用标准库中的std::sort 对自定义类对象进行排序应该没有问题。

我可以使用现成的库。

这通常是个好主意。我推荐它。

【讨论】:

  • 我知道我必须实现自己的类类型。我想我需要 3 个班级成员:符号、指数和尾数。符号只有 0 或 1。问题是如何存储指数和尾数。二进制记录如下所示: x xxx...xxx xxx...xxx x- 可以是 0 或 1 我想将符号用作字符串我也建议使用整数向量,但我的讲师说这不是最好的想法是稍后使用处理器机制来改进操作会出现问题。
  • @dida1007 并不明显你的教授提到的问题是std::vector 但不是std::string,我看到的主要区别是std::string 可能多一点方便 io,而 std::vector 可能更方便其他任何事情
【解决方案2】:

一个重要的考虑因素是您将使用什么基础来表示您的内部单位。正如其他人所说,这可能是单个单元的向量,然后您使用您在小学学到的那些“纸上”操作进行处理。也许是一个结构,它包含用于 mantassa 和 exponent 的单独向量以及用于它们每个符号的标志。但是这些单独的单元中发生了什么?

这种选择取决于这些操作的效率。

您可能会认为使用字符和以 10 为底的编码是最简单的编码方式,而且读取和写入函数非常简单!但实际上处理器在一次处理一个十进制字节时效率很低。不过,它非常适合读取数字!例如,做 56 * 37 将需要对“十进制”架构进行以下操作:

  • 6 * 7 -> 42
  • 42 / 10 -> ________ 4
  • 42 %10 -> ___________ 2*
  • 5 * 7 -> 35
  • 35 / 10 -> ______ 3
  • 35 %10 -> ________ 5
  • 6 * 3 -> 18
  • 18 / 10 -> ______ 1
  • 18 %10 -> ________ 8
  • 5 * 3 -> 15
  • 15 / 10 -> ____ 1
  • 15 %10 -> ______ 5
  • 4 + 5 + 8 -> 17
  • 17 / 10 -> ______ 1
  • 17 %10 -> ________ 7*
  • 3 + 1 + 5 + 1 -> 10
  • 10 / 10 -> ____ 1
  • 10 %10 -> ______ 0*
  • 1 + 1 -> 2
  • 2 /10 -> 0
  • 2 % 2 -> ____ 2*
  • 最终答案 __ 2 0 7 2

这是很多乘除运算,而且只有2位数!

您可能会认为使用整个字节 0-255 会更有效,而进行以 256 为基数的数学运算会更简单。尤其是当数字拆分 /10 和 %10 步骤变成简单的移位和掩码时!但是,在十进制显示中读取和写入任意长度的数字要困难得多,而且如果您决定使用以 2 为底的指数,那就更加困难了!

在 base 65536 中执行相同的数学运算效率更高,而在 64 位处理器上执行 base 4G 的数学运算效率更高,而打印的复杂性也不高。使用汇编器,您甚至可以使用 64 位存储和 128 位乘法运算!

每次将内部字长加倍时,乘法的部分运算次数就会减少 4,而除法的减少更为显着!

提高打印效率并保持数学合理有效的一种欺骗方法是将多个数字实际存储为每个存储单元中的二进制数。一个 32 位存储实际上可以在每个单元中保存一个最长为 9 位的整数。通过以 10 亿为底数进行数学运算,您只需每 9 位执行上述所有额外的数字拆分操作!

读取一个数字字符串涉及一次将 9 个数字读取到存储中,然后修复指数,我建议它仍然是 10 的幂。数字应始终以标准化的浮点格式在内部保存,其中只有一个小数点上方的数字(或者可能总是 0)。如果输入字符串在不同位置包含小数点,或者实际上是一个整数值,那么您可以通过摆弄指数值来修复它。数字始终以该格式或整数打印。这样,数字中未使用的数字始终位于最低有效单元的底部,如果它们为零,则它们是完全可用的。

在这个模式中,添加或减去 2 个具有不同指数的数字需要一些额外的工作,因为其中一个数字必须拆分为另一个数字的十亿对齐,然后才能求和,但加法仍然非常与乘法或除法相比,便宜。

将指数值本身读入保持向量很棘手,但也许您可以使用仅限于 64 位范围的指数,这意味着您不必对指数本身进行多字节操作?这允许数字高达 0.99E10sextillion(这是一个仅用于指数的 19 位数字),这对于大多数用途来说应该足够了。这假设指数仍然代表 10 的幂,这使得值的存储很方便,或者您可以以十亿的幂进行,“以指数方式”增加范围,但随后文本数字读取更加困难,因为读取数字必须重新对齐(类似于加/减预对齐的操作),但您也可以从不必进行加/减预对齐中受益。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多