Наткнулся на неожиданное поведение вычислений в программе:
int main()
{
unsigned int z = 176400;
long a = -4;
long b = a*z/1000; //b=4294261
long c = a*z; // c=-705600
long d = c/1000; // d =-705
return 0;
}
В комментариях — текущий результат вычисления.
Компилятор Visual C++ 2005
Почему b не равно d
Кстати, если убрать unsigned (т.е. сделать z знаковым), то b =-705.
Здравствуйте, 7C, Вы писали:
7C>Наткнулся на неожиданное поведение вычислений в программе:
7C>
7C>int main()
7C>{
7C> unsigned int z = 176400;
7C> long a = -4;
//b - это преобразованный к long результат деления беззнакового a*z на 1000
// тоесть 0xfff53bc0 сначала делится на 1000, а потом кастится к знаковому
7C> long b = a*z/1000; //b=4294261
//здесь беззнаковое a*z (0xfff53bc0) сначала кастится к long(-705600), а потом аж делится на тыщу
7C> long c = a*z; // c=-705600
7C> long d = c/1000; // d =-705
7C> return 0;
7C>}
7C>
7C>В комментариях — текущий результат вычисления. 7C>Компилятор Visual C++ 2005 7C>Почему b не равно d
7C>Кстати, если убрать unsigned (т.е. сделать z знаковым), то b =-705.
Здравствуйте, 7C, Вы писали:
7C>Наткнулся на неожиданное поведение вычислений в программе:
7C>
7C>int main()
7C>{
7C> unsigned int z = 176400;
7C> long a = -4;
7C> long b = a*z/1000; //b=4294261
7C> long c = a*z; // c=-705600
7C> long d = c/1000; // d =-705
7C> return 0;
7C>}
7C>
7C>В комментариях — текущий результат вычисления. 7C>Компилятор Visual C++ 2005 7C>Почему b не равно d 7C>Кстати, если убрать unsigned (т.е. сделать z знаковым), то b =-705.
Здравствуйте, Seon, Вы писали:
S>Здравствуйте, 7C, Вы писали:
7C>>Наткнулся на неожиданное поведение вычислений в программе:
7C>>
7C>>int main()
7C>>{
7C>> unsigned int z = 176400;
7C>> long a = -4;
7C>> long b = a*z/1000; //b=4294261
7C>> long c = a*z; // c=-705600
7C>> long d = c/1000; // d =-705
7C>> return 0;
7C>>}
7C>>
7C>>В комментариях — текущий результат вычисления. 7C>>Компилятор Visual C++ 2005 7C>>Почему b не равно d 7C>>Кстати, если убрать unsigned (т.е. сделать z знаковым), то b =-705.
S>Переставь а и z местами.
Не выйдет. Нужно явно привести типы. long b = (int)(a*z)/1000;
K> //b — это преобразованный к long результат деления беззнакового a*z на 1000 K> // тоесть 0xfff53bc0 сначала делится на 1000, а потом кастится к знаковому
Я всю жизнь считал, что тип определяется первым операндом умножения (и деления), т.е. тип a*z должен быть long!
Здравствуйте, 7C, Вы писали:
7C>Здравствуйте, kankan, Вы писали:
K>> //b — это преобразованный к long результат деления беззнакового a*z на 1000 K>> // тоесть 0xfff53bc0 сначала делится на 1000, а потом кастится к знаковому
7C>Я всю жизнь считал, что тип определяется первым операндом умножения (и деления), т.е. тип a*z должен быть long!
Тем более, что
Здравствуйте, 7C, Вы писали:
7C>Я всю жизнь считал, что тип определяется первым операндом умножения (и деления), т.е. тип a*z должен быть long!
Это неверно. Тип выражения определяется типом "максимального" операнда, и при этом совершенно неважно, на каком месте в выражении он находится.
5/9
Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield
result types in a similar way. The purpose is to yield a common type, which is also the type of the result.
This pattern is called the usual arithmetic conversions, which are defined as follows:
— If either operand is of type long double, the other shall be converted to long double.
— Otherwise, if either operand is double, the other shall be converted to double.
— Otherwise, if either operand is float, the other shall be converted to float.
— Otherwise, the integral promotions (4.5) shall be performed on both operands.54)
— Then, if either operand is unsigned long the other shall be converted to unsigned long.
— Otherwise, if one operand is a long int and the other unsigned int, then if a long int can represent
all the values of an unsigned int, the unsigned int shall be converted to a long int;
otherwise both operands shall be converted to unsigned long int.
— Otherwise, if either operand is long, the other shall be converted to long.
— Otherwise, if either operand is unsigned, the other shall be converted to unsigned.
[Note: otherwise, the only remaining case is that both operands are int ]
Здравствуйте, Bell, Вы писали:
B>Это неверно. Тип выражения определяется типом "максимального" операнда, и при этом совершенно неважно, на каком месте в выражении он находится.
B>
B>5/9
B>Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield
B>result types in a similar way. The purpose is to yield a common type, which is also the type of the result.
B>This pattern is called the usual arithmetic conversions, which are defined as follows:
B>— If either operand is of type long double, the other shall be converted to long double.
B>— Otherwise, if either operand is double, the other shall be converted to double.
B>— Otherwise, if either operand is float, the other shall be converted to float.
B>— Otherwise, the integral promotions (4.5) shall be performed on both operands.54)
B>— Then, if either operand is unsigned long the other shall be converted to unsigned long.
B>— Otherwise, if one operand is a long int and the other unsigned int, then if a long int can represent
B>all the values of an unsigned int, the unsigned int shall be converted to a long int;
B>otherwise both operands shall be converted to unsigned long int.
B>— Otherwise, if either operand is long, the other shall be converted to long.
B>— Otherwise, if either operand is unsigned, the other shall be converted to unsigned.
B>[Note: otherwise, the only remaining case is that both operands are int ]
Здравствуйте, Seon, Вы писали:
S>>>Переставь а и z местами. НС>>Не выйдет. Нужно явно привести типы. long b = (int)(a*z)/1000;
S>Та знаю, Это я Бориса приколол.
7C>Здравствуйте, Bell, Вы писали:
B>>Это неверно. Тип выражения определяется типом "максимального" операнда, и при этом совершенно неважно, на каком месте в выражении он находится.
B>>
B>>5/9
B>>Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield
B>>result types in a similar way. The purpose is to yield a common type, which is also the type of the result.
B>>This pattern is called the usual arithmetic conversions, which are defined as follows:
B>>— If either operand is of type long double, the other shall be converted to long double.
B>>— Otherwise, if either operand is double, the other shall be converted to double.
B>>— Otherwise, if either operand is float, the other shall be converted to float.
B>>— Otherwise, the integral promotions (4.5) shall be performed on both operands.54)
B>>— Then, if either operand is unsigned long the other shall be converted to unsigned long.
B>>— Otherwise, if one operand is a long int and the other unsigned int, then if a long int can represent
B>>all the values of an unsigned int, the unsigned int shall be converted to a long int;
B>>otherwise both operands shall be converted to unsigned long int.
B>>— Otherwise, if either operand is long, the other shall be converted to long.
B>>— Otherwise, if either operand is unsigned, the other shall be converted to unsigned.
B>>[Note: otherwise, the only remaining case is that both operands are int ]
Нет, все равно не понимаю!
Тут должно работать следующее правило (выделенное):
Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield
result types in a similar way. The purpose is to yield a common type, which is also the type of the result.
This pattern is called the usual arithmetic conversions, which are defined as follows:
— If either operand is of type long double, the other shall be converted to long double.
— Otherwise, if either operand is double, the other shall be converted to double.
— Otherwise, if either operand is float, the other shall be converted to float.
— Otherwise, the integral promotions (4.5) shall be performed on both operands.54)
— Then, if either operand is unsigned long the other shall be converted to unsigned long.
— Otherwise, if one operand is a long int and the other unsigned int, then if a long int can represent
all the values of an unsigned int, the unsigned int shall be converted to a long int;
otherwise both operands shall be converted to unsigned long int.
— Otherwise, if either operand is long, the other shall be converted to long.
— Otherwise, if either operand is unsigned, the other shall be converted to unsigned.
[Note: otherwise, the only remaining case is that both operands are int ]
Честно говоря, это правило непонятно для меня (точнее непонятна его двойственность).
Ну да бог с ним.
Но это правило мне не объясняет почему по-разному обрабатываются строки:
long b = a*z/1000; //b=4294261long c = a*z; // c=-705600
P.S. Явное приведение типов [(int)x или int(x)] меня мало интересует (это всё я знаю). Меня смущает неожиданное и неопределенное поведение компилятора.
Здравствуйте, 7C, Вы писали:
7C>Но это правило мне не объясняет почему по-разному обрабатываются строки: 7C>
7C>long b = a*z/1000; //b=4294261
7C>long c = a*z; // c=-705600
7C>
kankan в первом же ответе четко расписал:
//b — это преобразованный к long результат деления беззнакового a*z на 1000
// то есть 0xfff53bc0 сначала делится на 1000, а потом кастится к знаковому
long b = a*z/1000; //b=4294261
//здесь беззнаковое a*z (0xfff53bc0) сначала кастится к long(-705600), а потом аж делится на тыщу
long c = a*z; // c=-705600
long d = c/1000; // d =-705
7C>Меня смущает неожиданное и неопределенное поведение компилятора.
Здравствуйте, 7C, Вы писали:
7C>Нет, все равно не понимаю! 7C>Тут должно работать следующее правило (выделенное): 7C>
7C>— Otherwise, if one operand is a long int and the other unsigned int, then if a long int can represent
7C>all the values of an unsigned int, the unsigned int shall be converted to a long int;
7C>otherwise both operands shall be converted to unsigned long int.
7C>
7C>Честно говоря, это правило непонятно для меня (точнее непонятна его двойственность). 7C>Ну да бог с ним.
В нашем случае long int не может "вместить" unsigned int (т.к. и int и long по 4 байти), поэтому все операнды преобразуются в unsigned long. 7C>Но это правило мне не объясняет почему по-разному обрабатываются строки: 7C>
7C>long b = a*z/1000; //b=4294261
7C>long c = a*z; // c=-705600
7C>
7C>P.S. Явное приведение типов [(int)x или int(x)] меня мало интересует (это всё я знаю). Меня смущает неожиданное и неопределенное поведение компилятора.
Мне кажется, что тебя сбивает с толку тот факт, что выражение
long c = a*z; // c=-705600
дает ожидаемый результат.
Попробуй записать все это вот так:
unsigned int z = 176400;
long a = -4;
double dd = (unsigned long)a * (unsigned long)z;
long d = (long)dd;
ну или даже вот так:
unsigned int z = 176400;
long a = -4;
unsigned long ua = (unsigned long)a;
double dd = ua * (unsigned long)z;
long d = (long)dd;
Здравствуйте, 7C, Вы писали:
7C>Наткнулся на неожиданное поведение вычислений в программе:
Всё ожиданно, если ты напишешь типы выражений и подвыражений.
1) Когда в операции участвуют знаковый и беззнаковый аргументы, то знаковый приводится к соответствующему беззнаковому
2) Затем аргументы приводятся к максимальному из участвующих типов
Поэтому long*uint -> ulong*uint -> ulong*ulong
(Это я так, на пальцах — подробнее см. стандарт, 4.7)
Смотрим, что вышло по дефолту
7C>int main()
7C>{
7C> unsigned int z = 176400;
7C> long a = -4;
7C> long b = long(ulong(a)*ulong(z)/ulong(1000)); //b=4294261 = 0xFFFFFFFB * 176400 / 1000
7C> long c = long(ulong(a)*ulong(z)); // c=-705600
7C> long d = c/long(1000); // d =-705
7C> return 0;
7C>}
Т.е.
ulong uaz = a*z; // нечто, безусловно неотрицательноеlong saz = uaz; // поскольку uaz > LONG_MAX, т.е. его старший бит взведён, получили отрицательное числоlong b = uaz/1000; // деление на 1000 обеспечивает попадание внутрь диапазона 0..LONG_MAXlong d = saz/1000; // деление отрицательного числа - получили отрицательное
7C>int main()
7C>{
7C> unsigned int z = 176400;
7C> long a = -4;
7C> long b = a*z/1000; //b=4294261
7C> long c = a*z; // c=-705600
7C> long d = c/1000; // d =-705
7C> return 0;
7C>}
7C>
7C>Компилятор Visual C++ 2005
Щас проверил на Borland C++ 3.0
Результаты те же.
В коде оба умножения делаются знаковые.
Первое деление беззнаковое, второе знаковое.