FP编号的指数字段不是我预期的,为什么?

时间:2014-08-19 19:17:43

标签: c++ floating-point

我已经被困在这一天好几天了。我从一本名为Write Great Code Volume 1 Understanding the Machine Chapter 4的书中写了这个程序。

该项目是用C ++进行浮点运算。我计划用自己的C ++实现其他操作;本书在项目中使用HLA(高级程序集)进行乘法和除法等其他操作。

我想在从FP号中提取后显示指数和其他字段值;用于调试。然而我遇到了一个问题:当我在记忆中看到这些价值时,他们并不是我认为应该是的。关键词:我的想法。我相信我理解IEEE FP格式;它非常简单,我理解到目前为止我在书中所阅读的内容。

最大的问题是为什么Rexponent变量似乎几乎不可预测;在这个例子中,给定值为5.为什么?根据我的猜测它应该是两个。两个因为小数点是隐含的小数点的两位数。

我已经将程序中产生的实际值注释到代码中,因此您无需运行程序即可了解发生的事情(至少在重要部分中)。 目前尚未完成。尚未在我的计算机上创建整个项目。

这是代码(引自我从书中复制然后修改的文件):

#include<iostream>

typedef long unsigned real; //typedef our long unsigned ints in to the label "real" so we don't confuse it with other datatypes. 
using namespace std; //Just so I don't have to type out std::cout any more!

#define asreal(x) (*((float *) &x)) //Cast the address of X as a float pointer as a pointer. So we don't let the compiler truncate our FP values when being converted.

inline int extractExponent(real from) {
    return ((from >> 23) & 0xFF) - 127; //Shift right 23 bits; & with eight ones (0xFF == 1111_1111 ) and make bias with the value by subtracting all ones from it.
}


void fpadd ( real left, real right, real *dest) {
    //Left operand field containers
    long unsigned int Lexponent = 0;
    long unsigned     Lmantissa = 0;
    int               Lsign = 0;
    //RIGHT operand field containers
    long unsigned int Rexponent = 0;
    long unsigned     Rmantissa = 0;
    int               Rsign = 0;
    //Resulting operand field containers
    long int                Dexponent = 0;
    long unsigned   Dmantissa = 0;
    int             Dsign = 0;

    std::cout << "Size of datatype: long unsigned int is: " << sizeof(long unsigned int); //For debugging
    //Properly initialize the above variable's:
    //Left
    Lexponent = extractExponent(left); //Zero. This value is NOT a flat zero when displayed because we subtract 127 from the exponent after extracting it! //Value is: 0xffffff81
    Lmantissa = extractMantissa (left); //Zero. We don't do anything to this number except add a whole number one to it. //Value is: 0x00000000

    Lsign = extractSign(left); //Simple.
    //Right
    **Rexponent = extractExponent(right); //Value is: 0x00000005 <-- why???**
    Rmantissa = extractMantissa (right);
    Rsign = extractSign(right);



}

int main (int argc, char *argv[]) {
    real a, b, c;

    asreal(a) = -0.0;
    asreal(b) = 45.67;

    fpadd(a,b, &c);

    printf("Sum of A and B is: %f", c);
    std::cin >> a;
    return 0;
}

非常感谢帮助;我有几天参加这个项目并非常沮丧!

2 个答案:

答案 0 :(得分:3)

  

在此示例中,给定值为5.为什么会这样?

浮点数45.67在内部表示为

2^5 * 1.0110110101011100001010001111010111000010100011110110

实际上代表数字

45.6700000000000017053025658242404460906982421875

尽可能接近float内的45.67。

如果您感兴趣的只是数字的指数,只需计算其基数2的对数并向下舍入。由于45.67介于32(2 ^ 5)和64(2 ^ 6)之间,因此指数为5.

答案 1 :(得分:2)

计算机对所有数字使用二进制表示。因此,指数是基数为2,而不是基数为10。 int(log2(45.67))= 5.