如何在C ++中将Hex转换为IEEE 754 32位浮点数

时间:2016-04-30 21:28:08

标签: c++ c floating-point ieee-754

我正在尝试转换存储为int的十六进制值,并使用IEEE 32位规则将它们转换为浮点数。我特别努力为尾数和指数获得正确的值。十六进制存储在十六进制文件中。我希望有四位重要人物。以下是我的代码。

#include<mpi.h>
#include<stdio.h>
#include<stdlib.h>

int WhichSize(int mpiId, int numProc, int tam);

int main(int argc, char *argv[]){

    int i;
    int localSize;
    int numProc;
    int myid;

    int leftProc;
    int rightProc;

    int * myArray;
    int fullDomainSize = 16;

    MPI_Request request;

    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &numProc);
    MPI_Comm_rank(MPI_COMM_WORLD, &myid);


    // Lets get each partition size.
    localSize = WhichSize(myid, numProc, fullDomainSize);


    // Allocate arrays acording to proc number.
    if(numProc == 1){

        //printf("Allocating Array for serial usage\n");
        myArray = (int*)malloc(localSize*sizeof(int));

    } else if(numProc == 2) {

        //printf("Allocating Array for 2 proc usage\n");
        myArray = (int*)malloc((localSize+ 1)*sizeof(int));

    } else if(numProc > 2) {

        if (myid == 0 || myid == numProc - 1){

            //printf("Allocating array for boundary nodes usage\n");
            myArray = (int*)malloc((localSize+ 1)*sizeof(int));

        } else {

            //printf("Allocating array for inner nodes usage\n");
            myArray = (int*)malloc((localSize+ 2)*sizeof(int));

        }

    }


    // Now we will fill the arrays with a dummy value 123. For the
    // boundaries (ghosts) we will fill than with 80. Just to differe
    // ntiate.

    if(numProc == 1){

        //printf("----------------------------------------\n");
        //printf("Filling the serial array with values... \n");

        for (i = 0; i<localSize; i++){
            myArray[i] = 123;
        }

    } else if(numProc == 2) {

        ////printf("------------------------------------------------\n");
        //printf("Filling array for two proc usage with values... \n");

        for (i = 0; i<localSize; i++){
            myArray[i] = 123;
        }

        // ghost.
        myArray[localSize+1] = 8;

    } else if(numProc > 2) {

        if (myid == 0 || myid == numProc - 1){

            //printf("--------------------------------------------------\n");
            //printf("Filling boundary node arrays usage with values... \n");

            for (i = 0; i<localSize; i++){
                myArray[i] = 123;
            }

            // ghosts.
            myArray[localSize+1] = 8;

        } else {

            //printf("--------------------------------------------------\n");
            //printf("Filling inner node arrays usage with values... \n");

            for (i = 0; i<localSize; i++){
                myArray[i] = 123;
            }

            // ghosts.
            myArray[localSize+1] = 8;
            myArray[0] = 8;

        }

    }


    // Now lets comunicate the ghosts with MPI_Sendrecv().

    if(numProc == 1){

        //printf("Serial usage, no ghost to comunicate \n");

    } else if(numProc == 2) {

        if (myid == 0){

            //printf("Sending ghost value from proc %d to %d\n", myid, myid + 1);
            MPI_Isend(&myArray[localSize+1],
                      1,
                      MPI_INT,
                      1,
                      12345,
                      MPI_COMM_WORLD,
                      &request);

        } else if (myid == 1) {

            //printf("Receiving ghost value from proc %d to %d\n", myid-1, myid);
            MPI_Irecv(&myArray[localSize+1],
                      1,
                      MPI_INT,
                      0,
                      12345,
                      MPI_COMM_WORLD,
                      &request);
        }


    } else if(numProc > 2) {

        if (myid == 0){

            rightProc = myid + 1;

            if (myid == 0){

                //printf("-------------------------------\n");
                //printf("Communicating Boundary ghosts !\n");
                //printf("-------------------------------\n");

                //printf("Sending ghost value from proc %d to %d\n", myid, myid + 1);
                MPI_Isend(&myArray[localSize+1],
                          1,
                          MPI_INT,
                          rightProc,
                          12345,
                          MPI_COMM_WORLD,
                          &request);

            } else if (myid == rightProc) {

                //printf("Receiving ghost value from proc %d to %d\n", myid-1, myid);
                MPI_Irecv(&myArray[localSize+1],
                          1,
                          MPI_INT,
                          0,
                          12345,
                          MPI_COMM_WORLD,
                          &request);
            } 

        } else if (myid == numProc - 1) {

            leftProc  = myid - 1;

            if (myid == numProc - 1){

                //printf("-------------------------------\n");
                //printf("Communicating Boundary ghosts !\n");
                //printf("-------------------------------\n");

                ////printf("Sending ghost value from proc %d to %d\n", myid, myid + 1);
                MPI_Isend(&myArray[localSize+1],
                          1,
                          MPI_INT,
                          leftProc,
                          12345,
                          MPI_COMM_WORLD,
                          &request);

            } else if (myid == leftProc) {

                rightProc = myid + 1;

                //printf("Receiving ghost value from proc %d to %d\n", myid-1, myid);
                MPI_Irecv(&myArray[localSize+1],
                          1,
                          MPI_INT,
                          rightProc,
                          12345,
                          MPI_COMM_WORLD,
                          &request);
            } 

        } else {

                //printf("-------------------------------\n");
                //printf("Communicating Inner ghosts baby\n");
                //printf("-------------------------------\n");

                leftProc  = myid - 1;
                rightProc = myid + 1;

                // Communicate tail ghost.
                if (myid == leftProc) {
                    MPI_Isend(&myArray[localSize+1],
                              1,
                              MPI_INT,
                              rightProc,
                              12345,
                              MPI_COMM_WORLD,
                              &request);

                } else if (myid == rightProc){
                    MPI_Irecv(&myArray[localSize+1],
                              1,
                              MPI_INT,
                              leftProc,
                              12345,
                              MPI_COMM_WORLD,
                              &request);
                }

                // Communicate head ghost.
                if (myid == leftProc) {
                    MPI_Isend(&myArray[0],
                              1,
                              MPI_INT,
                              rightProc,
                              12345,
                              MPI_COMM_WORLD,
                              &request);

                } else if (myid == rightProc){
                    MPI_Irecv(&myArray[0],
                              1,
                              MPI_INT,
                              leftProc,
                              12345,
                              MPI_COMM_WORLD,
                              &request);
                }
        }
    }


    // Now I Want to see if the ghosts are in place !.

    if (myid == 0){
        printf("The ghost value is: %d\n", myArray[localSize + 1]);
    } else if (myid == numProc - 1){
        printf("The ghost value is: %d\n", myArray[0]);
    } else {
        printf("The head ghost is: %d\n", myArray[0]);
        printf("The tail ghost is: %d\n", myArray[localSize + 1]);
    }


    MPI_Finalize();

    exit(0);
}

