Почему деление двух int не дает правильного значения, когда присваивается значение double? - PullRequest
90 голосов
/ 27 сентября 2011

Как получается, что в следующем фрагменте

int a = 7;
int b = 3;
double c = 0;
c = a / b;

c заканчивается значением 2, а не 2.3333, как можно было бы ожидать.Если a и b являются двойными, ответ превращается в 2.333.Но, конечно, потому что c уже является двойным, он должен был работать с целыми числами?

Так почему же int/int=double не работает?

Ответы [ 8 ]

143 голосов
/ 27 сентября 2011

Это потому, что вы используете целочисленное деление версии operator/, которое занимает 2 int с и возвращает int. Чтобы использовать версию double, которая возвращает double, по крайней мере, один из int должен быть явно приведен к double.

c = a/(double)b;
11 голосов
/ 27 сентября 2011

Вот оно:

a) Деление двух int s всегда выполняет целочисленное деление. Таким образом, результат a/b в вашем случае может быть только int.

Если вы хотите оставить a и b как int с, но разделить их полностью, вы должны разыграть хотя бы один из них, чтобы удвоить: (double)a/b или a/(double)b или (double)a/(double)b.

b) c является double, поэтому он может принимать int значение при назначении: int автоматически преобразуется в double и присваивается c.

c) Помните, что при присваивании выражение справа от = вычисляется first (в соответствии с правилом (a) выше и без учета переменной слева от =) ) и , затем присваивается переменной слева от = (согласно (b) выше). Я считаю, что это завершает картину.

9 голосов
/ 27 сентября 2011

За очень немногими исключениями (я могу думать только об одном), C ++ определяет весь смысл выражения (или под-выражения) из самого выражения.То, что вы делаете с результатами выражения, не имеет значения.В вашем случае в выражении a / b не видно double;все int.Таким образом, компилятор использует целочисленное деление.Только получив результат, он решает, что с ним делать, и конвертирует его в double.

6 голосов
/ 27 сентября 2011

Когда вы делите два целых числа, результатом будет целое число, независимо от того, что вы храните его в двойном числе.

5 голосов
/ 27 сентября 2011

c является переменной double, но присваиваемое ей значение является значением int, поскольку оно является результатом деления двух int с, что дает вам "целочисленное деление" (удаление остатка ). Так что в строке c=a/b происходит

  1. a/b оценивается, создавая временный тип int
  2. значение временного объекта присваивается c после преобразования в тип double.

Значение a/b определяется без ссылки на его контекст (присвоение double).

4 голосов
/ 27 сентября 2011

В языке C ++ на результат подвыражения никогда не влияет окружающий контекст (за редкими исключениями). Это один из принципов, которым тщательно следует язык. Выражение c = a / b содержит независимое подвыражение a / b, которое интерпретируется независимо от всего, что находится за пределами этого подвыражения. Для языка не важно, что вы позже назначите результат для double. a / b - целочисленное деление. Все остальное не имеет значения. Вы увидите, что этот принцип соблюдается во многих уголках спецификации языка. Вот как работает C ++ (и C).

Одним из примеров исключения, которое я упомянул выше, является назначение / инициализация указателя функции в ситуациях с перегрузкой функции

void foo(int);
void foo(double);

void (*p)(double) = &foo; // automatically selects `foo(fouble)`

Это один контекст, в котором левая сторона присваивания / инициализации влияет на поведение правой стороны. (Кроме того, инициализация ссылки на массив предотвращает затухание типа массива, что является еще одним примером подобного поведения.) Во всех других случаях правая часть полностью игнорирует левую часть.

4 голосов
/ 27 сентября 2011

Оператор / может использоваться для целочисленного деления или деления с плавающей запятой.Вы даете ему два целочисленных операнда, поэтому он выполняет целочисленное деление, а затем результат сохраняется в двойном.

2 голосов
/ 27 сентября 2011

Технически это зависит от языка, но почти все языки относятся к этому предмету одинаково.В случае несоответствия типов между двумя типами данных в выражении большинство языков пытаются преобразовать данные на одной стороне =, чтобы сопоставить данные на другой стороне в соответствии с набором предопределенных правил.

При делении двух чисел одного типа (целых, двойных и т. Д.) Результат всегда будет одного и того же типа (поэтому int / int всегда будет приводить к int).

В этом случаеу вас есть double var = integer result, который приводит к целочисленному результату двойному после вычисления , и в этом случае дробные данные уже потеряны.(большинство языков будет выполнять это приведение, чтобы предотвратить неточности типа без возникновения исключения или ошибки).

Если вы хотите сохранить результат в двойном размере, вы захотите создать ситуацию, в которой у вас естьdouble var = double result

Самый простой способ сделать это - заставить выражение в правой части уравнения привести к удвоению:

c = a/(double)b

Деление междуinteger и double приведут к приведению целого числа к двойному (обратите внимание, что при выполнении математических операций компилятор часто «переводит» к наиболее конкретному типу данных, чтобы предотвратить потерю данных).

После преобразования, a окажется двойным, и теперь у вас есть деление на два двойных.Это создаст желаемое разделение и назначение.

СНОВА, обратите внимание, что это зависит от языка (и может даже зависеть от компилятора), однако почти все языки (конечно, все те, которые я могу)подумай над головой) относись к этому примеру одинаково.

...