如何在ARM中进行浮点计算?
How to do floating point calculation in ARM?
我正在尝试将两个小数相加,例如 1.5
和 1.75
。我把它们变成了十六进制 0x3fc00000
和 0x3fe00000
。我尝试使用 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 编码。
我正在尝试将两个小数相加,例如 1.5
和 1.75
。我把它们变成了十六进制 0x3fc00000
和 0x3fe00000
。我尝试使用 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 编码。