简体   繁体   English

C ++仅使用整数数学将浮点数转换为十六进制

[英]C++ convert float to hex using only whole number math

I need to convert a whole number that should be considered a float into its hexadecimal equivalent. 我需要将一个整数(应视为浮点数)转换为等效的十六进制数。

For example: 例如:

Float To Hex 浮动到十六进制

1 = 0x3f800000 1 = 0x3f800000

2 = 0x40000000 2 = 0x40000000

12345 = 0x4640e400 12345 = 0x4640e400

It will always be whole numbers, never fractions such as 0.5. 它始终是整数,而不是小数,例如0.5。 This could be done with memory assignment or a formatting function, but the situation its being used it, it has no memory access and no API calls at all. 这可以通过内存分配或格式化功能来完成,但是在使用它的情况下,它没有内存访问权限,也没有API调用。

I tried this idea, but it doesn't work at all http://bytes.com/topic/c/answers/219928-how-convert-float-hex#post886069 我尝试过这个想法,但并非所有http://bytes.com/topic/c/answers/219928-how-convert-float-hex#post886069

Function floatAsUint_s() below re-interprets a 32-bit IEEE-754 float as an unsigned int for any input x for which |x| 下面的函数floatAsUint_s()将对于| x |的任何输入x,将32位IEEE-754 float重新解释为unsigned int is in [1, 2 128 ), or zero. 是[1、2 128 )或零。 The information is extracted from the float one bit at a time and the resulting unsigned int is built from those bits one bit at at time. 一次从float提取信息,然后一次从那些位中构建结果unsigned int Provided both the input and output reside in processor registers rather than memory, no additional memory is required during the re-interpretation process. 如果输入和输出都驻留在处理器寄存器中而不是内存中,则在重新解释过程中不需要额外的内存。

/* re-interpret IEEE-754 float x, |x| in [1, 2**128) or 0, as unsigned int */
unsigned int floatAsUint_s (float x)
{
    unsigned int i;

    /* extract sign bit, proceed with absolute value */
    i = (((x == 0.0f) ? (1.0f / x) : x) < 0.0f) ? 0x80000000 : 0x00000000;
    x = (((x == 0.0f) ? (1.0f / x) : x) < 0.0f) ? -x : x;
    /* extract exponent, which is positive per specification */
    if (x >= 1.84467441e19f) { x /= 1.84467441e19f; i |= 1 << 29; }
    if (x >= 4.29496730e9f)  { x /= 4.29496730e9f;  i |= 1 << 28; }
    if (x >= 65536.0f)       { x /= 65536.0f;       i |= 1 << 27; }
    if (x >= 256.0f)         { x /= 256.0f;         i |= 1 << 26; }
    if (x >= 16.0f)          { x /= 16.0f;          i |= 1 << 25; }
    if (x >= 4.0f)           { x /= 4.0f;           i |= 1 << 24; }
    if (x >= 2.0f)           { x /= 2.0f;           i |= 1 << 23; }
    i += (x == 0.0f) ? 0 : (127 << 23); // add IEEE-754 specified exponent bias
    /* extract mantissa */
    x = x - 1.0f; // remove hidden bit
    x = x + x; if (x >= 1.0f) { x -= 1.0f; i |= 1 << 22; } 
    x = x + x; if (x >= 1.0f) { x -= 1.0f; i |= 1 << 21; } 
    x = x + x; if (x >= 1.0f) { x -= 1.0f; i |= 1 << 20; } 
    x = x + x; if (x >= 1.0f) { x -= 1.0f; i |= 1 << 19; } 
    x = x + x; if (x >= 1.0f) { x -= 1.0f; i |= 1 << 18; } 
    x = x + x; if (x >= 1.0f) { x -= 1.0f; i |= 1 << 17; } 
    x = x + x; if (x >= 1.0f) { x -= 1.0f; i |= 1 << 16; } 
    x = x + x; if (x >= 1.0f) { x -= 1.0f; i |= 1 << 15; } 
    x = x + x; if (x >= 1.0f) { x -= 1.0f; i |= 1 << 14; } 
    x = x + x; if (x >= 1.0f) { x -= 1.0f; i |= 1 << 13; } 
    x = x + x; if (x >= 1.0f) { x -= 1.0f; i |= 1 << 12; } 
    x = x + x; if (x >= 1.0f) { x -= 1.0f; i |= 1 << 11; } 
    x = x + x; if (x >= 1.0f) { x -= 1.0f; i |= 1 << 10; } 
    x = x + x; if (x >= 1.0f) { x -= 1.0f; i |= 1 <<  9; } 
    x = x + x; if (x >= 1.0f) { x -= 1.0f; i |= 1 <<  8; } 
    x = x + x; if (x >= 1.0f) { x -= 1.0f; i |= 1 <<  7; } 
    x = x + x; if (x >= 1.0f) { x -= 1.0f; i |= 1 <<  6; } 
    x = x + x; if (x >= 1.0f) { x -= 1.0f; i |= 1 <<  5; } 
    x = x + x; if (x >= 1.0f) { x -= 1.0f; i |= 1 <<  4; } 
    x = x + x; if (x >= 1.0f) { x -= 1.0f; i |= 1 <<  3; } 
    x = x + x; if (x >= 1.0f) { x -= 1.0f; i |= 1 <<  2; } 
    x = x + x; if (x >= 1.0f) { x -= 1.0f; i |= 1 <<  1; } 
    x = x + x; if (x >= 1.0f) { x -= 1.0f; i |= 1 <<  0; } 
    return i;
}

