Предупреждение о потере данных c ++ / c - PullRequest
9 голосов
/ 17 апреля 2010

Я получаю доброкачественное предупреждение о возможной потере данных

предупреждение C4244: «аргумент»: преобразование из «const int» в «float», возможная потеря данных

Вопрос

Я помню, как будто float имеет большую точность, чем int.Итак, как могут быть потеряны данные, если я преобразую данные меньшего типа (int) в данные большего типа (float) ?

Ответы [ 7 ]

14 голосов
/ 17 апреля 2010

Потому что float числа не точны. Вы не можете представить каждое возможное значение, которое int может хранить в float, даже если максимальное значение float намного выше.

Например, запустите эту простую программу:

#include <stdio.h>

int main()
{
 for(int i = 0; i < 2147483647; i++)
 {
  float value = i;
  int ivalue = value;
  if(i != ivalue)
   printf("Integer %d is represented as %d in a float\n", i, ivalue);
 }
}

Вы быстро увидите, что есть тысячи миллиардов целых чисел, которые нельзя представить как float с. Например, все целые числа в диапазоне от 16 777 219 до 16 777 221 представлены как 16 777 220.

Снова отредактируйте Выполнение указанной выше программы указывает на наличие 2,071,986,175 положительных целых чисел, которые не могут быть точно представлены как float с. Что дает вам примерно 100 миллионов положительных целых чисел, которые корректно вписываются в float. Это означает, что только одно целое число из 21 является правильным, когда вы помещаете его в число с плавающей точкой.

Я ожидаю, что числа будут одинаковыми для отрицательных целых чисел.

6 голосов
/ 17 апреля 2010

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

В системах, где int составляет 32 бита, double обычно составляет 64 бита и поэтому может точно представлять любое целое число.

3 голосов
/ 17 апреля 2010

Оба типа состоят из 4 байтов (32 бита). Только один из них допускает дробь (float).

Возьмем это для примера с плавающей точкой;

34,156

(целое число). (Дробь)

Теперь используйте вашу логику; Если один из них должен сохранить информацию о дроби (в конце концов он должен представлять число), то это означает, что у него меньше битов для целочисленной части.

Таким образом, число с плавающей запятой может представлять максимальное целое число, которое меньше возможности типа int.

Чтобы быть более точным, int использует 32 бита для представления целого числа (максимальное целое число без знака 4 294 967 296). Для этого «float» использует 23 бита (максимальное целое число без знака 8 388 608).

Вот почему при конвертации из int в float вы можете потерять данные.

Пример: int = 1 158 354 125

Вы не можете хранить этот номер в «float».

Дополнительная информация по адресу:

http://en.wikipedia.org/wiki/Single_precision_floating-point_format

http://en.wikipedia.org/wiki/Integer_%28computer_science%29

1 голос
/ 17 апреля 2010

Точность не имеет значения. Точность int равна 1, в то время как точность типичного числа с плавающей точкой (одинарная точность IEEE 754) составляет приблизительно 5,96e-8. Важны наборы чисел, которые могут представлять два формата. Если есть числа, которые int может представлять в точности то, чего не может float, тогда возможна потеря данных.

Плавающие и целые числа обычно бывают 32-битными в наши дни, но это не гарантируется. Предполагая, что это так на вашей машине, из этого следует, что должны быть значения int, которые не могут точно представлять значения с плавающей точкой, поскольку, очевидно, есть значения с плавающей точкой, которые int не может представлять точно. Диапазон одного формата не может быть надлежащим супернабором другого, если оба формата эффективно используют одинаковое количество битов.

32-битное int эффективно имеет 31 бит, кодирующий абсолютное значение числа. У плавающего элемента IEEE 754 только 24 бита, кодирующих мантиссу (один неявный).

0 голосов
/ 28 февраля 2014

Дело в том, что и float, и int представлены 32-битными значениями. Целочисленное значение использует все 32 бита, поэтому оно может содержать числа от -2 31 до 2 31 -1. Однако число с плавающей запятой использует 1 бит для знака (включая -0.0f) и 8 бит для показателя степени. Средство 32 - 9 = 23 бита осталось для мантиссы. Однако число с плавающей точкой предполагает, что если мантисса и показатель степени не равны нулю, тогда мантисса начинается с 1. Таким образом, у вас более или менее есть 24 бита для целого числа вместо 32. Однако, поскольку оно может быть смещено, оно вмещает больше чем 2 24 целых чисел.

A floating point uses a Sign, an eXponent, and a Mantissa
S X X X X X X X X M M M M M M M M M M M M M M M M M M M M M M M

An integer has a Sign, and a Mantissa
S M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M

Итак, целое число, такое как:

1 0 0 1 1 1 1 1 1 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0

помещается в число с плавающей точкой, потому что его можно сместить:

1 0 0 1 1 1 1 1 1 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
|       |                             |
|       +---------+                   +---------+
|                 |                             |
v                 v                             v
S X X X X X X X X M M M M M M M M M M M M M M M M M M M M M M M
1                 1 1 1 1 1 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0

Я не показываю вам eXponent, потому что я чаще всего ошибаюсь при его вычислении, но это должно быть что-то вроде 5 (или -5?), Потому что я сдвинулся на 5 бит (но вы должны добавить или вычесть 128) ...). Это ясно показывает, что если вам нужно сдвинуться на 5 битов, вы потеряете 5 младших битов.

Таким образом, это другое целое число может быть преобразовано в число с плавающей запятой с потерей 2 бит (т. Е. При обратном преобразовании в целое число последние два бита (11) устанавливаются в ноль (00), поскольку они не были сохранены в плавать):

1 0 0 1 1 1 1 1 1 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 1
|       |                             |               | | | | |
|       +---------+                   +---------+     +-+-+-+-+--> all lost
|                 |                             |
v                 v                             v
S X X X X X X X X M M M M M M M M M M M M M M M M M M M M M M M
1                 1 1 1 1 1 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0

Довольно простые вещи на самом деле.

ВАЖНОЕ ПРИМЕЧАНИЕ: Да, первая 1 в целом числе является знаком, затем следующая 1 не копируется в мантиссу, предполагается, что это 1, поэтому это не требуется.

0 голосов
/ 17 апреля 2010

Мой стандартный ответ на такие вопросы - прочитать это - Что должен знать каждый учёный об арифметике с плавающей точкой .

0 голосов
/ 17 апреля 2010

A float обычно в стандартном формате IEEE с одинарной точностью. Это означает, что в float есть только 24 бита точности, в то время как int, вероятно, будет 32-битным. Итак, если ваш int содержит число, абсолютное значение которого не может поместиться в 24 бита, вы, вероятно, округлите его до ближайшего представимого числа.

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