c++ - FP 数的指数字段不是我预期的,为什么?

标签 c++ floating-point

我已经被这个难住了好几天了。我根据一本名为 Write Great Code Volume 1 Understanding the Machine Chapter four 的书编写了这个程序。

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

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

最大的问题是为什么 Reexponent 变量看起来几乎不可预测;在此示例中,给定值为 5。这是为什么呢?我猜应该是两个。二是因为小数点是隐含的小数点右边的两位数。

我已将程序中产生的实际值注释到代码中,因此您不必运行程序即可了解发生了什么(至少在重要部分)。 此时尚未完成。整个项目还没有在我的电脑上创建。

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

#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;
}

帮助将不胜感激;我已经参与这个项目好几天了,非常沮丧!

最佳答案

in this example with the given values its 5. Why is that?

float 45.67在内部表示为

2^5 * 1.0110110101011100001010001111010111000010100011110110

实际上代表的是数字

45.6700000000000017053025658242404460906982421875

这是您在 float 中可以达到的最接近 45.67 的值。

如果您只对一个数的指数感兴趣,只需计算它的以 2 为底的对数并向下舍入即可。由于 45.67 介于 32 (2^5) 和 64 (2^6) 之间,因此指数为 5。

关于c++ - FP 数的指数字段不是我预期的,为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25391313/

相关文章:

c++ - 来自 c-Structure 的安全 dynamic_cast?

c++ - 静态断言实例化时模板类型的大小

c++ - union 存储多个值

javascript - 为什么 (-2.4492935982947064e-16).toFixed(5) 等于 "-0.00000"?

c++ - 使用 waitpid 等待另一个进程的线程

c++ - 两个已排序数组的交集

c# - 增加 float 的第 n 位数字

c++ - 将 float 从 1 递减到 0,增量为 0.01

c++ - 函数通过引用返回变量?

floating-point - float CSS定位的有效性