Можно ли хранить значение с плавающей точкой в ​​переменной int - PullRequest
2 голосов
/ 07 июня 2019

Я хочу сохранить значение с плавающей точкой в ​​целочисленной переменной и напечатать эту целочисленную переменную, и я хочу увидеть само значение с плавающей запятой.Это можно сделать или нет?

Ответы [ 5 ]

4 голосов
/ 07 июня 2019

Если вы хотите увидеть битовую комбинацию вашей переменной float, вы можете сделать это:

#include <stdio.h>
#include <stdint.h>
#include <string.h>

int main(void) {
    uint8_t bitpattern[sizeof (float)];
    float f = 3.1414;
    memcpy(bitpattern, &f, sizeof (float));

    for (int i = 0; i < sizeof (float); i++)
      printf("%02x ", bitpattern[i]);
}
3 голосов
/ 07 июня 2019

Я хочу сохранить значение с плавающей запятой в целочисленной переменной

Ну, это плохое начало. Тем не менее, если выбранный целочисленный тип достаточно широк, чтобы вместить представление float, вы можете скопировать байты float в целое число. memcpy будет одним из лучших способов сделать это с определенными результатами. Например, если float и int являются 32-битными величинами, тогда

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

Это самое близкое, что я могу думать о сохранении значения float в целое число таким образом, чтобы охватить весь диапазон float и избежать потери какой-либо точности.

и распечатайте это целочисленная переменная, и я хочу видеть само значение с плавающей запятой.

Я предполагаю, что вы хотите напечатать читаемое человеком десятичное представление значения float. Существует несколько стандартных библиотечных функций, которые преобразуют внутреннее представление float в печатное десятичное представление, но все они принимают float в качестве ввода, а не целое число. Конечно, вы можете скопировать представление с плавающей точкой в ​​объект типа float и использовать его, но, похоже, это не соответствует цели. Однако без этого нет стандартной библиотечной функции, которая делает то, что вы хотите.

что это можно сделать или нет?

Конечно, это можно сделать. Хотя C не определяет способ сделать это с помощью операторов C и стандартных библиотечных функций, если вы предполагаете детали представления float, вы можете написать свою собственную функцию, которая копирует необходимые аспекты (скажем, ) printf, хотя это явно нетривиально. В принципе, можно даже написать код, который анализирует представление реализации float, поэтому не нужно делать никаких предположений. Но это чертовски много сложного кода для результата, который лучше получить, просто сохраняя float значений в float объектах .

2 голосов
/ 07 июня 2019

Из комментариев:

один из моих друзей спросил меня, возможно ли это или нет, я пытался, но я не смог найти решение, поэтому

Строго отвечая на это, вы можете сделать так:

#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.Это называется Кармак Хак , хотя это был не Джон Кармак, который придумал это.Но это были дни, когда циклы процессора были важнее переносимости.Код выглядит так (с оригинальными комментариями):

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;
}
1 голос
/ 07 июня 2019

Можно ли сохранить значение с плавающей запятой в переменной 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);.

0 голосов
/ 07 июня 2019

Прежде всего, помните, что двоичные представления значений int и float очень отличаются друг от друга.Представления для целочисленного значения 1 и значения с плавающей запятой 1.0 не выглядят ничем похожими друг на друга.Предполагая 32-битное представление int и float и 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, будет 1 (0x00000001).Если вы попытаетесь присвоить b обратно float, например

float f = b;  

, тогда значение, сохраненное в f, будет 1.0 (0x3f800000), , а не 1.2 (0x3f99999a)

Таким образом, вы не можете сохранить float значение в int объекте с помощью простого назначения.

Вы можете сохранить битовая комбинация для значения с плавающей точкой в ​​int объекте , если , int, по крайней мере, такой же ширины, как float, либо с использованием memcpy, либо некоторымивид литья гимнастики (как показали другие ответы).Однако, если вы попытаетесь напечатать это значение, используя printf со спецификатором преобразования %d, вывод не будет представлением этого значения float (1.2), это будет представление целое число значение, представленное этой битовой комбинацией (1067030938).

Не существует безопасного, четко определенного, стандартного способа хранения значения с плавающей запятой значение в целочисленном объекте и обработки его как любого другого объекта с плавающей запятой.C может быть не так строго типизирован, как другие языки, но его достаточно достаточно , так что вам придется полагаться на небезопасные хаки, чтобы обойти его (как было продемонстрировано в других ответах).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...