【问题标题】:How to do floating point calculation in ARM?如何在ARM中进行浮点计算?
【发布时间】:2021-09-24 07:17:21
【问题描述】:

我正在尝试将两个十进制数字相加,例如 1.51.75。我把它们变成了十六进制的0x3fc000000x3fe00000。我尝试使用ADD 指令进行计算,但我得到了0x7fa00000,我认为正确的答案应该是0x40500000。有没有办法解决这个问题?谢谢!

【问题讨论】:

  • 浮点数通过 NEON 扩展和额外的寄存器集来处理。另外还有vadd指令developer.arm.com/documentation/dui0473/m/neon-instructions/…
  • @vadd NEON 对我不可用。我正在为 LPC2138 编程。
  • @XYWnot 如果您的 CPU 没有浮点指令(这是一个 ARM7TDMI-S,所以它没有),您必须自己实现这些浮点运算或调用合适的浮点点库。
  • @XYWnot 这是一个复杂的过程。请参阅像 Muller 等人的标准文本。 浮点算术手册了解详情。如果您对此不熟悉,最好使用浮点库而不是自己实现它。
  • 最好使用软浮点库。只需添加两个非 nan 数字,这很容易,您可以自己完成。维基百科有显然你已经知道的浮点格式,所以你应该能够自己做到这一点。一点小学数学(排列小数点,做加法,如果需要,四舍五入,标准化浮点数,完成)。先在 C 中尝试,然后在 asm 之后...

标签: assembly floating-point arm keil


【解决方案1】:

你是正确的 0x3FC00000 和 0x3FE00000 结果是 0x40500000

您不能将定点加法直接与浮点数一起使用。正如您在 Wikipedia 或其他任何地方所看到的,单精度浮点数格式非常简单。您需要知道的大部分内容都是在小学时学到的。

是加法还是减法?在这种情况下添加,还好最简单。排列小数点(在本例中为二进制)。
做加法。然后浮点部分根据需要进行四舍五入并归一化。

单精度是符号位、指数和隐含 1.fraction 的分数。指数是做数学运算的浮动部分,你需要将较小的数字小数位转移到以太中,直到点排成一行。然后您可以使用定点加法。我为规范化做了一个循环,但实际上是为了加法,你不能溢出超过一位(例如 0x3+0x3 ​​= 0x6),所以正常数字的唯一规范化(不会上溢或下溢或不是nan 开始)是将其从 1x.fraction 转换为 1.fraction 或者它已经是 1.fraction 形式(用于添加两个正数)。

这里似乎有很多代码,但如果您需要做的只是添加两个 你知道的正常正数会产生一个正常的数字,你可以采取一些捷径。比我有的多。如果你不关心四舍五入,你可以采取更多。

但浮点数的加、减、乘、除并不复杂,因为您可以使用定点运算来完成任务(就像逻辑一样),您只需要准备操作数并规范化结果即可。

//float fun1 ( void )
//{
//  return(1.5);
//}
//float fun2 ( void )
//{
//  return(1.75);
//}
//float fun3 ( void )
//{
//  return(1.75+1.5);
//}
//
//Disassembly of section .text:
//
//00000000 <fun1>:
//   0: e3a005ff    mov r0, #1069547520 ; 0x3fc00000
//   4: e12fff1e    bx  lr
//
//00000008 <fun2>:
//   8: e59f0000    ldr r0, [pc]    ; 10 <fun2+0x8>
//   c: e12fff1e    bx  lr
//  10: 3fe00000    .word   0x3fe00000
//
//00000014 <fun3>:
//  14: e59f0000    ldr r0, [pc]    ; 1c <fun3+0x8>
//  18: e12fff1e    bx  lr
//  1c: 40400000    .word   0x40500000

#include <stdio.h>
int main ( void )
{
    unsigned int a,b;
    unsigned int ea,eb;
    unsigned int sa,sb;
    unsigned int x,y,z;
    unsigned int sxy;
    a = 0x3FC00000;
    b = 0x3FE00000;
    
    //shortcut just do positive numbers
    if(a&(1<<31)) return(1);
    if(b&(1<<31)) return(1);
    
    //exponents
    sa=(a>>23)&0xFF;
    sb=(a>>23)&0xFF;
    //line up the decimal places
    if(sa>sb)
    {
        x=a&0x007FFFFF;
        x|=0x00800000;
        x<<=1; //room for rounding if desired
        y=b&0x007FFFFF;
        y|=0x00800000;
        y<<=1;
        while(sa!=sb)
        {
            y>>=1;
            sb++;
        }
        sxy=sa;
    }
    else
    {
        x=a&0x007FFFFF;
        x|=0x00800000;
        x<<=1;
        y=b&0x007FFFFF;
        y|=0x00800000;
        y<<=1;
        while(sa!=sb)
        {
            y>>=1;
            sa++;
        }
        sxy=sb;
    }
    z=x+y;
    z++; //round up
    while(z&0xFE000000) //should just be if(0x02000000)
    {
        z>>=1;
        sxy++;
    }
    z>>=1; //remove sticky bit
    z&=0x007FFFFF;
    z|=sxy<<23;
    printf("0x%08X\n",z);
    
    return(0);
}

在开始之前了解这两个数字,我们可以作弊并采取一些捷径,而不必费心四舍五入。

#include <stdio.h>
int main ( void )
{
    unsigned int a,b;
    unsigned int ea,eb;
    unsigned int sa,sb;
    unsigned int x,y,z;
    unsigned int sxy;
    a = 0x3FC00000;
    b = 0x3FE00000;
    
    //shortcut already know they are positive numbers
    //exponents I already know are the same
    sxy=(a>>23)&0xFF;
    //line up the decimal places (already aligned)
    x=a&0x007FFFFF;
    x|=0x00800000;
    y=b&0x007FFFFF;
    y|=0x00800000;
    z=x+y;
    if(z&0x02000000)
    {
        z>>=1;
        sxy++;
    }
    z&=0x007FFFFF;
    z|=sxy<<23;
    printf("0x%08X\n",z);
    
    return(0);
}

在 asm 中编写代码并不难。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-10
    • 1970-01-01
    相关资源
    最近更新 更多