int WhichSize(int mpiId, int numProc, int tam){

    double resto;
    int    tamLocal;

    tamLocal = tam / numProc;

    resto = tam - tamLocal*numProc;

    if (mpiId < resto) tamLocal = tamLocal + 1;


    return tamLocal;
}

}

6 个答案:

答案 0 :(得分:2)

我怀疑你的意思是{/ 1}}

^

意味着&#34;以及#34;的力量。在C或C ++中没有这样的运算符。 mantissa2 = m1 * (2 ^ -1) + m2*(2 ^ -2) + m3*(2 ^ -3) + m4*(2 ^ -4); 运算符是逐位XOR运算符。

答案 1 :(得分:1)

我们需要转换IEEE-754单精度和双精度数字(使用32位和64位编码)。我们使用的C编译器具有一组受限制的函数,最终开发了以下函数(可以使用任何on-line C compiler对其进行轻松测试):

#include <stdio.h>
#include <math.h>

double ConvertNumberToFloat(unsigned long number, int isDoublePrecision)
{
    int mantissaShift = isDoublePrecision ? 52 : 23;
    unsigned long exponentMask = isDoublePrecision ? 0x7FF0000000000000 : 0x7f800000;
    int bias = isDoublePrecision ? 1023 : 127;
    int signShift = isDoublePrecision ? 63 : 31;

    int sign = !((number >> signShift) & 0x01);
    int exponent = ((number & exponentMask) >> mantissaShift) - bias;

    int power = -1;
    double total = 0.0;
    for ( int i = 0; i < mantissaShift; i++ )
    {
        int calc = (number >> (mantissaShift-i-1)) & 0x01;
        total += calc * pow(2.0, power);
        power--;
    }
    total += 1.0;

    double value = sign * pow(2.0, exponent) * total;

    return value;
}

float GetSinglePrecision(unsigned int number)
{
    return (float)ConvertNumberToFloat(number, 0);
}

double GetDoublePrecision(unsigned long number)
{
    return ConvertNumberToFloat(number, 1);
}

