Как сравнить int, float и double¶
К общим материалам · К лабораторным
Что именно сравниваем¶
Для простого эксперимента возьмите небольшие целые исходные данные. Прочитайте
их один раз в int, проверьте и скопируйте в float и double. Если исходные числа
точно представимы во всех трёх типах, можно отдельно исследовать различия при вычислениях.
Выполните одну формулу три раза, сохраняя её скобки и порядок операций. Менять тип
только у переменной результата недостаточно: важны типы операндов справа от =.
Для среды MSVC используются 32-битный int, 32-битный float и 64-битный double.
До эксперимента убедитесь, что промежуточные целочисленные результаты укладываются
в диапазон int.
Переполнение не является способом показать «неточность» целых чисел.
Целочисленное деление¶
int a = 10;
int b = 3;
double wrong = a / b;
Здесь сначала выполняется деление двух int: получается 3. Затем 3 преобразуется
в double. Дробная часть уже потеряна. Целочисленное деление отбрасывает дробную
часть к нулю; это не округление к ближайшему целому.
Чтобы разделить в вещественном типе, сначала подготовьте операнды нужного типа.
Небольшой пример трёх расчётов¶
Это фрагмент для размещения внутри main; исходные числа в вашей программе
должны поступать через scanf_s.
int a_i = 10;
int b_i = 3;
float a_f = a_i;
float b_f = b_i;
double a_d = a_i;
double b_d = b_i;
int result_i = a_i / b_i;
float result_f = a_f / b_f;
double result_d = a_d / b_d;
printf("int: %d\n", result_i);
printf("float: %.9f\n", result_f);
printf("double: %.17lf\n", result_d);
Ожидаемый вывод для обычных IEEE 754 float и double с округлением к ближайшему:
int: 3
float: 3.333333254
double: 3.33333333333333348
Математический ответ — точная дробь 10/3. Она не имеет конечной двоичной записи.
Поэтому оба вещественных типа хранят приближение. Для примера 12/4 все три
результата равны 3: различие типов не обязано проявляться на каждом вводе.
Константы тоже влияют на вычисление¶
Если в формуле есть числовая константа, запишите её в соответствующем типе.
| Расчёт | Константа 60 | Константа 1000 |
|---|---|---|
int |
60 |
1000 |
float |
60.0f |
1000.0f |
double |
60.0 |
1000.0 |
Суффикс f обозначает литерал float. Литерал 60.0 имеет тип double и может
перевести часть выражения с float в вычисление с большей точностью. В данном
эксперименте смешивать типы внутри одного расчёта не нужно.
Значащие цифры и цифры после точки¶
В обычной реализации MSVC у float около 6–7 значащих десятичных цифр, у double
около 15–16. Это количество значащих цифр всего числа, а не фиксированное количество
знаков после точки. См. описание типов Microsoft.
Для исследования выводите float через %.9f, а double через %.17lf.
Это девять и семнадцать знаков после точки соответственно. Такое форматирование
не увеличивает точность вычислений: часть напечатанных разрядов показывает округление.
Число знаков после точки не равно числу достоверных значащих цифр.
Для очень малых значений различие может оказаться дальше выбранного числа знаков.
Короткая печать через %.2f для float и %.2lf для double тоже может скрыть различие.
Как записывать ожидания и сравнивать с эталоном¶
Сначала подставьте входы в математическую формулу и получите точную дробь либо
десятичное число высокой точности. Ожидаемый результат int найдите по правилам
целочисленных операций в указанном порядке. Для float и double можно указать
приближённый эталон и допуск, не угадывая все последние разряды.
Допуски и требуемые форматы вывода задаются в условиях конкретной лабораторной. Их нельзя автоматически переносить на другой алгоритм: ошибка зависит в том числе от числа и порядка операций.
Если хотите численно оценить ошибку, абсолютная погрешность равна
|полученный результат - математический эталон|. Для ненулевого эталона её можно
разделить на |эталон| и получить относительную погрешность.
Разность ответов float и double сама по себе не является точной ошибкой float:
double тоже округляет.
Что написать в выводах¶
Укажите конкретные входы и результаты. Объясните, на каких наборах ответы совпали,
а на каких различаются. Назовите операцию, при которой потерялась дробная часть
в int. Отдельно объясните различие float и double и влияние формата печати.
При желании повторите печать с %.2f для float и %.2lf для double
и проверьте, какие отличия перестали быть видны.