我正在计算c程序中的浮点数。我的值是6.3和2.8
有指数
10000001
10000000
我将它们相加并减去127,得到值130。
但是在在线计算器上,结果是131..so,我想知道这笔额外的钱是从哪里来的?
答案 0 :(得分:0)
01000000110010011001100110011010 6.3
01000000001100110011001100110011 2.8
01000001100011010001111010111000 6.3*2.8
0 10000001 10010011001100110011010 6.3
0 10000000 01100110011001100110011 2.8
0 10000011 00011010001111010111000 6.3*2.8
1尾数中的1以格式表示,并且不存储,但是数学要求。
1.10010011001100110011010 * 2^2 (6.3)
1.01100110011001100110011 * 2^1 (2.8)
1.00011010001111010111000 * 2^4 (6.3*2.8)
使用小数点众所周知,如果您想乘以1.234 * 98.76,我们将1234 * 9876相乘就好像没有小数点,然后在这种情况下将小数点放在答案中3 + 2上的5位数字。对于单精度浮点数,归一化数字的点右边有23位数字。
所以我们先乘以24bit * 24bits
1100 1001 1001 1001 1001 1010 0xC9999A
1011 0011 0011 0011 0011 0011 0xb33333
0xC9999A * 0xB33333 = 0x8D1EBA47AE
现在将我们的点设置为46位。 46 = 11.5个十六进制数字,因此我们的结果为12个数字,所以在第一个数字的中间。
10.00110100011110101110000111... * 2^3
1.000110100011110101110000111... * 2^4 (normalize)
将尾数修剪为23位
1.00011010001111010111000 * 2^4
我们得到的结果与生产的计算机相同。
这就是为什么指数化是127 + 4而不是127 + 3的原因。
加法的工作原理与小学一样,只是我们将较小的数字移到右侧,将有效位数转储到以太中,以便对这一点进行排队,因此我们可以进行加法(或减法)。基本上是24位加24位= 25位加法。然后根据需要进行归一化。如果您认为这两个数字都为1.something,则msbit总是相加2(或3)。 1.x + 1.y = 10.z或11.z,如果有一个进位。
除法我们理想地希望精度,因此46位除以23位,因此填充分子,并使用标准二进制整数除法除以分母。我们知道两个数字都是1.something,所以像乘法一样,我们也确切地知道归一化之前将点放置在何处。
编辑
我的即席程序有多个问题。这是非法使用工会,这是几分钟的破解,而不是长期的解决方案,结果表明它恰好在使用此编译器的计算机上工作。我还假设unsigned int是32位。不要在一台计算机上使用几分钟来编写您要使用的代码。绝对不是长期代码。
#include <stdio.h>
union
{
float f;
unsigned int x;
} myun;
int main ( void )
{
unsigned int ra;
unsigned int rb;
unsigned long long la,lb,lc;
myun.f=6.3F;
for(rb=0x80000000;rb;rb>>=1)
{
if(rb&myun.x) printf("1"); else printf("0");
}
printf("\n");
myun.f=2.8F;
for(rb=0x80000000;rb;rb>>=1)
{
if(rb&myun.x) printf("1"); else printf("0");
}
printf("\n");
myun.f=2.8F*6.3F;
for(rb=0x80000000;rb;rb>>=1)
{
if(rb&myun.x) printf("1"); else printf("0");
}
printf("\n");
la = 0xC9999A;
lb = 0xB33333;
lc = la*lb;
printf("0x%llX\n",lc);
return(0);
}
一些合法的东西,但仍然有假设。
float one ( void )
{
return 6.3F;
}
float two ( void )
{
return 2.8F;
}
float three ( void )
{
return 6.3F*2.8F;
}
编译然后反汇编
00000000 <one>:
0: e59f0000 ldr r0, [pc] ; 8 <one+0x8>
4: e12fff1e bx lr
8: 40c9999a smullmi r9, r9, sl, r9 ; <UNPREDICTABLE>
0000000c <two>:
c: e59f0000 ldr r0, [pc] ; 14 <two+0x8>
10: e12fff1e bx lr
14: 40333333 eorsmi r3, r3, r3, lsr r3
00000018 <three>:
18: e59f0000 ldr r0, [pc] ; 20 <three+0x8>
1c: e12fff1e bx lr
20: 418d1eb8 ; <UNDEFINED> instruction: 0x418d1eb8
我们得到了计算机来生成40c9999a 40333333和418d1eb8,并简单地从这些十六进制数字扩展位以查看此答案的开始。
乘法没什么不对的(好吧,我假设unsigned long long大于32位,那不是非法的,只是一个错误的假设),如果您没有可以使用的计算器,则很容易让计算机为您执行此操作。