Почему в Java / C ++ нет оператора power?

23

Хотя **в Python есть такой оператор , мне было интересно, почему в Java и C ++ его тоже нет.

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

Итак, почему бы не определить такой оператор для примитивных типов?

RanZilber
источник
8
В C ++ мы не можем создавать свои собственные операторы. Вы можете только перегружать существующих операторов.
1
@Mahesh, так что я могу создать свой собственный класс Number и оператор перегрузки ^, чтобы быть степенью. Это действительно не важно.
22
@RanZilber: это важно, потому что приоритет ^оператора не совпадает с приоритетом возведения в степень. Рассмотрим выражение a + b ^ c. В математике сначала возводится возведение в степень ( b ^ c), затем результирующая степень прибавляется к a. В C ++ сначала выполняется сложение ( a + b), затем выполняется ^оператор c. Таким образом, даже если вы реализовали ^оператор для обозначения возведения в степень, приоритет превзойдет всех.
In silico
2
@RamZilber - ^это XOR в C ++. Рекомендуется, чтобы перегруженный оператор не отличался от того, что делает примитивный тип данных, используя его.
4
@RanZilber: Потому что совсем не интуитивно использовать любой из тех операторов, которые вы упомянули для обозначения возведения в степень. Я бы серьезно усомнился в компетенции любого программиста на С ++, который перегружает ++оператора или !оператора и т.д. и др. означать экспонату. Но в любом случае вы не можете, потому что операторы, о которых вы говорите, принимают только один аргумент; возведение в степень требует двух аргументов.
In silico

Ответы:

32

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

Также предоставляется стандартная библиотека языка в виде std::pow.

Наконец, выполнение этого для целочисленных типов данных не имело бы большого смысла, потому что большинство даже небольших значений для возведения в степень выдувают диапазон, требуемый для int, то есть до 65 535. Конечно, вы можете сделать это для двойных и плавающих чисел, но не для целых чисел, но зачем делать язык несовместимым для редко используемой функции?

Билли ОНил
источник
4
Хотя я согласен с большей частью этого, тот факт, что оператор модуля не может использоваться в типах с плавающей запятой, несовместим с примитивными типами данных, но это также, вероятно, не будет единственной инструкцией на любом оборудовании, которое, как мне кажется, сейчас распространено.
@Sion: по крайней мере на x86, модуль - это одна инструкция. ( DIVвыполняет как деление, так и модуль). Но у меня есть точка согласованности.
Билли ONEAL
@Billy ONeal: модуль с плавающей точкой в ​​одной инструкции? Я не слонялся вокруг на собрании в последнее время, чтобы знать для себя. Если это так, то оператор модуля должен быть применим к типам с плавающей запятой.
3
@DonalFellows: FORTRAN имел оператор возведения в степень задолго до того, как у него было что-то похожее на поддержку bignum.
суперкат
1
@DonalFellows: Оператор мощности не так полезен для целых чисел, как для чисел с плавающей запятой, но для малых степеней (особенно в квадрате) он определенно может найти свое применение. Лично мне нравится подход создания операторов из букв (как это делает Паскаль с divили с FORTRAN .EQ.); в зависимости от правил языкового пробела, может быть возможно иметь произвольное количество операторов, не требуя, чтобы они были зарезервированными словами.
суперкат
41

Этот вопрос отвечает за C ++: Страуструп, «Проектирование и развитие C ++» обсуждает этот вопрос в разделе 11.6.1, с. 247-250.

Были общие возражения против добавления нового оператора. Это добавило бы к уже слишком сложной таблице приоритетов. Члены рабочей группы думали, что это даст лишь незначительное удобство при наличии функции, и они хотели иногда иметь возможность заменять свои собственные функции.

Не было хорошего кандидата на оператора. ^Исключительно-или, и вызывает ^^путаницу из-за отношений между &и |и &&и ||. !был неподходящим, так как была бы естественная тенденция писать !=для возведения в степень существующей ценности, и это уже было принято. Лучшее из доступных, возможно, было *^, которое, видимо, никому не понравилось.

Страуструп считается **снова, но это уже имеет значение в C: a**pэто a-кратный pуказует, а и char ** c;объявляет cкак указатель на указатель char. Введение **в качестве маркера значения «объявление указателя на указатель на», «время, на которое указывает следующая вещь» (если это указатель) или «возведение в степень» (если за ним следует число), вызывало проблемы с приоритетом. a/b**pпришлось бы анализировать, как a/(b**p)если бы p было числом, но (a/b) * *pесли бы p был указателем, то это должно быть решено в парсере.

Другими словами, это было бы возможно, но это усложнило бы таблицу приоритетов и анализатор, и оба они уже слишком сложны.

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

Дэвид Торнли
источник
2
Хороший ответ. Я предполагаю, что Java пыталась упростить C в этом отношении, поэтому никто не хотел добавлять новый оператор. Жаль, что меня никто не спрашивал, мне бы наверняка понравилось *^. : D
maaartinus
1
C был создан для форматирования текста. Фортран был построен для математики и имел сложную, мощную и матричную математику 20 лет назад.
Мартин Беккет
@Martin Beckett: Можете ли вы найти доказательства того, что C был создан для форматирования текста? Мне это кажется очень неуклюжим языком, и то, что я читал о происхождении Си, говорит, что оно было разработано в первую очередь для системного программирования для Unix.
Дэвид Торнли
@DavidThornley - Он был разработан для написания Unix, но все ранние версии Unix, по-видимому, были форматированием текста, и в то время у него была обширная библиотека строк и ввода-вывода.
Мартин Беккет
6
+1: существующее значение для a**pубийца. (Хаки, чтобы обойти эту проблему… Брр!)
Донал Феллоуз
13

