Чому в Java / C ++ немає оператора живлення?


23

Поки є такий оператор - **у Python мені було цікаво, чому у Java та C ++ теж немає.

Це легко зробити для класів, які ви визначаєте на C ++, з перевантаженням оператора (і я вважаю, що таке можливо і в Java), але якщо говорити про примітивні типи, такі як int, double і так далі, вам доведеться використовувати бібліотеку функція на зразок Math.power(і зазвичай доводиться кидати обидві, щоб подвоїтись).

Отже - чому б не визначити такого оператора для примітивних типів?


8
У C ++ ми не можемо створити власних операторів. Ви можете перевантажувати лише існуючі оператори.

1
@Mahesh, тому я можу створити свій власний клас чисел і перевантажити ^ оператора, щоб бути владою. Це дійсно не має значення.

22
@RanZilber: Це має значення, тому що пріоритет ^оператора не відповідає перевазі експоненції. Розглянемо вираз a + b ^ c. У математиці спочатку виконується експоненція ( b ^ c), потім додається отримана сила a. У C ++ додавання виконується спочатку ( a + b), потім ^виконується оператор c. Тож навіть якщо ви реалізували ^оператора з метою експоненції, пріоритет здивує всіх.
In silico

2
@RamZilber - ^це XOR в C ++. Рекомендується, що перевантажений оператор не повинен відрізнятися від того, який робить примітивний тип даних за допомогою нього.

4
@RanZilber: Тому що не зовсім інтуїтивно використовувати будь-який з тих операторів, яких ви згадуєте, означати експоненцію. Я б серйозно поставив під сумнів компетентність будь-якого програміста на C ++, який перевантажує ++оператора або !оператора тощо. ін. означати експоненцію. Але ви все одно не можете, тому що оператори, про яких ви говорите, приймають лише один аргумент; експоненція вимагає двох аргументів.
Силіко

Відповіді:


32

Взагалі кажучи, примітивні оператори в C (і за допомогою розширення C ++) розроблені таким чином, щоб їх можна було реалізувати простим обладнанням приблизно в одній інструкції. Щось на зразок експоненції часто вимагає програмного забезпечення; тому його немає за замовчуванням.

Крім того, вона надається стандартною бібліотекою мови у вигляді std::pow.

Нарешті, робити це для цілих типів даних не має особливого сенсу, оскільки більшість навіть малих значень для експоненціації видувають діапазон, необхідний для int, тобто до 65535. Звичайно, ви можете зробити це для парних і плаваючих, але не вбудованих, але чому мова робить непослідовною для рідко використовуваної функції?


4
Хоча я погоджуюсь із більшою частиною цього, той факт, що оператор модуля не може бути використаний для типів з плаваючою точкою, є несуперечливим для примітивних типів даних, але це, мабуть, не було б єдиною інструкцією на будь-якому апаратному забезпеченні, я думаю, будь-яким чином переважає зараз.

@Sion: Принаймні на x86 модуль - це одна інструкція. ( DIVчи є поділ, так і модуль) Хоча ви поставили мене на точку узгодженості.
Біллі ONeal

@Billy ONeal: Модуль плаваючої точки в одній інструкції? Я не пізніше гуртувався в зборах, як пізно, щоб знати про себе. Якщо це так, то оператор модуля повинен бути застосований до типів з плаваючою точкою.

3
@DonalFellows: FORTRAN мав оператора експоненції задовго до того, як у нього було щось, що нагадувало підтримку bignum.
supercat

1
@DonalFellows: Енергооператор не настільки корисний з цілими числами, як з поплавками, але для малих потужностей (особливо квадратиків) він, безумовно, може використовувати його. Особисто мені подобається підхід до створення операторів з літер (як це робить Паскаль divабо FORTRAN .EQ.); залежно від правил пробілу мови, можливо, можливо мати довільну кількість операторів, не вимагаючи, щоб вони були зарезервованими словами.
supercat

41

Це питання відповідає C ++: Stroustrup, "Дизайн та еволюція C ++", обговорює це у розділі 11.6.1, с. 247-250.

Були загальні заперечення щодо додавання нового оператора. Це додало б до вже надто складної таблиці пріоритетів. Члени робочої групи вважали, що це буде лише незначним зручністю щодо функціонування, і вони хотіли, щоб можна було іноді замінити власні функції.

Не було хорошого кандидата на оператора. ^є виключною або ^^запрошеною плутаниною через зв’язок між &і |та &&та ||. !було непридатним, оскільки існувала б природна тенденція писати !=до експоненції існуючої цінності, і це вже було прийнято. Можливо, найкраще було *^, що, мабуть, нікому дуже не сподобалось.

Stroustrup розглянуто **ще раз, але він вже має значення в C: a**pє aрази, на які pвказує, і char ** c;оголошує cяк вказівник на покажчик char. Введення **як лексеми значення "оголошення вказівника на вказівник на", "разів, на що вказує наступне" (якщо це вказівник) або "експоненція" (якщо супроводжується числом), спричинило проблеми пріоритетності. a/b**pповинен був би розібратися так, a/(b**p)ніби р - це число, але (a/b) * *pякби p - вказівник, тож це потрібно було б вирішити в аналізаторі.

Іншими словами, це було б можливо, але це ускладнило б таблицю пріоритету та аналізатор, і обидва вже занадто складні.

Я не знаю історії про Java; все, що я міг би зробити, було б міркувати. Що стосується C, де він запустився, всі оператори C легко переводяться в код складання, частково для спрощення компілятора, а частково для уникнення приховування трудомістких функцій у простих операторів (той факт, що operator+()та інші могли приховати велику складність та ефективність хітів, було одним ранніх скарг на С ++).


2
Гарна відповідь. Я думаю, що Java намагалася спростити C у цьому відношенні, тому ніхто не хотів додати нового оператора. Шкода, що мене ніхто не просив, я, безумовно, хотів би *^. : D
maaartinus

1
C був побудований для форматування тексту. Фортран був побудований, щоб займатися математикою, і мав складну математичну математику на 20 років раніше.
Мартін Беккет

@Martin Beckett: Чи можете ви знайти докази того, що C був побудований для форматування тексту? Мені це здається дуже незграбною мовою, і те, що я читав про походження C, говорить, що воно було розроблене насамперед для системного програмування для Unix.
Девід Торнлі

@DavidThornley - Він був розроблений для запису в Unix, але, як здається, всі раннє використання Unix було форматуванням тексту.
Мартін Беккет

6
+1: Існуюче значення для a**pвбивці. (Хаки вирішувати цю проблему… Брр!)
Донори стипендіатів

13

Я підозрюю, що це тому, що кожен представлений вами оператор збільшує складність мови. Отже, бар'єр для вступу є дуже високим. Я виявляю, що використовую експоненцію дуже, дуже рідко - і я більш ніж радий використовувати заклик методу для цього.



3
Я б користувався x**2і x**3не дуже рідко. І магічна реалізація, про яку компілятор знає і оптимізує для простих випадків, було б непогано.
CodesInChaos

2
@CodeInChaos: Однак x * xі x * x * xне погані замінники квадрата та куба.
Девід Торнлі

5
@David, ви не можете просто написати, x*xякщо x є виразом. У кращому випадку код стає непростим, а в гіршому повільнішим або навіть неправильним. Тому вам потрібно буде визначити власні функції Square і Cube. І навіть тоді код був би гіршим, ніж використання ** в якості оператора живлення.
CodesInChaos

1
@David Мені потрібно поставити дужки так, але не потрібно повторювати вираз кілька разів і роздуває вихідний код. Що значно знижує читабельність. А загальне усунення субэкспресії можливе лише в тому випадку, якщо компілятор може гарантувати, що вираз не має побічних ефектів. І щонайменше .net тремтіння не надто розумне в цьому плані.
CodesInChaos

11

Дизайнери мови Java та основні бібліотечні бібліотеки вирішили перенести більшість математичних операцій у клас Math . Див. Math.pow () .

Чому? Гнучкість визначати пріоритетність продуктивності над точністю біт за бітом. Буде суперечити решті мовних специфікацій, сказати, що поведінка вбудованих математичних операторів може відрізнятися від платформи до платформи, тоді як клас Math спеціально говорить, що поведінка потенційно приносить точність для продуктивності, тому покупець остерігайтеся:

