Реалните числа в C++ всъщност се обработват от фундаменталните типове данни: float и double. Те са приближени модели на въведена стойност. Но достатъчно точни за всички математически изчисления. Мигновено се изчисляват от съвременните процесори.
Float дава точност до 6-то число, след десетичната запетая. Заема 4 байта памет.
Double е точен до 15-то число, след десетичната запетая. Заема 8 байта памет.
Стандарта на C++ дефинира и разширения тип long double. Заради някои процесорни архитектури. Може и да е по – голям и по точен от double. Стандарта само казва, че трябва да покрива точността на double. Понякога за long double ще трябват повече инструкции. Просто го добавям, за да знаете че има и такова животно. Float и double са нативни типове за ARM, x32 и x64 архитектурата. Използвайте тях. Кода в долния пример ще върне различна дължина на типовете при различните видове компилатори за long double.
#include <iostream>
using namespace std;
int main() {
cout << "float: " << sizeof(float) << endl;
cout << "double: " << sizeof(double) << endl;
cout << "long double: " << sizeof(long double) << endl;
}На macOS C++ компилатора ще върне размер 8 байта за long double. Което значи, че това е същия тип като double. Но GNU C++ ще ви върне размер 16.
Тези типове наричаме реални или дробни. По правилния термин е „типове за числа с плаваща запетая„, това е груб превод от английското „floating point numbers„. Използвайте тези типове само за математически изчисления. За финансови изчисления тез типове не се използват, защото имат голямо приближения след десетичния знак.
Нека разгледаме следния пример:
#include <iostream>
using namespace std;
int main() {
double a = 0.1;
double b = 0.2;
bool r = ((a + b) == 0.3);
cout << boolalpha << r << endl;
}Този код винаги ще връща false. Тук проверяваме сбора на 0.1 и 0.2 дали е равен на 0.3. False означава невярно, лъжа. Това е така заради неточността на типовете с плаваща запетая след десетичния знак. За нативно изпълнение от процесора, бързина на кода.
Как се сравняват числа с плаваща запетая
Трябва да го правим, като изберем точността на сравнението, след десетичния знак. От математиката помня, че това число се бележи с Епсилон. Означаваме го с EPS.
#include <iostream>
#include <cmath>
using namespace std;
const double EPS = 1e-6;
int main() {
double a = 0.1;
double b = 0.2;
bool r = ( abs(trunc(a + b)) < EPS );
cout << boolalpha << r << endl;
}Магията е в 10 ред: Събираме a и b. С trunc режем цялата част от полученото число. Abs ни връща положителна стойност. Сравняваме я с EPS. Понеже вече имаме 0.xxxxxxx. И ако условието е OK на r се присвоява някаква стойност различна от 0. Но понеже е булева променлива всичко различно от 0 връща true. И само 0 връща false.
Деление на 0
При целите числа това е сериозна грешка. Която ви прекратява програмата. Защото процесора не обича да дели на 0 цели числа. И това е сигнал за неправилно написан израз в кода ви. А с цели числа вие достъпвате индекси на масиви от данни. Опасно е за това тактиката е дефанзивна.
Ако делите на 0 с числа с плаваща запетая програмата ви няма да се срути веднага. Тук компилатора е толерантен и разбира, че може да се случи такова нещо при разни математически изчисления.
#include <iostream>
using namespace std;
int main() {
float x = 1.0 / 0.0; // +inf
float y = -1.0 / 0.0; // -inf
cout << x << endl;
cout << y << endl;
}При подобна операция се връща Inf (infinity). Направо си е безкраен резултат. И при следваща операция с inf следва програмата да се прекрати…
Можем да го проверим с функцията isinf(double)
#include <iostream>
#include <cmath>
using namespace std;
int main() {
double x = 1.0 / 0.0;
if (isinf(x)) {
cout << "Безкрайност" << endl;
}
}С всички целочислени типове типовете и с плаващи числа можем да правим всички операции: събиране, изваждане, умножение и деление.