我在上次采访中被问到这个问题并再次期待。采访是针对嵌入式系统编程的固件工程师。可用于这些应用的微处理器和微控制器通常不是很强大,而较简单的微控制器和微控制器没有能力进行浮点计算(内部没有乘法器或除法器)。
那么这个问题的可能答案是什么,以及定点运算与此有什么关系呢?
是否可以使用Newton-Raphson方法进行此计算?怎么样?
答案 0 :(得分:7)
与任何这样的面试问题一样,聪明的回答就是提出反问题。旨在澄清和消除问题的明智问题表明,您可以思考而不是简单地兜售所接受的智慧或教条,并且还会缩小问题的范围,以便您的答案更适合应用。在这种情况下,没有浮点的 MCU 和不使用浮点的软件实现之间可能存在区别。如果是后者,那么肯定定点是相关的,但在许多应用中,integer square根可能就足够了 - 你可能会问这个问题,但isqrt(2)== 1在这种情况下似乎是不合适的。对于前者,这种情况并不排除使用浮点。
通常,使用浮点时嵌入式系统中的问题是缺少浮点单元(FPU),导致在软件中实现的浮点运算要慢得多且不太确定。缺少FPU甚至硬件整数乘法或除法并不排除使用浮点数,它只是意味着这样的操作要慢得多并且需要更大的代码空间。
在大多数系统上,即使没有硬件浮点支持,标准库数学函数仍将由软件浮点支持,并且可以正常使用 - 即使在8位系统上 - 但不要期望Mega-FLOPS性能。在某些情况下,性能损失以及可能的库实现的非确定性本质会妨碍其使用,在这种情况下,有许多算法会返回更快或更确定的性能。
如果要生根的值很大且整数结果足够精确,那么纯整数解决方案将是最快的,但是对于一般情况,有一些解决方案,其中Newton-Raphson是一个,但不太可能是最优的 - 它是冒泡 - 一种平方根算法;因为它很容易教导和理解,而不是因为它的表现。
使用固定点是可能的,但不是固有数据类型,代码可能变得不那么容易编写和调试。我用library written by Anthony Williams;它是用C ++编写的,定义了一个fixed
类; C ++的函数和运算符重载功能意味着只需将float
或double
替换为fixed
即可移植大多数浮点代码。在ARM处理器上,fixed
类的执行速度比软件浮点快五倍。然而,安东尼的sqrt算法可以改进,正如我所描述的here基于文章 The Neglected Art of Fixed Point Arithmetic 的实现 - 该文章中的代码在C中,因此可能更适用通常(C ++不可用或不实用 - 尽管这是一个不同的论点!)。
Jack Crenshaw在他的书Math Toolkit for Real-Time Programming中专门用了sqrt()函数,在那里他以一个天真的Newton-Raphson实现开始并逐渐完善它。他也提出了一个整数解决方案,虽然有趣的是不是定点。杰克在书中所包含的一些内容已经出现在他的期刊文章中;例如他对integer square-root的处理。
不管怎样,我可以回答如下问题:
我会评估标准库软件的浮点性能,精度和对代码大小的影响,并且只有当我发现它不适合应用程序需求时才会考虑使用已建立的算法和可能的定点算法的优化解决方案
请注意我使用术语“已建立的算法”;它有用的事实是我可能不知道或回想起任何特定算法的名称,我真正说的是我不知道什么算法是合适的但我不愚蠢重新发明轮子,因为我不太可能想出一些比现有的东西更好的东西,通过仔细的研究和评估,如果可行的话,我会达到预期的效果。如果一位受访者提出了这个答案并提出了明智的问题,我会发现这不仅仅是可以接受的。当然,面试官可能不像你那么聪明,并且可能会有一个特别的答案,他认为他是“正确的”;你可能不想在一个有这种教条反应的组织中工作。面试是一个双向的过程 - 你正在面试组织,看看你是否想要给你的服务带来好处。
答案 1 :(得分:4)
是的,您可以使用Newton-Raphson计算平方根。通常它是这样做的:
设x为数字。我们将首先近似1 / sqrt(x),然后乘以x得到x / sqrt(x),即sqrt(x)。
给定x,创建1 / sqrt(x)的粗略估计值。通常,这是通过一个小的查找表完成的,但任何合理的估计都足够(包括1)。调用初始估计e 0 。
根据需要多次重复此步骤:从当前估计e i ,创建新估计e i + 1 = 1/2·e 我·(3-X·电子<子> I 子> 2 )。通常,所需步骤的数量可以通过数值分析,初始估计的质量1 / sqrt(x)以及应用所需的准确度预先确定。
最后,返回最后一个e i ·x作为sqrt(x)的估计值。
此序列收敛非常快,通常用于计算平方根。您可以从Wikipedia page on Newton’s method开始,了解如何推导出平方根倒数的序列。另请注意,它不使用除法,这通常是一个缓慢的操作。
您可以使用固定点进行这些计算,因为您需要比整数提供更多的精度,但浮点不可用。
基本上,采访者正在探究你是否有嵌入式处理器上数值算法的经验。
答案 2 :(得分:3)
ENIAC仅使用加法和减法取平方根。 基于公式,前n个奇数的总和是n平方。
要计算m的平方根,找到最小的整数n,使得前n个奇数的总和超过m。这可以通过从m中减去连续的奇数整数直到获得负结果来完成。如果n是最小整数,那么m - (1 + 3 + 5 + ... + 2n-1) < 0
则(n - 1)^2 <= m < n^2
。让a等于第n个奇数整数2n - 1
,求解
(n-1) <= sqrt(m) < n
a - 1 <= 2*sqrt(m) < a + 1
或
(a - 1)/2 <= sqrt(m) < (a + 1)/2
来源: http://www4.wittenberg.edu/academics/mathcomp/bjsdir/ENIACSquareRoot.htm
然而,这对m = 2并不适用,只适用于大数。