Я делю два числа друг на друга, например 1 / 2 и ожидаю получить в результате 0.5, так как присваиваю результат переменной с плавающей точкой, но получаю 0. Вот код:
#include
int main()
{
double d = 1 / 2;
std::cout << d << "
";
}
0
В чём может быть проблема?
Ответ
Дело в том, что в C++, а равно как и в C, C#, Java и многих других языках деление целых чисел даёт исключительно целый же результат, т.е. дробная часть просто отбрасывается.
Стандарт языка буквально так это и говорит [expl.mul]
For integral operands the / operator yields the algebraic quotient with any fractional part discarded;
Подобное поведение обусловлено в первую очередь производительность, т.к. целочисленная арифметика обычно работает быстрее арифметики с плавающей точкой.
То, что результат деления целых чисел присваивается переменной с плавающей точкой не влияет на само деление, т.к. присваивание выполняется уже после факта деления. И мы просто инициализируем вещественную переменную d целым значением 0, которое никак не даст нам чего-то с ненулевой дробной частью, например, ожидаемых 0.5
Чтобы всё-таки добиться желаемого результата нужно производить вещественное деление. Для этого достаточно хотя бы один из операндов привести к вещественному типу. Сделать это можно разными способами. Если используется константа, то достаточно дописать в конце неё точку, например:
double d = 1 / 2.;
или
double d = 1. / 2;
Это выглядит минималистично, но иногда несколько странно, т.к. в математике подобная запись не используется. Для большей наглядности стоит добавить .0, получим:
double d = 1.0 / 2;
Если вместо явного числового литерала используется именованная целочисленная переменная, или функция, возвращающая целый тип, то добавлением точки с нулём проблему уже не решить, и нужно выполнять иное приведение типа, т.е. делать static_cast
int one = 1;
int two() { return 2; }
double d = static_cast
Но можно использовать и умножение (или деление) любого операнда на 1.0, что так же преобразует результат, который будет выступать операндом последующего деления, к вещественному типу:
double d = (one * 1.0) / two();
Альтернативным вариантом может быть прибавка (или вычитание) вещественного нуля:
double d = (one + 0.0) / two();
Однако, вариант со static_cast будет более правильным, т.к. такие преобразования всегда легче находить в тексте программы, нежели обычные плавающие константы.
Ну и конечно же, если речь идёт о переменных или функциях, то можно просто изменить их тип:
double one = 1;
double two() { return 2; }
double d = one / two();
В такой ситуации надо не забывать, что использование one и two в других контекстах так же может давать иные результаты, что были раньше. Поэтому задачу всё же лучше локализовать, и не делать всё поголовно в программе вещественного типа, если это требуется только в некоторых частных случаях.
Комментариев нет:
Отправить комментарий