Арифметические операции в языке Си, типы

1. roman77 332 21.09.18 15:27 Сейчас в теме
Классический язык программирования Си.
Есть, допустим, такая операция присваивания:

f=1+3*4/6;

В арифметическом выражении нет переменных.

Результат арифметического выражения рассчитывается в ходе выполнения кода, или же компилятор рассчитывает его на стадии компиляции и в код помещает f=3 ?
По теме из базы знаний
Ответы
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
3. kuzev 47 21.09.18 16:02 Сейчас в теме
(1) О, пятничный вопрос =)
В ходе компиляции получится f=3
Как нам говорили в университете на первых курсах: "в военное время синус может равняться 2".
10. protexprotex 115 21.09.18 21:54 Сейчас в теме
(1) Компилятор ничего не расчитывает - а переводит программу на машинные команды (например, в exe файл) - и потом уже когда запускаете этот exe файл он выполняется на процессоре. А вот транслятор уже выполняет саму программу без перевода в машинные команды - правда, предварительно для оптимизации транслятор переводит программу в байт - код - но это тоже не машинные команды, а просто более удобное для транслятора представление. Также применяется перевод в обратную польскую запись.
11. spacecraft 21.09.18 22:19 Сейчас в теме
(10) какой транслятор для скомпилированной программы на языке си (именно чистый си указан в заголовке) транслирует и куда?
Про оптимизирующую компиляцию упоминать не стоит?
Если в выражении переменной происходит статический расчет, то оптимизатор ее сразу же вычислит и подставит результат. Тоже самое и с конкатенацией строк.
Допускаю, что существуют компиляторы без оптимизаций, или ее возможно отключить. Но в большинстве случае именно так и происходит.
13. protexprotex 115 21.09.18 23:07 Сейчас в теме
(11) Вы о чем? при чем тут то, что Вы написали. Я писал о том, что транслятор может и не вычислить выражение, а компилятор вычислит сразу же и подставит 3 - т.к. в выражении нет ссылок на переменные - одни числа.
14. spacecraft 21.09.18 23:41 Сейчас в теме
(13)
Я писал о том, что транслятор может и не вычислить выражение, а компилятор вычислит сразу же и подставит 3 - т.к. в выражении нет ссылок на переменные - одни числа.

Компилятор ничего не расчитывает - а переводит программу на машинные команды (например, в exe файл) - и потом уже когда запускаете этот exe файл он выполняется на процессоре.


Вот как это понимать? И причем тут транслятор?
15. alex_sh2008 4 22.09.18 23:29 Сейчас в теме
(1)f=3, вычислит во время компиляции в объектный код
17. spacecraft 23.09.18 00:13 Сейчас в теме
(1) есть более интересная особенность таких вычислений.
Вот, пример:
float x = 4/6;
int f = 1+3*x;

Чему будет равен f ?

Даже если взять полностью предложенный пример в (1), то он будет работать ожидаемо только из-за пограничного условия: целочисленное деление. Усложним:
int f = 1+4/6*3;

Чему теперь равен f?
18. alex_sh2008 4 23.09.18 09:45 Сейчас в теме
(17)В обоих примерах будет зависит от типа компиляции 32 или 64 разрядная, в любом случае будет усечение результата, в первом примера 2 усечения, double в float и double в int, во втором одно double в int
19. spacecraft 23.09.18 10:49 Сейчас в теме
(18) в том то и дело, что пример выше не будет так выполнен. 4/6 это тип int поделенный на тип int. Результат такого деления будет тип int. Итого имеем, что 4/6 будет равен 0.
Даже float x = 4/6 будет равен 0. Автоприведение типов применяется уже к результату вычисления.
Следовательно в обоих случаях f = 1. Неожиданный результат в итоге.
Чтобы результат вычисления был ожидаемым, необходимо осуществить явное приведение:
int f = 1+((double)4/6)*3;