На відміну від деяких числових методів класу StrictMath , всі реалізації еквівалентних функцій класу Math не визначені для повернення бітових для бітів однакових результатів. Таке розслаблення дозволяє краще реалізовувати реалізацію, коли не потрібно чіткого відтворення.


6

Експоненціація була частиною Фортран з самого початку, оскільки вона була прямо спрямована на наукове програмування. Інженери та фізики використовують його часто для моделювання, тому що правові відносини є загальними у фізиці.

Python також має сильну присутність у наукових обчисленнях (наприклад, NumPy та SciPy). Це, поряд із його оператором експоненції, дозволяє припустити, що воно також спрямоване на наукове програмування.

C, Java і C # мають коріння в системному програмуванні. Можливо, це вплив, який утримував експоненцію від групи підтримуваних операторів.

Просто теорія.


4

C визначені лише оператори для загальних арифметичних операцій, доступних для ALU. Основна його мета - створення зрозумілого для людини інтерфейсу до асемблерного коду.

C ++ не змінив жодної поведінки оператора, оскільки він хотів, щоб вся база коду, написана на C, відповідала.

Java зробила те саме, оскільки не хотіла залякати існуючих програмістів на C ++.


Коли С був створений, множення та ділення нечасто бракувало апаратних засобів, і їх доводилося впроваджувати в програмне забезпечення. Однак C має операторів множення та ділення.
Сіріде

@siride: Наскільки мені відомо, PDP-7, перший комп'ютер, який запустив Unix, мав апаратне множення та поділ через EAE. Дивіться: bitsavers.org/pdf/dec/pdp7/F-75_PDP-7userHbk_Jun65.pdf
Ates

1

Ну тому, що кожен оператор, який би мав сенс для потужності, вже використовується. ^ є XOR і ** визначає вказівник на покажчик. Тож натомість вони просто мають функцію, яка робить те саме. (як pow ())


@RTS - Чи справді розробник лангажу шукає сенсу більше, ніж ефективності?

Хороший розробник мови програмування дивиться на обидва. Я нічого не можу сказати про Java. Але в c ++ функція pow () обчислюється під час компіляції. І це так само ефективно, як і звичайні оператори.

@RTS: pow()Функція виконує обчислення під час виконання, якщо ви не отримали компілятор, який може робити постійне складання pow(), в чому я дуже сумніваюся. (Деякі компілятори дають вам можливість використовувати інтерфейси процесора для виконання обчислення.)
у silico

@ У silico я не мав на увазі, що він обчислює остаточне значення, я мав на увазі, що компілятори оптимізують функцію виклику функції, тому у вас є просто необроблене рівняння.

2
@josefx: Звичайно, це вагома причина. Сингл *- це лексичний знак, незалежно від того, чи він використовується для непрямості чи множення. **Значення експоненцірованіе буде або один або два лексичні маркери, і ви дійсно не хочете , щоб ваш лексичний , щоб потрапити в таблицю символів розмітити.
Девід Торнлі

0

Справа в тому, що арифметичні оператори - це лише ярлики функцій. (Майже) Все, що ви робите з ними, можна виконати за допомогою функції. Приклад:

c = a + b;
// equals
c.set(a.add(b));
// or as free functions
set(c, add(a,b));

Це просто більш багатослівно, тому я не бачу нічого поганого у використанні функцій для виконання "power of".


-1

Додавання / віднімання / заперечення та множення / ділення - основні математичні оператори. Якби ви зробили владу оператором, де б ви зупинилися? Оператор квадратного кореня? N-root оператор? Оператор логарифму?

Я не можу говорити за їхніх творців, але можу сказати, що я думаю, що такі мовні оператори мовою стали б непростими і не ортогональними. Кількість символів, що не містять букв / пробіл, що залишаються на клавіатурі, досить обмежена. Як це не дивно, що в C ++ є оператор модуля.


+1 - Я не бачу, чому modдивно мати оператора. Зазвичай це одна інструкція. Це первісна операція над цілими числами. Він найбільше використовується скрізь в інформатиці. (Реалізація таких речей, як обмежені буфери, не modсмердить)
Біллі ONeal

@Billy ONeal: Дивно через невідповідність між можливістю використовувати цілі типи та типи з плаваючою точкою. Це абсолютно корисно, але я б не мріяв видалити його. Просто химерно все.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.