当前位置: 首页 > 知识库问答 >
问题:

armv6中log10数学函数在Raspberry Pi上的错误结果

易烨磊
2023-03-14

我有一个非常简单的代码:

#include <stdio.h>
#include <math.h>
int main()
{
    long v = 35;
    double app = (double)v;
    app /= 100;
    app = log10(app);
    printf("Calculated log10 %lf\n", app);
    return 0;
}

这段代码在x86上工作得很好,但在arm上不工作,arm的结果是0.00000。一些想法?

共有1个答案

岑叶秋
2023-03-14

ARM Linux发行版上的浮点支持并非微不足道。因此,您应该使用与您的系统相匹配的工具链,即操作系统和硬件,并使用正确的编译开关。

首先,您需要理解ARM的调用约定,它是关于“调用函数时参数是如何传递的?”。ARM是一个RISC架构,只能在寄存器上工作。没有直接操作内存的指令。如果您需要更改内存中的一个值,首先需要将其加载到寄存器中,修改它,然后将其存储回内存中。

当您调用一个函数时,您可能需要向它传递参数,您可以将参数放在堆栈(内存)上,但是由于ARM只能使用寄存器,您的函数可能首先要做的是将它们加载回寄存器。为了避免这种浪费,ARM调用约定使用寄存器传递参数。然而,由于ARM的寄存器数量有限,调用约定还要求您只对前四个参数使用前四个(r0-r3)寄存器,其余的仍然必须使用堆栈才能传递。

float pi2(float a) {
    return a * 3.14f;
}
00000000 <pi2>:
   0:   f24f 51c3   movw    r1, #62915  ; 0xf5c3
   4:   b508        push    {r3, lr}
   6:   f2c4 0148   movt    r1, #16456  ; 0x4048
   a:   f7ff fffe   bl  0 <__aeabi_fmul>
   e:   bd08        pop {r3, pc}

当浮动硬件支持添加到ARM时(同样是因为体系结构风格),它附带了自己的一组寄存器(s0、s1、...)。

如果我们用-c-o3-mfloat-abi=softfp编译相同代码段并转储,我们将得到

00000000 <pi2>:
   0:   eddf 7a04   vldr    s15, [pc, #16]  ; 14 <pi2+0x14>
   4:   ee07 0a10   vmov    s14, r0
   8:   ee27 7a27   vmul.f32    s14, s14, s15
   c:   ee17 0a10   vmov    r0, s14
  10:   4770        bx  lr
  12:   bf00        nop
  14:   4048f5c3    .word   0x4048f5c3

正如您现在所看到的,编译器没有创建对__AEABI_FMUL的调用,而是在将位于R0中的参数移动到S14并在S15上填充3.14之后创建一个vmul.f32指令。在乘法指令之后,它将S14中可用的结果移回R0,因为这个函数的任何调用者都希望得到它,因为调用约定。

然而,在保持简洁性的同时,这种方法引入了在ARM寄存器和FP寄存器之间移动值的开销。这显然会影响性能,并由一个新的调用约定解决,该约定由gcc称为hard。这个新约定声明,如果函数中有浮点参数,则可以使用与普通寄存器交织的浮点寄存器,并且可以返回浮点寄存器S0中的浮点值。

同样,如果我们用-c-o3-mfloat-abi=hard和dump编译代码段,我们将得到

00000000 <pi2>:
   0:   eddf 7a02   vldr    s15, [pc, #8]   ; c <pi2+0xc>
   4:   ee20 0a27   vmul.f32    s0, s0, s15
   8:   4770        bx  lr
   a:   bf00        nop
   c:   4048f5c3    .word   0x4048f5c3

您可以看到没有登记簿被移动。pi2的参数在s0中传递,编译器在S15中创建用于填充3.14的代码,并使用vmul.f32 s0、s0、S15s0中获得所需的结果。

有关调用约定的更多信息,您应该查看ARM的网站。

 类似资料:
  • Python3 数字 描述 log10() 方法返回以10为基数的x对数,x>0。 语法 以下是 log10() 方法的语法: import math math.log10( x ) 注意:log10()是不能直接访问的,需要导入 math 模块,通过静态对象调用该方法。 参数 x -- 数值表达式。 返回值返回以10为基数的x对数,x>0。 实例 以下展示了使用 log10() 方法的实例

  • 问题内容: 我正在尝试从CSV文件中的一组数字中找到最大值和最小值。我的代码在某些行中始终为Max函数返回错误的数字。这是我的代码: 我的输出示例: 我不确定我做错了什么。一些建议,将不胜感激。 问题答案: 您的列表元素是字符串。您需要对其进行转换,以避免按字典顺序进行比较(按字母顺序,一次只比较一个字符,这是因为) 除非您实际上想要字符串,否则不要创建新列表,而只需传递给您的函数即可:

  • 本文向大家介绍SQL中的数学函数,包括了SQL中的数学函数的使用技巧和注意事项,需要的朋友参考一下 数学函数在SQL中对于在查询中实现不同的数学概念非常重要。 SQL中的一些主要数学函数如下- ABS(X) 此函数返回X的绝对值。例如- 返回6。 MOD(X,Y) 变量X除以Y,然后返回它们的余数。例如- 返回4。 签名(X) 如果X为正,则此方法返回1;如果为负,则返回-1;如果X的值为0,则返

  • 问题内容: 为什么Python的数学错误? 问题答案: 你已达到计算机科学的新水平,并且你正在走向成熟。 因此,你现在可以进行下一步了。BDFL 本人已授权我向你透露以下超级机密文件。古人先理解它,再解密它,现在,你也将如此! http://floating-point-gui.de/basic/ 请谨慎对待本文件!只与你认识的人分享同样令人困惑的结论!

  • 本文向大家介绍MySQL数学函数简明总结,包括了MySQL数学函数简明总结的使用技巧和注意事项,需要的朋友参考一下 1. ABS(x): 返回x的绝对值 2. PI(): 返回圆周率 3. SQRT(x): 返回x的平方根,要求(x为非负数,返回NULL) 4. MOD(x,y): 求余函数,返回x被y除后的余数;对于带有小数部分的数据值也起作用,它返回除法运算后的精确余数。 5. CEIL(X)

  • 本文向大家介绍Oracle数学相关函数小结,包括了Oracle数学相关函数小结的使用技巧和注意事项,需要的朋友参考一下 本文总结了Oracle数学相关函数。分享给大家供大家参考,具体如下: 1.绝对值:abs() 2.取整函数(大):ceil() 3.取整函数(小):floor() 4.取整函数(截取):trunc() 5.四舍五入:round() 6.取平方:Power(m,n) 7.取平方根: