2013-12-03 4 views
1

И когда я читал главу о плавающих точках в C++ Primier Plus.Почему значение точки с плавающей точкой?

Он привел пример, как показано ниже:

#include <iostream> 

int main(){ 
using namespace std; 

float a = 2.34E+22f; 
float b = a + 1.0f; 

cout << "a =" << a <<endl; 
cout << "b -a =" << b - a<< endl; 
return 0; 
} 

И его результат:

a = 2.34e+22 
b -a = 0 

Объяснение от книги, и я цитирую:

«Проблема состоит в том, что 2.34E + 22 представляет число с 23 цифрами слева от десятичного разряда . Добавив 1, вы пытаетесь добавить 1 к 23-я цифра в этом номере. Но тип float может представлять только первые 6 или 7 цифр в количестве, поэтому попытка изменить 23-я цифра не влияет на значение. "

Но я не понимаю. Может кто-нибудь помочь мне понять, почему б -а 0 в понятной форме, пожалуйста?

+0

Ухм, это объяснение совершенно ясно, какая часть его вы не понимаете? –

+3

Говорят, что 'float' недостаточно точен, чтобы иметь возможность хранить разницу между 23 400 000 000 000 000 000 000 и 23 400 000 000 000 000 000 000. – dreamlax

+0

Спасибо всем! От Юхао и ответа Джеффри. Поплавок хранится как одноточечная с форматом + -m * 2^x. m больше 2^23 больших, что объясняет, почему float может представлять первые 6 или 7 цифр в десятичном числе. – BBai

ответ

0

Сингл точности с плавающей точкой типа float, как это (при условии, IEEE-754)

single precision floating point

фракция часть имеет только 23 бит, примерно менее 10 -. При вы добавляете небольшое число до 2.34E+22f, точность float ограничивает представление результата, поэтому b заканчивается неизменным значением от a.

1

b - a является 0, потому что b и a равны.

Когда вы добавляете слишком маленькое число в большое число, это как если бы вы ничего не добавляли.

В этом случае «слишком мало» будет меньше чем примерно 2,34e + 15, т.е. на 7 цифр меньше.

0

Оба существующих ответа верны (от Марка Рэнсом и Ю Хао).

Очень короткое объяснение состоит в том, что значения поплавка не очень точны. Значения округляются после 6 или 7 десятичных цифр. Для очень больших чисел эта неточность означает, что небольшие изменения значения округляются до нуля. Даже + 1 или + 100 может быть «очень небольшим изменением», если это делается до 1000000000.

2

Тип float в C/C++ хранится в стандартном формате «одной точности». Числа имеют вид

±m*2^e 

, где m представляет собой целое число от 2 до 23 и 2 и e представляет собой целое число. (Я оставляю много деталей, которые здесь не актуальны.)

Так как это объясняет, что вы видите?

Прежде всего, цифры в вашем коде всегда округляются до ближайшего числа с плавающей запятой. Таким образом, значение 2.34e+22 фактически округлено до 10391687 * 2 , что составляет 23399998850475413733376. Это значение a.

Во-вторых, результат операции с плавающей запятой всегда округляется до ближайшего числа с плавающей запятой. Итак, если вы добавите 1 к a, результат будет 23399998850475413733377, который снова округляется до ближайшего числа с плавающей запятой, что все равно, конечно, 23399998850475413733376. Таким образом, b получает то же значение, что и a. Поскольку оба числа равны, a - b == 0.

Вы можете добавить числа, которые намного больше 1 до a, и получить тот же результат. Причина опять же в том, что результат округлен, а ближайший номер с плавающей запятой по-прежнему будет a, когда вы добавляете номера не менее чем до 2 , или примерно 1e + 15.

+0

Использует ли cpp тот же способ хранения типа float, что и в C? – BBai

+0

Все современные компиляторы C и C++, которые я знаю, используют этот формат для float, но те же рассуждения применимы к любому представлению. –

Смежные вопросы