我正在使用Atmel Studio中的ATmega328P,我必须制作一个函数/算法,它需要一个8位数并计算它的平方根。结果必须在两个寄存器中给出,一个用于整数部分,另一个用于小数部分。
我在考虑这个问题:根必须介于给定数字和0(或1)之间。所以我会lsr(除以2)它会检查它是否更大,更小或相等,然后再以更高的精度再次尝试,因此它会变得越来越精确。
问题是整数不正确,而且我不知道如何把它放到代码中,因为我是一个新的程序集。我也可以发布到目前为止我发布的内容。
感谢您提供任何建议和帮助。
答案 0 :(得分:0)
仅仅为了完整性(或无用的展示),这里是如何通过线性搜索(在大多数情况下0-15值仍然比二进制更快的情况下)仅使用整数进行任务,而不是乘法用乘法搜索。)
root = -1
square = 0
addValue = 1
while (square <= input) {
square += addValue
addValue += 2
++root
}
; here root == trunc(sqrt(input))
所以,如果你不需要小数部分,这就足够了,或者你可以使用至少256B长的LUT作为小数部分,以及它。
用8位整数寄存器编写正确的小数sqrt实际上是相当有用的,我不会带走你的所有乐趣。 :P ..
检查各种算法,不要忘记通过乘以某个“base_exp”值可以将有限的小数范围转换为整数。
即。通过执行* 100(0-1599)可以将0.00到15.99之间的值转换为11位整数,并且(100 * 100)的sqrt为100,因此通过输入* 10000,您将获得值0-2550000(至少需要) 22位,将其四舍五入到24b),然后执行整数平方根将得到结果* 100(并且适合11位),因此您可以通过除以100进一步将其拆分为两个值。
对于人类来说这可能看起来很简单,但在现实世界中,当使用8 / 16b寄存器进行十进制计算时,通常是通过这个原理来完成的,而是使用了2的幂,即* 256 * 256,这可以简单地完成通过向左移动16位值。除以256将值向右移动8。
因此对于具有二进制数的每位数方法,您需要创建24位加法/减法/移位器代码片段。然后输入的数字是24位数的最高8位。 (即输入值10
=&gt; (10<<16) == 0x0A0000
)=&gt;简单的转移。计算其中的sqrt(0x0329或0x032A,取决于你是设法截断,还是在最后一位进行舍入),就是这样,结果肯定会适合12位,而上面4则是整个0-15部分,低8位是“量1/256”值(0x29 / 256 = 0.16015625)的小数。这可以通过简单的移位/和重新分割,即不需要mul / div操作。
所以它仍然有很多工作,但它是合理的(在8b CPU上进行24位乘法/除法比做加/子/移位扩展要痛苦得多)。并解释为什么选择4:8 fixed-point格式的结果,从结果的小数部分使用完整的8位精度,并使其更容易进行进一步的二进制计算。 (在8:8固定点0.5 = 0x0080 ...尝试添加它,看看会发生什么:0x0080 + 0x0080 = 0x0100 = 1.0没有任何复杂的篡改结果..这就是我们如何在8位CPU上进行低精度十进制计算例如,对于sin / cos效应,乘法/除法也更简单,同样适用于0.5:0x0080 * 0x0080 =(0x4000&gt;&gt; 8)= 0x0040 = 0.25)。