如何在ARM中进行浮点计算?

How to do floating point calculation in ARM?

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

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

您不能使用定点直接与浮点数相加。正如您在维基百科或其他任何地方看到的那样,单精度浮点数格式非常简单。您需要了解的大部分内容都是在小学时学到的。

是加法还是减法?在这种情况下加法,好吧最简单。排列十进制(在本例中为二进制)点。
做加法。然后浮点部分按要求取整并归一化。

单精度是一个符号位、指数和一个隐含 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 编码。