Precision loss in integer to float conversion

Наименее значимые биты целого числа, потерянные во время преобразования в тип с плавающей точкой

Описание

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

Для образца, long int значение 1234567890L слишком велик для переменной типа float .

Риск

Если тип с плавающей точкой не может представлять целое значение, поведение не определено (см. C11 стандарт, 6.3.1.4, абзац 2). Для образца можно отбросить наименее значимые биты значения переменных, что приведет к неожиданным результатам.

Зафиксировать

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

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

При записи функции, которая преобразует целое число в тип с плавающей точкой, перед преобразованием проверьте, может ли целое значение быть представлено в типе с плавающей точкой. Для образца, DBL_MANT_DIG * log2(FLT_RADIX) представляет количество основы -2 цифр в типе double. Перед преобразованием в тип double, проверьте, больше ли это число или равно точности целого числа, которое вы преобразуете. Чтобы определить точность целого числа num, используйте этот код:

 size_t precision = 0;
 while (num != 0) {
    if (num % 2 == 1) {
      precision++;
    }
    num >>= 1;
 }

Некоторые реализации обеспечивают функцию builtin, чтобы определить точность целого числа. Для образца GCC обеспечивает функцию __builtin_popcount.

Примеры

расширить все

#include <stdio.h>

int main(void) {
  long int big = 1234567890L;
  float approx = big;
  printf("%ld\n", (big - (long int)approx));
  return 0;
}

В этом коде С long int переменная big преобразуется в float.

Коррекция - используйте более широкий тип с плавающей точкой

Одной из возможных коррекций является преобразование в double тип данных вместо float.

#include <stdio.h>

int main(void) {
  long int big = 1234567890L;
  double approx = big;
  printf("%ld\n", (big - (long int)approx));
  return 0;
}

Информация о результатах

Группа: Численный
Язык: C | C++
По умолчанию: Off
Синтаксис командной строки : INT_TO_FLOAT_PRECISION_LOSS
Влияние: Низкое
ИДЕНТИФИКАТОР CWE : 189, 681, 704
Введенный в R2018b