【问题标题】:How are floating point operations emulated in software? [closed]如何在软件中模拟浮点运算? [关闭]
【发布时间】:2016-10-01 19:39:17
【问题描述】:

当 CPU 没有(或有问题的)浮点单元时,软件如何执行浮点运算?例如 PIC、AVR 和 8051 微控制器架构。

【问题讨论】:

  • “模拟”?在 X86/64 CPU 上根本没有。你心目中的拱门是什么?
  • 我在谈论 PIC、AVR、8051 微控制器
  • 这发生在你告诉我们拱门之前。理想情况下,您应该在问题本身中包含这些信息。
  • @deviantfan:对于任何听说过“hardfloat”与“softfloat”的人来说,很明显他说的是后者。如果您知道它属于这两个类别中的哪一个,那么确切的架构并不重要。此外,人们确实会在 x86 上模拟浮点,例如避免famous Pentium floating-point division bug
  • @BenVoigt:您的密码学示例不是仿真; PIC、AVR 或 8051 上也没有任何 FP 实现;这些都没有定义 FPU,也没有 FPU 指令,所以没有什么可以模拟。仿真用于定义 FPU 但可能不存在 FPU 的架构,以便在缺少 FPU 的目标上处理包含 FPU 指令的二进制文件。因此,根据定义,您无法在这些架构上模拟 FPU;您只能实现浮点运算。实施不是模拟。

标签: floating-point embedded fpu


【解决方案1】:

“仿真” 在 PIC、AVR 和 8051 的上下文中是错误的术语。浮点仿真是指在具有FPU 选项,但并非所有部件都包含 FPU。这允许包含浮点指令的二进制文件在没有 FPU 的变体上运行。在使用时,FPU 仿真被实现为 invalid-instruction 异常处理程序;当遇到 FPU 指令但不存在 FPU 时,会发生异常,处理程序读取指令值并在软件中执行操作。

但是,您列出的架构都没有定义 FPU 或 FPU 指令,因此没有什么可以模拟的。相反,在这些情况下,浮点运算完全在软件中实现,编译器生成代码以根据需要调用浮点例程。例如,表达式x = y * z ; 将生成等效于函数调用x = _fmul( y, z ) ; 的代码。事实上,如果您查看包含浮点运算的构建的链接器映射输出,您可能会看到例行符号名称,例如 _fmul_fdiv 等 - 这些函数是 固有的编译器。

【讨论】:

  • 在机器码层面,你是对的;这些架构没有要模拟的浮点指令。但是这个问题是关于 C++ 的,而不是关于汇编的,并且 C++ 某些 确实 提供了作为内置函数的浮点运算。正是这种内置的性质被模仿。关于指令模拟的快速说明——无效指令处理程序是最直接的方法,但其他方法也是可能的,例如即时binary translation
  • @BenVoigt:在所有 C++ 问题中都没有提到特定语言,虽然我在 AVR 上使用过 C++,但它在 PIC 和 8051 上并不常用或广泛使用。我不会打电话无论如何,这种“仿真”。有许多运算符不能直接转换为单个指令;在 16 位和 32 位整数运算的 8 位目标上 - 您不会将这些实现称为“仿真”。通过多条指令或子程序调用实现运算符不是仿真。不管你怎么看,它都是错误的术语。
  • C++ 肯定会被提及,直到 Olaf 删除它。
  • @BenVoigt:很公平,但我建议将其删除,因为它是相关的。使用 C++ 并没有改变仿真的意义。
【解决方案2】:

浮点数只是以 2 为底的科学记数法。尾数和指数都是整数,softfloat库会将浮点运算分解为影响尾数和指数的运算,可以使用CPU整数支持。

例如,(x 2n) * (y 2m) = x * y 2n+m

通常还需要一个规范化步骤来保持浮点表示规范,但在规范化之前可能会执行多个操作。此外,由于 IEEE-754 存储带有偏差的指数,因此必须考虑这一点。

【讨论】:

  • 谢谢。使用定点数学并将浮点数转换为定点数学有什么意义,而微控制器没有 FPU。
  • @AhmedSaleh:这个答案无疑是您认为您提出的问题的答案,并(简要地)解释了如何在软件中实现 FP 操作,但那是不是仿真;指定的目标不支持仿真,因为它们没有要仿真的 FP 指令。
  • @AhmedSaleh:您关于浮点数与定点数的问题值得提出一个不同的问题(尽管 SO 上可能已经存在这样的问题)——简而言之,对整数实现定点运算处理器需要更少的指令,并且比软件实现的浮点更快、更具确定性。另一方面,浮点支持更宽的值范围、更少的位。
【解决方案3】:

浮点不是“模拟”的。一般来说,它们的存储方式如IEEE754 中所述。

定点是一种不同的实现类型。数字 2,54 可以用定点或浮点实现。

软件实现VS FPU(浮点单元)

一些现代 MCU,如 ARM cortex M4F 有一个浮点单元,可以比软件更快地在硬件中进行浮点运算(如乘法、除法、加法)。

在 AVR、PIC 和 8051 等 8 位 MCU 中,操作仅在软件中完成(一个除法可能需要多达数百次操作)。它将必须分别处理尾数(分数)部分和指数部分以及所有特殊情况(例如 NaN)。编译器通常有许多例程来威胁相同的操作(例如除法),并且会根据优化(大小/速度)和其他参数(例如,如果它知道数字总是正数...)来选择。

【讨论】:

  • 我使用过软件 IEEE754 库。 “soft-float”通常被称为浮点协处理器电路的“仿真”。
  • @BenVoigt 您认为有人总是使用 FPU,我更习惯于 8 位 MCU(对我来说,HW 浮点是“特殊”情况)。最初的问题不是很清楚,我没有回答我的理解(在您编辑之前)。
  • 哪里声明浮点需要 IEEE754 实现甚至格式。特别是对于 MCU,通常会使用其他格式。
【解决方案4】:

another SO question 涵盖了 C/C++ 标准对浮点数的要求。因此,严格来说,浮点数可以表示为编译器喜欢的任何形式。但实际上,如果您的浮点实现与IEEE754 有很大不同,那么您可以预料到很多错误是由习惯于 IEEE754 的程序引起的。并且编译器必须对程序员友好,并且不应该在利用未指定的标准位置时造成麻烦。因此,在大多数情况下,浮点数的表示方式与它们在所有其他架构(包括 x86)上的表示方式相同。定点算法太不一样了。

如果 AVR 和 PIC 的编译器知道没有可用的 fpu,那么它会将每个操作转换为 CPU 支持的一堆命令。它将必须将两个操作数归一化为一个共同的指数,然后像对整数一样对尾数执行运算,然后调整指数。这是相当多的操作,因此模拟浮点数很慢。而且,除此之外,如果优化大小,每个浮点运算都可能成为函数调用。

在 ARM 架构上,事情可能很奇怪。有带 FPU 和不带 FPU 的 ARM。而且您可能希望拥有可以在两者上运行的通用应用程序。在这种情况下,有一个棘手(且缓慢)的方案。应用程序使用 FPU 命令。如果您的 CPU 没有 FPU,则此类命令将触发中断,并且操作系统将在其中模拟指令,清除错误位并将控制权返回给应用程序。但是该方案发生得很慢并且不常用。

【讨论】:

  • 加法和减法需要一个共同的指数,但并非所有运算都需要。
猜你喜欢
  • 1970-01-01
  • 2011-05-02
  • 2012-03-19
  • 1970-01-01
  • 2016-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-25
相关资源
最近更新 更多