Я вижу некоторую ошибку при простом назначении значения с плавающей запятой, которое содержит только 4 значащих цифры. Я написал короткую программу для отладки, и я не понимаю, в чем проблема. После проверки пределов поплавка на моей платформе кажется, что не должно быть никаких ошибок. Что вызывает это?
#include <stdlib.h>
#include <stdio.h>
#include <limits>
#include <iostream>
int main(){
printf("float size: %lu\n", sizeof(float));
printf("float max: %e\n", std::numeric_limits<float>::max());
printf("float significant figures: %i\n", std::numeric_limits<float>::digits10);
float a = 760.5e6;
printf("%.9f\n", a);
std::cout.precision(9);
std::cout << a << std::endl;
double b = 760.5e6;
printf("%.9f\n", b);
std::cout << b << std::endl;
return 0;
}
Выход:
float size: 4
float max: 3.402823e+38
float significant figures: 6
760499968.000000000
760499968
760500000.000000000
760500000
float
имеет точность 24 бита, что примерно эквивалентно 7 десятичным цифрам. double
имеет точность 53 бита, что примерно эквивалентно 16 десятичным цифрам.
Как уже упоминалось в комментариях, 760.5e6
не совсем представлен float
; тем не менее, он точно представлен double
, Вот почему напечатанные результаты для double
точны, а те из float
не.
Это законно, чтобы запросить печать большего количества десятичных цифр, чем представлено вашим числом с плавающей запятой, как вы это сделали. Результаты, о которых вы сообщаете, не являются ошибкой — они просто являются результатом того, что алгоритм десятичной печати делает все возможное.
Сохраненный номер в вашем float
760499968. Это ожидаемое поведение для двоичных чисел с плавающей точкой IEEE 754, так как float
с, как правило,
IEEE 754 числа с плавающей запятой хранятся в трех частях: знаковый бит, показатель степени и мантисса. Поскольку все эти значения хранятся как биты результирующее число вроде, как бы, что-то вроде бинарный эквивалент научной записи. Биты мантиссы на единицу меньше числа двоичных цифр, допустимых в качестве значимых цифр в двоичной научной нотации.
Как и в случае с десятичными научными числами, если показатель степени превышает значащие цифры, вы потеряете целочисленную точность.
До сих пор эта аналогия продолжается: мантисса — это модификация коэффициента, найденного в десятичной научной нотации, с которой вы, возможно, знакомы, и есть определенные битовые комбинации, которые имеют особое значение в стандарте.
Конечным результатом этого механизма хранения является то, что целое число 760500000 не может быть точно представлено IEEE 754 binary32
с его 23-битной мантиссой: он теряет точность целочисленного уровня после целого числа в 2 ^ (мантисса_бит + 1), что составляет 16777217 для 23-битных плавающих мантисс. Ближайшими целыми числами к 76050000, которые могут быть представлены с плавающей точкой, являются 760499968 и 76050032, первое из которых выбрано для представления из-за правило круглых связей, и печать целого числа с большей точностью, чем может представлять число с плавающей запятой, естественно приведет к очевидным неточностям.
Двойной тип, размер которого в вашем случае составляет 64 бита, естественно, имеет большую точность, чем число с плавающей точкой, которое в вашем случае составляет 32 бита. Таким образом, это ожидаемый результат
Спецификации не требуют, чтобы любой тип правильно представлял все числа, меньшие, чем std :: numeric_limits :: max (), со всей их точностью.
Отображаемый номер отключен только в 8-й цифре и после. Это хорошо в пределах 6 цифр точности, которую вы гарантируете для float
, Если вы напечатаете только 6 цифр, результат будет округлен, и вы увидите ожидаемое значение.
printf("%0.6g\n", a);
Увидеть http://ideone.com/ZiHYuT