или указать, что один из операндов тип float(к примеру):
int f = 1+4f/6*3
20. alex_sh2008 4 23.09.18 11:56 Сейчас в теме
(19) По умолчанию компилятор к числовым константам применят тип double, а результат приводит к типу переменной, то есть будет усечение результата double до float, а усечение double до int приведет к усечение до разрядности которая определена для текущей платформы компиляции. В обоих случаях результаты непредсказуемые, в вашем новом примере вы даете явное указание компилятору какие типы использовать при вычислении.
21. spacecraft 23.09.18 13:05 Сейчас в теме
(20) компилятор тут не причем. В языке си есть стандарт: При делении значение целого типа на значение целого типа результат тоже получается целого типа. Компилятор не может применять к константе целого числа тип double.
22. alex_sh2008 4 23.09.18 13:46 Сейчас в теме
(21)компилятор приводит к одному типу оба операнда к максимальному по разрядности типу, выражения int f = 1+((double)4/6)*3; и int f = 1+4f/6*3, разные и могут дать разные результаты и соответственно приведение к int то же не предсказуемое. Все 4 примера, результат не предсказуемый, предсказуемый только в том случае когда в результате вычисления результат будет меньше наибольшего числа в типе int.
23. spacecraft 23.09.18 13:56 Сейчас в теме
(22) мы обсуждали float x = 4/6; и int f = 1+4/6*3;
Для них никакие double не влияют.
24. alex_sh2008 4 23.09.18 14:03 Сейчас в теме
(23) зависит от того как компилятор по умолчанию распознает значение 1 как 1 или как 1.0
25. spacecraft 23.09.18 14:09 Сейчас в теме
(24) по правилам самого языка целые константы имеют тип int. Вот его размер может меняться. Но никак не тип double. Вещественные константы имеют отличную от целых типов написание.

Вывод типа от размера целочисленной константы не рассматриваем. Он может и в long его определить. В рассматриваемом примере тип точно int.
26. alex_sh2008 4 23.09.18 14:18 Сейчас в теме
(25) Константы имеют отличное написание, но если записать выражение float i = 4/6 и int i = 4/6 результаты разные, а вычислит он их как double в обоих случаях. Так что выражение 4/6 может иметь и как целое значение и как вещественное.
27. spacecraft 23.09.18 14:26 Сейчас в теме
(26) результат в самой переменной будет разный. Просто разные типы. Вычисление выражения в обоих случаях будет одним и тем же. Целочисленной константой типа int равной 0.
Уже для float i тип int будет неявно приведен к типу float.
28. alex_sh2008 4 23.09.18 14:34 Сейчас в теме
(27) по вашему float i = 4/6 и int i = 4/6 - равные, и результат 0?
29. spacecraft 23.09.18 14:38 Сейчас в теме
(28) именно это я и пытался объяснить. Если не учитывать сам тип, то значение будет одинаковое, равное 0.
30. alex_sh2008 4 23.09.18 14:53 Сейчас в теме
(29)вы заблуждаетесь, я перед этим писал что компилятор приводит к максимальному типу все операнды, по сути такие записи выглядят так:
float i = (float)4/6
int i = (int)4/6
само вычисление зависит от компилятора, какой он алгоритм выберет, в 1 и 2 случае, или так:
float i = (float)(double)4/6
int i = (int)(double)4/6
31. spacecraft 23.09.18 15:04 Сейчас в теме
(30) попробуйте. Есть онлайн компиляторы. Как вариант: https://www.onlinegdb.com/online_c_compiler
int main()
{
float i = 4/6;
printf("%f", i);

return 0;
}

результат: 0.000000
41. YanTsys 12 24.09.18 11:29 Сейчас в теме
(31)
Есть онлайн компиляторы


Спасибо :)
43. roman77 332 25.09.18 09:45 Сейчас в теме
(31) Ещё есть бесплатные. Вот, например, http://orwelldevcpp.blogspot.com/
32. spacecraft 23.09.18 15:07 Сейчас в теме
(30) вот с явным приведением:
int main()
{
float i = (float)4/6;
printf("%f", i);

return 0;
}

результат: 0.666667
33. alex_sh2008 4 23.09.18 15:11 Сейчас в теме
(32)Ну значит правила изменили, раньше компилятор вел себя по другому.
35. spacecraft 23.09.18 15:16 Сейчас в теме
(33) про эту особенность еще Страуструп писал в своей книге. Про деление целых чисел.
36. alex_sh2008 4 23.09.18 15:18 Сейчас в теме
(35)Про деление я читал, просто когда я писал на этом языке у компилятор у таких записей делал не явное преобразование к типу получателю.
37. spacecraft 23.09.18 15:26 Сейчас в теме
(36) так он и приводит к типу получателя, но уже вычисленный результат. Или он прямо все операнды приводил к типу получателя? Это не может быть.
Вот пример:
int a = 1.6*1.6;
В таком случае a должен получиться 1?
38. alex_sh2008 4 23.09.18 15:29 Сейчас в теме
(37)мне достаточно было записать double i = 3 / 15; и я получал нужный результат, может я ему принудительно указывал это сделать, уже не помню, в параметрах компиляции, сейчас он намного строже стал
39. alex_sh2008 4 23.09.18 15:30 Сейчас в теме
(37)результат 2, будет усечение дробной части
34. spacecraft 23.09.18 15:12 Сейчас в теме
(30)
я перед этим писал что компилятор приводит к максимальному типу все операнды

