软件中如何模拟浮点运算?

4

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


1
“Emulated”?在X86/64 CPU上完全不需要。你心中有哪种架构? - deviantfan
1
我在谈论PIC、AVR、8051微控制器。 - andre_lamothe
2
@deviantfan:对于听说过“hardfloat”和“softfloat”的人来说,很清楚他在谈论后者。如果你知道它属于这两个类别中的哪一个,那么确切的架构就不重要了。此外,人们确实会在x86上模拟浮点运算,例如为了避免著名的奔腾浮点除法错误 - Ben Voigt
另一种需要在软件中实现浮点运算的情况是当需要比硬件FPU支持的精度更高时。一些椭圆曲线密钥加密操作需要高精度浮点实现。 - Ben Voigt
4
@BenVoigt:你所举的加密学例子并非“仿真”;同样,PIC、AVR或8051上的任何FP实现也不是;它们都没有定义FPU或具有FPU指令,因此没有什么可“仿真”的。仿真是用于定义了FPU但目标系统中可能不存在FPU以处理包含FPU指令的二进制文件的体系结构。因此,根据定义,你无法在这些体系结构上模拟FPU;你只能简单地实现浮点运算。实现并非仿真。 - Clifford
显示剩余2条评论
4个回答

3
在PIC、AVR和8051的上下文中,“模拟”是一个错误的术语。浮点“模拟”是指在具有FPU选项但并非所有部件都包含FPU的架构上模拟FPU硬件。这允许包含浮点指令的二进制文件在不带FPU的变体上运行。如果使用,FPU模拟将被实现为“无效指令异常处理程序”;当遇到FPU指令但不存在FPU时,会发生异常,并且处理程序读取指令值并使用软件实现操作。
然而,在你列出的所有架构中都没有定义FPU或FPU指令,因此没有什么需要模拟。相反,在这些情况下,浮点运算完全由软件实现,编译器生成调用浮点例程的代码。例如,表达式“x = y * z;”将生成等效于函数调用“x = _fmul(y, z); ”的代码。事实上,如果查看包含浮点运算的构建的链接器映射输出,您可能会看到诸如“_fmul”、“_fdiv”之类的例程符号名称 - 这些函数对编译器是内在的。

1
在机器码级别上,你是正确的;这些架构没有浮点指令可以模拟。但是这个问题是关于 C++ 的,而 C++ 提供了浮点操作作为内置功能。正是这种内置特性被模拟。关于指令模拟的一个快速说明——无效指令处理程序是最直接的方法,但还有其他方法可用,例如即时二进制转换 - Ben Voigt
1
@BenVoigt:问题中没有提到任何特定的语言,尤其不是C++。虽然我在AVR上使用过C++,但它在PIC和8051上并不常用或广泛可用。无论如何,我也不会称之为“仿真”。有许多运算符不能直接转换为单个指令;在8位目标上,16位和32位整数操作也是如此 - 您不会将这些实现称为“仿真”。通过多个指令或子例程调用来实现运算符并不是仿真。无论从哪个角度看,这都是错误的术语。 - Clifford
1
C++ 在 Olaf 移除它之前肯定被提到过。 - Ben Voigt
@BenVoigt:说得很好,但我认为它被删除是因为它是相关的。使用C++并不改变模拟的含义。 - Clifford

0

浮点数只是以2为底的科学计数法。尾数和指数都是整数,softfloat库将把浮点部分操作分解成影响尾数和指数的操作,这些操作可以使用CPU整数支持。

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

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


谢谢。使用定点数学并将浮点数转换为定点数学的重点是什么,而微控制器没有FPU呢? - andre_lamothe
1
@AhmedSaleh:毫无疑问,这个答案回答了你所认为的问题,并简要解释了FP操作如何在软件中实现,但这不是仿真;指定的目标不能支持仿真,因为它们没有需要仿真的FP指令。 - Clifford
1
@AhmedSaleh:关于浮点数和定点数的问题,值得发表一个不同的问题(虽然可能已经有这样的问题在SO上了)- 简而言之,在整数处理器上实现定点运算需要更少的指令,速度更快,更具确定性,而软件实现的浮点数则支持更广泛的值范围,且所需位数更少。 - Clifford

-2

浮点数并非“模拟”。通常情况下,它们是按照IEEE754中所解释的方式存储的。

定点数是一种不同的实现类型。数字2.54可以使用定点数或浮点数来实现。

软件实现与FPU(浮点运算单元)

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

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


1
我使用了IEEE754软件库。 "soft-float"通常被称为浮点协处理器电路的“仿真”。 - Ben Voigt
@BenVoigt,你的观点是一个总是使用FPU的人的观点,而我更习惯于8位MCU(对我来说,硬件浮点数是“特殊”情况)。原始问题不是很清楚,我在你编辑之前回答了我的理解。 - Julien
1
浮点数需要IEEE754实现或格式,这一点需要明确。特别是对于微控制器而言,通常会使用其他格式。 - too honest for this site

-2

有一个另一个SO问题涵盖了C/C++标准对浮点数的要求。严格来说,浮点数可以以编译器喜欢的任何形式表示。但是实际上,如果您的浮点实现与IEEE754显著不同,则可以预期由于程序员习惯于IEEE754而导致许多错误。编译器必须友好于程序员,并且不应通过利用标准中未指定的位置来制造麻烦。因此,在大多数情况下,浮点数将以与所有其他架构(包括x86)相同的方式表示。固定点算术则完全不同。

在AVR和PIC的情况下,编译器知道没有可用的FPU,因此它将把每个单独的操作转换为CPU支持的一堆命令。它将必须将两个操作数归一化到公共指数,然后像整数一样在尾数上执行操作,然后调整指数。这是相当多的操作,因此模拟浮点数很慢。而且,除此之外,如果您优化大小,则每个浮点操作可能会变成函数调用。

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


3
加法和减法需要具有相同的指数,但并非所有操作都需要。 - Ben Voigt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接