/* reference implementation */
unsigned int floatAsUint (float a)
{
    unsigned int i;
    unsigned char *ap = (unsigned char *)&a, *ip = (unsigned char*)&i;
    for (unsigned int c = 0; c < sizeof (i); c++) { 
        *ip++ = *ap++;
    }
    return i;
}

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

int main (void)
{                          
    unsigned int res, ref;
    float s = -1.0f;
    while (s < 2.0f) {
        float x = 0.0f;
        while (x < 3.40282346e38f) {
            ref = floatAsUint (s * x);
            res = floatAsUint_s (s * x);
            if (ref != res) {
                printf ("error @ % 15.8e: res= %08x ref=%08x\n", x, res, ref);
                exit (EXIT_FAILURE);
            }
            x = (x == 0.0f) ? 1.0f : nextafterf (x, 3.40282346e38f);
        }
        s += 2.0f;
    }
    return EXIT_SUCCESS;
}

An alternative interpretation of the specification in the question is as follows: Given an int x, |x| 问题中对该规范的另一种解释如下:给定一个int x,| x | in [0, 2 24 ], produce the IEEE-754 single-precision encoding of the value of x, stored in a uint32_t . 在[0,2 24 ]中,产生存储在uint32_t的x值的IEEE-754单精度编码。 Use only integer operations for the transformation. 仅将整数运算用于转换。

The bit pattern of a positive non-zero integer <= 2 24 is identical to the bit pattern of the mantissa (with hidden bit restored) of the IEEE-754 float it is converted to, only appropriately shifted. 正非零整数<= 2 24的位模式与将其转换为IEEE-754 float的尾数(恢复了隐藏位)的位模式相同,仅进行了适当的移位。 We therefore need to normalize by left shifting the integer until its most significant 1-bit is in the position of the hidden mantissa bit, which is bit 23. The number of shifts needed to normalize tells us the magnitude of the integer in powers of two, and thus determines the exponent of the floating-point number. 因此,我们需要通过左移整数来进行归一化,直到其最高有效的1位位于隐藏的尾数位(即位23)的位置中。归一化所需的移位数告诉我们整数的大小(以2的幂为单位) ,从而确定浮点数的指数。 We need to remember to add the exponent bias prescribed by IEEE-754, then combine the sign, exponent, and mantissa portions for the final result. 我们需要记住要添加IEEE-754规定的指数偏差,然后将符号,指数和尾数部分组合起来以获得最终结果。

The function make_float_s() in the code below implements the algorithm described above. 以下代码中的函数make_float_s()实现了上述算法。

#include <stdint.h>

/* For |a| in [0,2**24], generate IEEE-754 float encoding with same value */
uint32_t make_float_s (int a)
{
    uint32_t i;
    int e = 0;

    i = (a < 0) ? 0x80000000 : 0x00000000;   // sign bit
    if (a) {
        a = (a < 0) ? -a : a;
        while (a < 0x00800000) {   // normalize mantissa
            e++;
            a = a + a;
        }
        e = 127 + (22 - e); // determine biased exponent
        i += (e << 23) + a; // combine sign, exponent, mantissa
    }
    return i;
}

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

uint32_t float_as_uint (float a)
{
    uint32_t i;
    memcpy (&i, &a, sizeof(i));
    return i;
}

/* reference function */
uint32_t make_float (int a)
{
    return float_as_uint ((float)a);
}

int main (void)
{
    uint32_t res, ref;
    int a, s;

    a=1; printf("%d encoded as IEEE-754 float: %08x\n", a, make_float_s(a));
    a=2; printf("%d encoded as IEEE-754 float: %08x\n", a, make_float_s(a));
    a=12345; printf("%d encoded as IEEE-754 float: %08x\n", a, make_float_s(a));

    s = -1;
    while (s < 2) {
        a = 0;
        while (a <= 16777216) {
            res = make_float_s (s * a);
            ref = make_float (s * a);
            if (res != ref) {
                printf ("error @ % 7d: res=%08x  ref=%08x\n", s * a, res, ref);
                exit (EXIT_FAILURE);
            }
            a++;
        }
        s += 2;
    }
    return EXIT_SUCCESS;
}

You can use union for this. 您可以为此使用union Something like: 就像是:

union data {
    float f_data;
    char c_data[4];
};

And usage: 和用法:

data d1;
d1.f_data = 12345;

After that d1.c_data contain hex values you need. 之后, d1.c_data包含您需要的十六进制值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM