如何在ARM中进行浮点计算?
Posted
技术标签:
【中文标题】如何在ARM中进行浮点计算?【英文标题】:How to do floating point calculation in ARM? 【发布时间】:2021-09-24 07:17:21 【问题描述】:我正在尝试将两个十进制数字相加,例如 1.5
和 1.75
。我把它们变成了十六进制的0x3fc00000
和0x3fe00000
。我尝试使用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 之后...
【参考方案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 中编写代码并不难。
【讨论】:
以上是关于如何在ARM中进行浮点计算?的主要内容,如果未能解决你的问题,请参考以下文章