Вот это не совсем верно. Все операнды приводятся к наибольшему из участвующих в операции. Если оба операнда типа int, то и будет тип int.
Если один из операндов типа int, а второй типа double, то оба будут приведены к типу double.
2. Black Cat 32 21.09.18 15:57 Сейчас в теме
Может все-таки f=3 ?
8. roman77 332 21.09.18 16:10 Сейчас в теме
4. soft_wind 21.09.18 16:02 Сейчас в теме
;+)

несколько вопросов/утверждений

1. а какая разница? сразу результат присваивается или вычисляется? все эти простые вычисления за десяток тиков тактовой частоты расчитываются, т.е. какая-то лиллионная доля секунды.
2.нвверно, все-таки зависит от транслятора, многие трансляторы делают предвычисления, и даже с переменными если в них были помещениы константы/числа
3.вообще эта ветка форума по 1С, тут даже как это все в там ПИ код 1С транслируется не заморачиваются, не то что там с ассемблером., .
6. roman77 332 21.09.18 16:09 Сейчас в теме
1. Разные результаты могут быть.

float f;
f=10000*100000;
f+=1;
f-=4*250000000

Дает результат 0.

а если так:
f=10000*100000+1-4*250000000;

то результат 1.

3. Я хотел поместить в ветку "за жизнь", но там совсем не в тему.
9. SlavaKron 21.09.18 16:45 Сейчас в теме
(6) Точность результата до присваивания ограничена только разрядностью cpu/fpu, после - разрядностью/стандартом переменной.
Вместо float вы могли бы взять 8-биное, выражение, записанное в одну строку, был бы тот же.
16. alex_sh2008 4 22.09.18 23:42 Сейчас в теме
(4)Константы с плавающей запятой без суффикса f, F, l или L относятся к типу double. Если суффикс представлен буквой f или F, константа относится к типу float. Если суффикс представлен буквой l или L, константа относится к типу long double.
5. DenisCh 21.09.18 16:04 Сейчас в теме
Зависит от компилятора и уровня оптимизации
7. Timur.V 78 21.09.18 16:09 Сейчас в теме
С++ для начинающих. Обзор компиляторов
Существует множество компиляторов с языка C++, которые можно использовать для создания исполняемого кода под разные платформы. Проекты компиляторов можно классифицировать по следующим критериям.

Чтобы увидеть результат препроцессинга можно воспользоваться опцией...
ссылка
12. KulSer 21.09.18 22:55 Сейчас в теме
Я занимался Си ещё во времена MS DOS. Помню что многое зависит от компилятора.
Если компилятор компилирует "в лоб", то он напишет примерно следующие команды:
записать в регистр процессора число 3
умножить содержимое регистра на 4
разделить полученный результат на 6
добавить к результату 1 (или выполнить инкремент)
занести результат в ячейку памяти, в которой хранится f.
Более продвинутый компилятор еще на этапе компиляции вычислит выражение и запишет его в f.
Как-то так.
40. Green2 29 24.09.18 11:25 Сейчас в теме
В принципе, можно эту программу скомпилировать и посмотреть полученный код в ассемблере.

Интересно, если программа будет скомпилирована на C# в код CLR?
42. YanTsys 12 24.09.18 11:48 Сейчас в теме
Скажем так хороший компилятор обязан оптимизировать программный код с целью ускорения его работы.
Если приведенный вами расчет провести на этапе компиляции и заменить на подстановку готового результата то это будет хорошим примером оптимизации.
Но не каждый компилятор является хорошим поэтому и не каждый выполнит такую оптимизацию.
Поэтому если вы пишете программу в которой скорость является критичной и если тем более вы даже не знаете какой компилятор в итоге это будет обрабатывать то лучше не надеяться на компилятор и подставить рассчитанное значение.
Для обычных пользовательских программ оставлять такую оптимизацию на откуп компилятору и оставлять расчет в наглядном виде для упрощения чтения кода и дальнейшей корректировки программы общепринято и вполне допустимо.
44. user970630 25.09.18 13:05 Сейчас в теме
А что это задачи? Где посмотреть можно?
Оставьте свое сообщение

Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот