реклама на сайте
подробности

 
 
> IAR C умножение int x int = long, Странность компилятора, или я что-то не допонимаю
Д_М
сообщение Jun 22 2013, 21:01
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 121
Регистрация: 15-04-05
Из: Краснодар
Пользователь №: 4 185



Здравствуйте!
Перенёс код алгоритма, отлизанный при помощи C Builder, на IAR - не работает. После долгих поисков выявил, что когда умножаются два числа int, а частное long, старшие 16 бит частного всегда равны нулю. Когда сделал множителе тоже long всё нормально. Как-то странно. Другие компиляторы наоборот выдают придупреждения, когда разрядность частного не больше, чем разрядность множителей - char/int, или int/long...
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
Xenia
сообщение Dec 10 2013, 00:05
Сообщение #2


Гуру
******

Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237



Цитата(Д_М @ Jun 23 2013, 01:01) *
После долгих поисков выявил, что когда умножаются два числа int, а частное long, старшие 16 бит частного всегда равны нулю. Когда сделал множителе тоже long всё нормально. Как-то странно. Другие компиляторы наоборот выдают придупреждения, когда разрядность частного не больше, чем разрядность множителей - char/int, или int/long...


Это правила языка C таковы - операции над int-операндами он делает в разрядной сетке int, и не обязан расширять результат до long, даже если тот в int не помещается. Другое дело, если один из операндов уже long, тогда и второй операнд тоже будет приведен к типу long, и операция между ними будет произведена в разрядной сетке long. Т.е. забота о типах - это дело программиста, а не компилятора. И если результат умножения двух int-сомножителей требуется перемножать, как long, то следует хотя бы один из сомножителей конвертировать в long-тип явно. Например, так:
Код
int m=20000, n=30000;
long result = (long)m*n;

Причем, понимать эту запись надо не так, что преобразование типа (long) конвертирует результат умножения m*n в long, а так, что оно конвертирует первый сомножитель m из типа int в тип long, после чего компилятор обязан будет их перемножать, как long'и.

Далее. Вы ошибаетесь, в утверждении "другие компиляторы выдают придупреждения, когда разрядность частного не больше, чем разрядность множителей - char/int, или int/long...". Предупреждения выдаются в противоположном случае - когда результат операции не лезет туда, куда его пытаются положить. Вот тогда компилятор и предупреждает о вынужденном округлении или усечении результата. А присваивание короткого длинному вполне законно.

Случай
int = int/long
выдаст предупреждение, но исключением он не является, т.к. здесь один из операндов деления (делитель) имеет тип long, что, в соответствии с правилами, приведет к выполнению деления в разрядной сетке long. По этой причине и результат деления тоже получится long. А засовывание long-результата (частного) в int будет сопровожаться предупреждением о вынужденном урезании. По той же причине результат char/int назад в char без предупреждения не полезет, поскольку будет формально считаться уже int'ом.

Рекомендация вам будет такая: обращайте внимание на то, какого типа у вас операнды. Именно это определяет разрядную сетку, в которой произойдет операция, а вовсе не то, большие числа у вас там лежат или маленькие. Ведь это же компилятор, а не интерпретатор, а потому он компилирует, заранее не анализируя, какие там получатся числа. Об этом должен думать программист, а не компилятор. Например:
Код
int m=20000
long n=1000;
long result = m/n;

Такая запись предупреждения не вызовет, но откомпилируется неоптимально (долго для 8-битников), т.к. делитель типа long обязывает компилятор и делимое тоже превратить в long, а потом делить их друг на друга в разрядной сетке long. Но вы-то понимаете, что результат m/n целочисленен и длиннее int быть не может. Тогда вы должны подсказать компилятору, что n у вас короче long'а:
Код
int m=20000
long n=1000;
long result = m/(int)n;

В последней записи вы сами явно усекаете n до int, чем разрешаете компилятору делить в разрядной сетке int (более быстро).

И наконец. Для умножения char на char с получением результата типа int в компиляторе IAR существует предельно эффективный способ, минуя необходимость совершать умножение в разрядной сетке int. Речь идет встроенных функциях
__intrinsic unsigned int __multiply_unsigned(unsigned char, unsigned char);
__intrinsic signed int __multiply_signed(signed char, signed char);
__intrinsic signed int __multiply_signed_with_unsigned(signed char, unsigned char);
описанных в хидере intrinsics.h
Эти функции позволяют при умножении обходить правила языка C для бинарных операций. Однако для деления таких функций нет.
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 31st July 2025 - 20:44
Рейтинг@Mail.ru


Страница сгенерированна за 0.01371 секунд с 7
ELECTRONIX ©2004-2016