Ні, але так, але, можливо, але, можливо, інакше, але ні.
Як люди вже зазначали, (якщо вважати мову, де додавання є ліво-асоціативним, наприклад, C, C ++, C # або Java), то вираз ((1 + 2) + 3)
точно еквівалентний 1 + 2 + 3
. Вони мають різні способи запису чогось у вихідний код, що матиме нульовий вплив на отриманий машинний код або байт-код.
Так чи інакше, результат буде інструкцією, наприклад, додати два регістри, а потім додати третій, або взяти два значення зі стека, додати його, відсунути назад, потім взяти його та інше і додати їх, або додати три регістри в одна операція або якийсь інший спосіб підсумовувати три числа залежно від того, що є найбільш розумним на наступному рівні (машинний код або байт-код). У випадку з байт-кодом, це, в свою чергу, буде, ймовірно, зазнати подібної реструктуризації в тому, що, наприклад, еквівалент ІЛ цього (який би був серією завантажень у стек, і вискакуючи пари, щоб додати і потім відштовхнути результат) не призвело б до прямої копії цієї логіки на рівні машинного коду, але до чогось більш розумного для цієї машини.
Але у вашому питанні є щось більше.
У випадку будь-якого розумного компілятора C, C ++, Java або C #, я очікую, що результат обох заяв, які ви даєте, матиме такі самі результати, як:
int a = 6;
Чому отриманий код втрачає час, займаючись математикою на буквах? Ніякі зміни стану програми не зупинять результат 1 + 2 + 3
існування 6
, тому саме це повинно входити в код, який виконується. Дійсно, можливо, навіть не про це (залежно від того, що ви робите з цими 6, можливо, ми можемо викинути все це; і навіть C # з його філософією "не оптимізуйте сильно, оскільки тремтіння все одно оптимізує це" або призведе до еквівалент int a = 6
або просто викинути всю річ як непотрібну).
Це, однак, призводить до можливого розширення вашого питання. Розглянемо наступне:
int a = (b - 2) / 2;
/* or */
int a = (b / 2)--;
і
int c;
if(d < 100)
c = 0;
else
c = d * 31;
/* or */
int c = d < 100 ? 0 : d * 32 - d
/* or */
int c = d < 100 && d * 32 - d;
/* or */
int c = (d < 100) * (d * 32 - d);
(Зверніть увагу, що останні два приклади не є дійсними C #, тоді як усе інше тут є, і вони дійсні в C, C ++ та Java.)
Тут ми знову точно еквівалентний код з точки зору виходу. Оскільки вони не є постійними виразами, вони не будуть обчислюватися під час компіляції. Цілком можливо, що одна форма швидша за іншу. Що швидше? Це залежатиме від процесора та, можливо, від деяких довільних відмінностей у стані (тим більше, що якщо один швидший, він, швидше за все, не буде набагато швидшим).
І вони не зовсім пов'язані з вашим запитанням, оскільки вони здебільшого стосуються відмінностей у порядку, в якому щось робиться концептуально .
У кожному з них є підстави підозрювати, що один може бути швидшим за інший. Окремі декременти можуть мати спеціалізовану інструкцію, тому вона (b / 2)--
може бути швидшою, ніж (b - 2) / 2
. d * 32
можливо, може бути вироблено швидше, перетворивши його на d << 5
так, щоб зробити d * 32 - d
швидше, ніж d * 31
. Особливо цікавими є відмінності між останніми двома; одна дозволяє в деяких випадках пропускати обробку, але інша уникає можливості неправильного прогнозування галузей.
Отже, це залишає перед нами два питання: 1. Чи одне насправді швидше, ніж інше? 2. Чи перетворить компілятор повільніший у швидший?
А відповідь - 1. Це залежить. 2. Можливо.
Або розширити, це залежить, оскільки це залежить від розглянутого процесора. Звичайно, існували процесори, де наївний машино-кодовий еквівалент одного був би швидшим, ніж наївний машино-кодовий еквівалент іншого. Протягом історії електронних обчислень не було жодного, який був завжди швидшим (зокрема, елемент помилкового прогнозування галузей не був актуальним для багатьох, коли більш нечастотні процесори були більш поширеними).
Можливо, тому, що існує маса різних оптимізацій, які будуть робити компілятори (і тремтіння, і сценарії), і хоча деякі можуть мати мандат у певних випадках, ми, як правило, зможемо знайти деякі фрагменти логічно еквівалентного коду, які навіть самий наївний компілятор має абсолютно однакові результати та деякі фрагменти логічно еквівалентного коду, де навіть найдосконаліший виробляє швидший код для одного, ніж для іншого (навіть якщо нам доведеться написати щось абсолютно патологічне, щоб довести свою думку).
Це може здатися дуже крихітним питанням оптимізації,
Ні. Навіть при більш складних відмінностях від тих, які я тут навожу, це здається абсолютно хвилюючим питанням, яке не має нічого спільного з оптимізацією. Якщо що, це питання песимізації, оскільки ви підозрюєте, що важче читати ((1 + 2) + 3
може бути повільніше, ніж легше читати 1 + 2 + 3
.
але вибір C ++ над C # / Java / ... - все стосується оптимізації (IMHO).
Якщо це дійсно те, що вибір C ++ над C # або Java був "все про", я б сказав, що люди повинні записати свою копію Stroustrup та ISO / IEC 14882 та звільнити простір свого компілятора C ++, щоб залишити місце для ще кількох MP3-файлів чи чогось іншого.
Ці мови мають різні переваги один над одним.
Один з них полягає в тому, що C ++ все ще швидше і легше у використанні пам'яті. Так, є приклади, коли C # та / або Java швидше і / або мають кращу пам'ять при застосуванні протягом життя, і вони стають все більш поширеними, коли вдосконалені технології покращуються, але ми все ще можемо очікувати, що середня програма, написана на C ++, буде менший виконуваний файл, який виконує свою роботу швидше і використовує менше пам'яті, ніж еквівалент на будь-якій з цих двох мов.
Це не оптимізація.
Оптимізація іноді використовується для того, щоб означати "швидше робити справи". Це зрозуміло, тому що часто, коли ми справді говоримо про "оптимізацію", ми дійсно говоримо про те, щоб все пішло швидше, і тому одна стала скороченням для іншого, і я визнаю, я неправильно використовую слово таким чином.
Правильне слово "прискорити процес" - це не оптимізація . Правильне слово тут - вдосконалення . Якщо ви внесете зміни в програму, і єдиною змістовною різницею є те, що вона зараз швидша, вона ніяк не оптимізована, це просто краще.
Оптимізація - це коли ми вдосконалюємо певний аспект та / або конкретний випадок. Поширені приклади:
- Зараз це швидше для одного випадку використання, але повільніше для іншого.
- Зараз це швидше, але використовує більше пам’яті.
- Тепер він легший на пам’яті, але повільніше.
- Зараз це швидше, але складніше в обслуговуванні.
- Зараз простіше в обслуговуванні, але повільніше.
Такі випадки були б виправданими, якщо, наприклад:
- Більш швидкий випадок використання є більш поширеним або більш серйозним перешкодою для початку.
- Програма була неприпустимо повільною, і у нас багато оперативної пам'яті.
- Програма була зупинена, оскільки вона використовувала стільки оперативної пам'яті, що витрачала більше часу на обмін, ніж на її надшвидку обробку.
- Програма була неприпустимо повільною, і складніше зрозуміти код добре задокументований і відносно стабільний.
- Програма все ще приємно швидка, і більш зрозуміла база коду дешевше в обслуговуванні та дозволяє зробити інші вдосконалення легшими.
Але такі випадки також не були б виправдані в інших сценаріях: код не був покращений абсолютною непогрішною мірою якості, він був покращений в певному відношенні, що робить його більш придатним для певного використання; оптимізований.
І вибір мови тут впливає, тому що на це можуть вплинути швидкість, використання пам'яті та читабельність, але так само сумісність з іншими системами, доступність бібліотек, наявність часу виконання, зрілість цих режимів роботи для даної операційної системи (за мої гріхи я якось закінчився тим, що Linux і Android були моїми улюбленими ОС і C # як моя улюблена мова. Хоча Mono є чудовим, але я все-таки зустрічаюся проти цього).
Скажіть, що "вибір C ++ над C # / Java / ... - це все, що стосується оптимізації", має сенс лише, якщо ви думаєте, що C ++ справді відстійний, оскільки оптимізація - це "краще, незважаючи на ...", а не "краще". Якщо ви вважаєте, що C ++ краще, незважаючи на себе, то останнє, що вам потрібно, - це турбуватися про такі хвилини можливих мікроопцій. Дійсно, вам, мабуть, краще взагалі відмовитися від цього; щасливі хакери - це якість, яку також оптимізувати!
Якщо ви схильні сказати: "Я люблю C ++, і одна з речей, яку я люблю, - це вичавлення зайвих циклів", то це вже інша справа. Все ж таки випадок, що мікроопції варті лише того, якщо вони можуть бути рефлексивною звичкою (тобто спосіб, який ви, як правило, кодуєте природним чином, буде швидше швидше, ніж повільніше). Інакше вони навіть не передчасна оптимізація, це передчасна песимізація, яка просто погіршує ситуацію.