Я подозреваю, что это потому, что каждый оператор, который вы вводите, увеличивает сложность языка. Поэтому барьер для входа очень высок. Я использую возведение в степень очень, очень редко - и я более чем счастлив использовать вызов метода для этого.

Джон Скит
источник
3
Я бы использовал x**2и x**3не так уж редко. И было бы неплохо реализовать магическую реализацию Pow, о которой знает и оптимизирует компилятор для простых случаев.
CodesInChaos
2
@CodeInChaos: Тем не менее , x * xи x * x * xне плохие заменители квадрата и куба.
Дэвид Торнли
5
@ Давид, ты не можешь просто написать, x*xесли х - это выражение. В лучшем случае код становится громоздким, а в худшем медленнее или даже неправильным. Поэтому вам нужно определить свои собственные функции Square и Cube. И даже тогда код будет более уродливым, чем использование ** в качестве оператора мощности.
CodesInChaos
1
@ Давид Мне нужно поставить круглые скобки, да, но не нужно повторять выражение несколько раз и раздувает исходный код. Что значительно снижает читабельность. И устранение общего подвыражения возможно только в том случае, если компилятор может гарантировать, что выражение не имеет побочных эффектов. И, по крайней мере, .net jitter не слишком умен в этом отношении.
CodesInChaos
11

Разработчики языка Java и базовой библиотеки решили перенести большинство математических операций в класс Math . Смотрите Math.pow () .

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

В отличие от некоторых числовых методов класса StrictMath , все реализации эквивалентных функций класса Math не определены для получения побитовых одинаковых результатов. Это ослабление позволяет реализовать более эффективные реализации, где не требуется строгая воспроизводимость.


источник
6

Экспонирование было частью Фортрана с самого начала, потому что оно было нацелено прямо на научное программирование. Инженеры и физики часто используют его в симуляции, потому что отношения степенного закона распространены в физике.

Python также широко используется в научных вычислениях (например, NumPy и SciPy). Это, наряду с оператором возведения в степень, позволяет предположить, что оно было нацелено и на научное программирование.

C, Java и C # имеют корни в системном программировании. Возможно, это влияние не давало возведения в степень в группу поддерживаемых операторов.

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

duffymo
источник
4

В C определены только операторы для общих арифметических операций, доступных для ALU. Его основной целью было создание удобочитаемого интерфейса с кодом ассемблера.

C ++ не изменил никакого поведения оператора, потому что он хотел, чтобы вся кодовая база, написанная на C, была совместимой.

Java сделала то же самое, потому что не хотела запугивать существующих программистов на C ++.

Тугрул Атес
источник
Когда C был создан, умножение и деление нередко испытывали недостаток в оборудовании и должны были быть реализованы в программном обеспечении. Тем не менее C имеет операторы умножения и деления.
Сирид
@siride: Насколько мне известно, PDP-7, первый компьютер с Unix, имел аппаратное умножение и деление через EAE. Пожалуйста, смотрите: bitsavers.org/pdf/dec/pdp7/F-75_PDP-7userHbk_Jun65.pdf
Tugrul Ates
1

Хорошо, потому что каждый оператор, который имел бы смысл для власти, уже используется. ^ это XOR и ** определяет указатель на указатель. Так что вместо этого у них просто есть функция, которая делает то же самое. (например, Pow ())

Скайлер Салех
источник
@RTS - Действительно ли разработчик языка ищет смысл больше, чем эффективность?
Хороший разработчик языка программирования смотрит на оба. Я не могу ничего сказать о Java. Но в c ++ функция pow () вычисляется во время компиляции. И так же эффективен, как и обычные операторы.
@RTS: pow()функция выполняет свои вычисления во время выполнения, если у вас нет компилятора, который может выполнять постоянное сворачивание pow(), в чем я очень сомневаюсь. (Однако некоторые компиляторы дают вам возможность использовать встроенные функции процессора для выполнения вычислений.)
In silico
@ In silico Я не имел в виду, что он вычисляет окончательное значение, я имел в виду, что компиляторы оптимизируют вызов функции, так что у вас просто необработанное уравнение.
2
@josefx: Конечно, это хорошая причина. Сингл *- это лексический токен, используется ли он для косвенного или умножения. **Значение экспоненцирование будет либо один или два лексические маркеры, и вы действительно не хотите , чтобы ваш лексический , чтобы попасть в таблицу символов разметить.
Дэвид Торнли
0

На самом деле, арифметические операторы - это всего лишь ярлыки функций. (Почти) Все, что вы делаете с ними, может быть сделано с помощью функции. Пример:

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

Это просто более многословно, поэтому я не вижу ничего плохого в использовании функций для выполнения «силы».

Xeo
источник
-1

Сложение / вычитание / отрицание и умножение / деление являются основными математическими операторами. Если бы вы сделали власть оператором, где бы вы остановились? Оператор квадратного корня? N-корневой оператор? Логарифм оператора?

Я не могу говорить за их создателей, но я могу сказать, что я думаю, что стало бы громоздким и не ортогональным иметь такие операторы в языке. Количество не буквенно-цифровых символов / пробелов, оставшихся на клавиатуре, довольно ограничено. Странно, что в C ++ есть оператор модуля.

Сион Шеевок
источник
+1 - не понимаю, почему иметь modв качестве оператора странно. Обычно это одна инструкция. Это первичная операция над целыми числами. Это используется почти везде в компьютерной науке. (Реализация таких вещей, как ограниченные буферы без modзапаха)
Billy ONeal
@Billy ONeal: странно из-за несоответствия между возможностью использовать с целочисленными типами и типами с плавающей точкой. Абсолютно полезно, хотя и я бы не мечтал удалить его. Просто причудливо это все.