Приведение числа double к float с большой точностью

152
09 января 2018, 14:56

Пусть у меня есть некоторое значение типа double, мне необходимо провести некоторые манипуляции над этим значением и конвертировать в тип float. Имею такие данные:

double x = 12058660.309519000; float xx = x * 0.1f;

когда я проверяю через отладку выражение для переменной xx получаю - 1205866.0309518999, но когда проверяю само значение переменной xx, то получаю - 1205866.00

Почему?

Мне необходимо сохранить точность.

Answer 1

Вы уперлись в точность. Точность float — 7-8 знаков. Это значит, что float может хранить только 7 или 8(нечет и чет соответственно) цифр. Возьмите число с целой частью поменьше(1234, допустим), и у вас останется еще 8-4==4 цифры для дробной части.

Точность double(число двойной точности) - 15 знаков. Как можете заметить, double у вас тоже округляется до 15-го знака, причем не после запятой, а вообще. Округление связано с тем, что в памяти компьютера все числа представляются в двоичной системе счисления. Поэтому дробные числа в большинстве своем представляются в виде дроби, а уже она потом округляется, что вы и видите.

В float вы не сможете хранить больше 7-8 цифр, повторяю еще раз.

Answer 2

Проведем простой эксперимент

#include <stdio.h>
#include <math.h>
int main()
{
  float f = 1205866;
  printf("%.10f\n", f);
  printf("%.10f .. %.10f\n", nextafterf(f, 0), nextafterf(f, 1e8f));
}

Получаем

1205866.0000000000
1205865.8750000000 .. 1205866.1250000000

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

То есть ни о каком 1205866.0309518999 не может быть и речи. 1205866 - это ближайшее к вашему 1205866.0309518999 представимое значение типа float. Вот и ответ на ваш вопрос "Почему?".

Таким образом вы прекрасно "сохранили точность" - настолько, насколько это вообще возможно в выбранном вами типе. Если вы хотите еще лучше "сохранить точность", то тип float вам тут помочь не сможет. Используйте более точные типы. А если вам абсолютно необходимо конвертировать результат в тип float, то - увы...

Например, аналогичный эксперимент с типом double даст нам

1205866.00000000000000000000
1205865.99999999976716935635 .. 1205866.00000000023283064365

Как видите, "шаг" типа double в этой окрестности несравнимо мельче, чем ваше .0309....

READ ALSO
Память при создании переменной типа class

Память при создании переменной типа class

Когда мы создаем переменную int var = 5, все понятно, компьютер берет (выделяет) память 32 бита и записывает туда значение 5 в двоичном виде

160
Удаление из вектора и файла

Удаление из вектора и файла

Не знаю как удалять студентов из класса ГруппСтуденты добавляются из файла или с помощью функции addStudent

172
Сборка ANGLE под x86

Сборка ANGLE под x86

Собираю ANGLE в студии VS2017, под windows, по инструкцииЗадаю конфигурацию x86 (32bit) и генерирую проект для студии с помощью:

145