int main()
{
    unsigned int singleValue = 0x40490FDB; // 3.141592...
    float singlePrecision = GetSinglePrecision(singleValue);
    printf("IEEE754 Single (from 32bit 0x%08X): %.7f\n",singleValue,singlePrecision);

    unsigned long doubleValue = 0x400921FB54442D18; // 3.141592653589793... 
    double doublePrecision = GetDoublePrecision(doubleValue);
    printf("IEEE754 Double (from 64bit 0x%016lX): %.16f\n",doubleValue,doublePrecision);
}

答案 2 :(得分:0)

考虑到您的CPU遵循IEEE标准,您也可以使用union。像这样的东西

  union
  {
    int num;
    float fnum;
  } my_union;

然后将整数值存储到my_union.num中,并通过获取my_union.fnum将其读作浮动。

答案 3 :(得分:0)

您的代码中存在许多非常基本错误。

最明显的是使用^重复使用&#34;&#34;的权力。 ^是XOR运算符,对于&#34; power&#34;您必须使用pow(base, exponent)中的math.h功能。

接下来,&#34;我想要有四位重要人物&#34; (大概是尾数),但你只提取了四个。四位只能编码0..15,大约是一个半位。要获得四位有效数字,您至少需要log(10,000)/ log(2)≈13.288,或至少14位(但最好是17位,因此您可以得到一个完整的额外数字以获得更好的舍入)。 / p>

您为sign提取错误的位,然后以错误的方式使用它。是的,如果是0然后是sign = 1,如果是1,那么sign = -1,但是你在最终计算中使用

value = (-1^sign) * ...

(同样使用^,尽管偶数pow在这里没有任何意义)。您应该立即使用sign * ..

exponent被声明为unsigned int,但对于负值则失败。 signed需要pow(2, exponent)(已从(2 ^ exponent)更正)。

从积极的方面来说,(1+mantissa2)确实是正确的。

将所有这些要点放在一起,并忽略了实际上只要求4位有效数字的事实,我得到以下代码。请注意,为了方便起见,我重新排列了初始位移和提取 - 我将mantissa移至 left ,而不是右移,因此我可以在计算中对0进行测试。

(啊,我错过了!)直接使用sign不起作用,因为它被声明为unsigned int。因此,如果您认为值为-1,则它实际上会获得值4294967295(更精确:来自UINT_MAX的{​​{1}}的值)。

摆脱这种情况的最简单方法不是乘以limits.h而只测试它,如果设置则取消sign

value

通过上述内容,您可以获得float floatizeMe (unsigned int myNumba ) { //// myNumba comes in as 32 bits or 8 byte unsigned int sign = myNumba >>31; signed int exponent = ((myNumba >> 23) & 0xff) - 0x7F; unsigned int mantissa = myNumba << 9; float value = 0; float mantissa2; cout << endl << "input is : " << hex << myNumba << endl; cout << endl << "mantissa is : " << hex << mantissa << endl; value = 0.5f; mantissa2 = 0.0f; while (mantissa) { if (mantissa & 0x80000000) mantissa2 += value; mantissa <<= 1; value *= 0.5f; } cout << "\nsign is: " << sign << endl; cout << "exponent is : " << hex << exponent << endl; cout << "mantissa 2 is : " << mantissa2 << endl; /* REMOVE: if above this number it is negative if ( sign == 1) sign = -1; // if above this number it is positive else { sign = 1; } */ /* value = sign * (1.0f + mantissa2) * (pow (2, exponent)); */ value = (1.0f + mantissa2) * (pow (2, exponent)); if (sign) value = -value; cout << dec << "Float value is: " << value << "\n\n\n"; return value; } (0.2000000030)和0x3e4ccccd(3.1415927410)等值的正确结果。

如果你的输入已经是IEEE-754格式(尽管是十六进制格式),那么所有的说法和完成,那么一个简单的演员应该就够了。

答案 4 :(得分:0)

只需执行以下操作(但首先确保将字节读入整数时,您具有正确的字节序):

float int_bits_to_float(int32_t ieee754_bits) {
    float flt;
    *((int*) &flt) = ieee754_bits;
    return flt;
}

对我有用...当然,这假设float具有32位,并且在您的体系结构上采用IEEE754格式(几乎总是这样)。

答案 5 :(得分:-1)

除了更简单之外,这也避免了任何舍入/精度错误。

float value = reinterpret_cast<float&>(myNumba)

如果您仍想单独检查部件,请在之后使用库函数std::frexp。如果您不喜欢类型惩罚,至少使用std::ldexp来应用指数而不是您的显式数学,这很容易受到舍入/精度错误和溢出的影响。

这两者的替代方法是使用联合类型,如this answer中所述。