是否可以在int变量中存储浮点值

时间:2019-06-07 11:30:04

标签: c

我想将浮点值存储在整数变量中并打印该整数变量,我想查看浮点值本身。可以做到吗?

5 个答案:

答案 0 :(得分:4)

如果要查看orWhere变量的位模式,可以执行以下操作:

float

答案 1 :(得分:3)

  

我想将浮点值存储在整数变量中

那是一个不好的开始。但是,如果所选的整数类型足够宽以容纳float的表示形式,则可以将float的字节复制到整数中。 memcpy将是获得定义结果的更好方法之一。例如,如果floatint均为32位,则

float x = 1.2;
int i;
memcpy(&i, &x, sizeof(x));

这是我想到的最接近以整数形式存储float的值的方式,可以容纳float的整个范围,并且避免失去任何精度。

  

并打印   整数变量,我想查看浮点值本身。

我的意思是要打印float值的人类可读的十进制表示形式。有多个标准库函数可将float的内部表示形式转换为可打印的十进制表示形式,但是它们都将float作为输入,而不是整数。当然,您可以将float表示形式复制到float类型的对象中并使用它,但这似乎无法达到目的。但是,如果不这样做,就没有标准库函数可以满足您的要求。

  

它是什么   能不能做?

当然可以做到。尽管C没有定义使用C的运算符和标准库函数的方法,但是如果您假设float的表示形式的详细信息,则可以编写您自己的函数来复制所需的方面(例如)printf的总和,尽管这绝对是不平凡的。原则上,甚至可以编写代码来分析float的实现表示,因此无需进行任何假设。但这是很多复杂代码的结果,而仅通过float值存储在float对象中即可更好地获得结果。

答案 2 :(得分:2)

来自评论:

  

我的一个朋友问我这是否可行,我尝试了一下,但是找不到解决方法,就是为什么

通过严格回答,您可以这样:

#include <stdio.h>

int main(void) {
    int x; // Here is where we store the data
    float *p = (float*) &x; // Make a float pointer point at the integer
    *p = 42.67; // Pretend that the integer is a float and store the value
    printf("%f\n", *(float*)&x); // Print what's inside x, pretending it's a float
}

这样写不是一个好主意。请注意,这是未定义行为,因此C编译器基本上可以自由生成所需的任何垃圾。它只是偶然(几乎)始终在实践中起作用的那些不确定行为之一。至少对于预期的目标平台。我严格地写了这个答案以表明它是可能的,但是正如我所说的,它是UB,并且不是可移植的。

如果sizeof(float)> sizeof(int),这肯定会失败,但是我认为这是实现定义的。如果是这种情况,请选择一个至少与浮动类型一样大的整数类型。

值得一提的是,Quake引擎中确实存在类似的东西。即使不是约翰·卡马克(John Carmack)提出,也被称为Carmack hack。但是在那些日子里,CPU周期比可移植性更重要。代码如下(带有原始注释):

float Q_rsqrt( float number )
{
    long i;
    float x2, y;
    const float threehalfs = 1.5F;

    x2 = number * 0.5F;
    y  = number;
    i  = * ( long * ) &y;                       // evil floating point bit level hacking
    i  = 0x5f3759df - ( i >> 1 );               // what the fuck? 
    y  = * ( float * ) &i;
    y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration
//  y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed

    return y;
}

答案 3 :(得分:1)

  

是否可以将浮点值存储在int变量(?)

使用union

float的大小与可用的uintN_t类型匹配时,就没有问题。

float a = ...;
// i want to see the float value itself.
printf("%e %a\n", a, a);  // Use exponential notation

// to an integer type
assert(sizeof(float) == sizeof(uint32_t)); 
union {
  float f;
  uint32_t u;
} x = { a };
unsigned long ul = x.u;
// print that integer variable
printf("%lX\n", ul);

// and back again
union {
  float f;
  uint32_t u;
} y = { .u = (uint32_t) ul };
float f = y.f;
printf("%e %a\n", f, f);

请注意,printf("%lX\n", ul);将打印出与printf("%e %a\n", a, a);明显不符的内容。

答案 4 :(得分:0)

首先,请记住intfloat值的二进制表示形式彼此非常不同。整数值1和浮点值1.0的表示形式看起来并不相同。假设32位intfloat以及IEEE-754表示形式,我们得到:

  1: 0000 0000 0000 0000 0000 0000 0000 0001 (0x00000001)
1.0: 0111 1111 1000 0000 0000 0000 0000 0000 (0x3f800000)

float对象分配int截断小数部分-如果您编写类似的内容

int b = 1.2f; // 0x3f99999a

存储在b中的值为10x00000001)。如果您尝试将b分配回float,例如

float f = b;  

然后存储在f中的值为1.00x3f800000),不是 1.20x3f99999a

因此,您无法通过简单的分配将float 存储在int对象中。

如果int的宽度至少等于int,则可以在float对象 中存储浮点值的位模式memcpy,可以使用printf或某种形式的体操(如其他答案所示)。但是,如果尝试使用带有%d转换说明符的float打印该值,则输出将不会表示该1.2值(1067030938),将表示该位模式($ sudo npm sudo: npm: command not found $ sudo nvm sudo: nvm: command not found $ sudo balena sudo: balena: command not found )表示的整数值。

没有安全,定义明确的标准方法将浮点存储在整数对象中,并且像对待其他任何浮点对象一样对待它。 C可能不像其他语言那样强类型化,但是它的足够强足够强大,因此您必须依靠不安全的技巧来解决它(如其他答案所示)。