Warum gibt es in Java / C ++ keinen Netzbetreiber?

23

Während es einen solchen Operator gibt - **in Python habe ich mich gefragt, warum Java und C ++ auch keinen haben.

Es ist einfach, eine für Klassen zu erstellen, die Sie in C ++ mit Operatorüberladung definieren (und ich glaube, dass dies auch in Java möglich ist), aber wenn Sie über primitive Typen wie int, double usw. sprechen, müssen Sie library verwenden funktionieren wie Math.power(und müssen in der Regel beide auf double werfen).

Also - warum nicht einen solchen Operator für primitive Typen definieren?

RanZilber
quelle
8
In C ++ können wir keine eigenen Operatoren erstellen. Sie können nur die vorhandenen Operatoren überladen.
1
@ Mahesh, damit ich meine eigene Zahlenklasse und meinen eigenen Überladungsoperator erstellen kann, um eine Potenz zu sein. Das stimmt wirklich nicht.
22
@ RanZilber: Es ist wichtig, da die Priorität des ^Operators nicht mit der Priorität der Exponentiation übereinstimmt. Betrachten Sie den Ausdruck a + b ^ c. In der Mathematik wird zuerst die Exponentiation durchgeführt ( b ^ c), dann wird die resultierende Potenz addiert a. In C ++ wird die Addition zuerst ausgeführt ( a + b) und dann der ^Operator mit ausgeführt c. Selbst wenn Sie den ^Operator als Exponentiation implementiert haben , wird der Vorrang alle überraschen.
In silico
2
@RamZilber - ^ist ein XOR in C ++. Es wird empfohlen, dass überladene Operatoren nicht anders vorgehen sollten, als ein primitiver Datentyp es verwendet.
4
@ RanZilber: Weil es überhaupt nicht intuitiv ist, einen der Operatoren zu verwenden, die Sie als Potenzierung bezeichnen. Ich würde ernsthaft die Kompetenz eines C ++ - Programmierers in Frage stellen, der den ++Operator oder den !Operator et überlastet . al. Exponentation bedeuten. Dies ist jedoch nicht möglich, da die Operatoren, über die Sie sprechen, nur ein Argument akzeptieren. Potenzierung erfordert zwei Argumente.
In silico

Antworten:

32

Im Allgemeinen sind die primitiven Operatoren in C (und durch die Erweiterung C ++) so konzipiert, dass sie durch einfache Hardware in ungefähr einer einzigen Anweisung implementiert werden können. So etwas wie Exponentiation erfordert häufig Software-Unterstützung. Es ist also nicht standardmäßig vorhanden.

Es wird auch von der Standardbibliothek der Sprache in Form von bereitgestellt std::pow.

Schließlich wäre dies für ganzzahlige Datentypen nicht sehr sinnvoll, da die meisten selbst kleinen Werte für die Potenzierung den für int erforderlichen Bereich, dh bis zu 65.535, ausblasen. Sicher, Sie könnten dies für Doubles und Floats tun, aber nicht für Ints, aber warum sollte die Sprache für ein selten verwendetes Feature inkonsistent sein?

Billy ONeal
quelle
4
Obwohl ich dem Großteil zustimme, ist die Tatsache, dass der Moduloperator nicht für Gleitkommatypen verwendet werden kann, für primitive Datentypen inkonsistent, aber auch dies wäre wahrscheinlich kein einziger Befehl für eine Hardware, von der ich denke, dass sie derzeit in irgendeiner Weise vorherrscht.
@Sion: Zumindest bei x86 ist Modul eine einzelne Anweisung. ( DIVtut sowohl Division als auch Modul) Sie haben mich jedoch auf den Konsistenzpunkt gebracht.
Billy ONeal
@ Billy ONeal: Gleitkommamodul in einer einzigen Anweisung? Ich habe in letzter Zeit nicht mehr in der Montage rumgespielt, um es selbst zu wissen. In diesem Fall sollte der Modul-Operator auf Gleitkommatypen angewendet werden.
3
@DonalFellows: FORTRAN hatte den Exponentiationsoperator lange bevor er etwas hatte, das der Bignumunterstützung ähnelte.
Supercat
1
@DonalFellows: Ein Energieoperator ist nicht so nützlich für Ganzzahlen wie für Floats, aber für kleine Potenzen (insbesondere Quadratur) könnte er durchaus Verwendung finden. Persönlich mag ich den Ansatz, Operatoren aus Buchstaben zu machen (wie Pascal es mit divoder FORTRAN mit tut .EQ.); Abhängig von den Sprach-Whitespace-Regeln kann es möglich sein, eine beliebige Anzahl von Operatoren zu haben, ohne dass diese reservierte Wörter sein müssen.
Supercat
41

Diese Frage ist für C ++ zu beantworten: Stroustrup, "Design and Evolution of C ++", erörtert dies in Abschnitt 11.6.1, S. 247-250.

Es gab allgemeine Einwände gegen das Hinzufügen eines neuen Operators. Es würde die bereits überkomplizierte Rangfolgetabelle ergänzen. Die Mitglieder der Arbeitsgruppe dachten, es würde nur eine geringe Bequemlichkeit bedeuten, eine Funktion zu haben, und sie wollten manchmal ihre eigenen Funktionen ersetzen können.

Es gab keinen guten Kandidaten für einen Betreiber. ^ist Exklusiv-Oder und ^^lud wegen der Beziehung zwischen &und |und &&und zu Verwirrung ein ||. !war ungeeignet, da es die natürliche Tendenz geben würde, !=für die Potenzierung eines vorhandenen Wertes zu schreiben , und das wurde bereits genommen. Das beste *^, was verfügbar war , hat anscheinend niemand wirklich gemocht.

Stroustrup betrachten **wieder, aber es hat schon eine Bedeutung in C: a**pist amal was auch immer pPunkte zu, und char ** c;erklärt cals Zeiger auf Zeiger auf char. Das Einführen **als Token, das "Deklaration eines Zeigers auf Zeiger auf" bedeutet, "mal was das nächste Ding auf" (wenn es ein Zeiger ist) oder "Potenzierung" (wenn gefolgt von einer Zahl) zeigt, verursachte Vorrangprobleme. a/b**pwürde analysieren müssen, als a/(b**p)ob p eine Zahl wäre, aber (a/b) * *pwenn p ein Zeiger wäre, müsste dies im Parser aufgelöst werden.

Mit anderen Worten, es wäre möglich gewesen, aber es hätte die Prioritätstabelle und den Parser kompliziert, und beide sind bereits zu kompliziert.

Ich kenne die Geschichte über Java nicht. Ich könnte nur spekulieren. Was C betrifft, so können alle C-Operatoren leicht in Assembler-Code übersetzt werden, um den Compiler zu vereinfachen und um zu vermeiden, dass zeitaufwändige Funktionen in einfachen Operatoren verborgen bleiben (die Tatsache, dass operator+()und andere die Komplexität und Leistung beeinträchtigen könnten, war eine der frühen Beschwerden über C ++).

David Thornley
quelle
2
Gute Antwort. Ich denke, Java hat versucht, C in dieser Hinsicht zu vereinfachen, daher wollte niemand einen neuen Operator hinzufügen. Das ist schade, dass mich niemand gefragt hat, hätte ich mir sicher gewünscht *^. : D
maaartinus
1
C wurde für die Textformatierung entwickelt. Fortran wurde für Mathematik gebaut und hatte vor 20 Jahren komplexe Potenz- und Matrixmathematik.
Martin Beckett
@ Martin Beckett: Können Sie Beweise dafür finden, dass C für die Textformatierung entwickelt wurde? Es scheint mir eine sehr ungeschickte Sprache zu sein, und was ich über den Ursprung von C gelesen habe, besagt, dass es hauptsächlich für die Systemprogrammierung für Unix entwickelt wurde.
David Thornley
@DavidThornley - Es wurde entwickelt, um Unix einzuschreiben, aber alle frühen Unix-Anwendungen schienen Textformatierungen gewesen zu sein, und es ist Zeit für eine umfangreiche String- und I / O-Bibliothek.
Martin Beckett
6
+1: Die existierende Bedeutung für a**pist der Killer. (Die Hacks, um dieses Problem zu umgehen ... Brr!)
Donal Fellows
13

Ich vermute , dass jeder Operator, den Sie einführen, die Komplexität der Sprache erhöht. Die Eintrittsbarriere ist daher sehr hoch. Ich setze Exponentiation sehr, sehr selten ein - und ich bin mehr als glücklich, dafür einen Methodenaufruf zu verwenden.

Jon Skeet
quelle
3
Ich würde x**2und x**3nicht so selten verwenden. Und eine magische POW-Implementierung, die der Compiler kennt und für die einfachen Fälle optimiert, wäre schön.
CodesInChaos
2
@CodeInChaos: Aber x * xund x * x * xsind keine schlechten Substitute für das Quadrat und den Würfel.
David Thornley
5
@ David Sie können nicht einfach schreiben, x*xwenn x ein Ausdruck ist. Im besten Fall wird der Code unhandlich und im schlimmsten Fall langsamer oder sogar falsch. Sie müssen also Ihre eigenen Quadrat- und Würfelfunktionen definieren. Und selbst dann wäre der Code hässlicher als die Verwendung von ** als Netzbetreiber.
CodesInChaos
1
@ David Ich muss ja Klammern setzen, aber ich muss den Ausdruck nicht mehrmals wiederholen und den Quellcode aufblähen. Das verringert die Lesbarkeit erheblich. Die Eliminierung häufiger Unterausdrücke ist nur möglich, wenn der Compiler garantiert, dass der Ausdruck frei von Nebenwirkungen ist. Und zumindest .net Jitter ist in dieser Hinsicht nicht allzu klug.
CodesInChaos
11

Die Entwickler der Java-Sprache und der Kernbibliothek haben beschlossen, die meisten mathematischen Operationen in die Klasse Math zu verlagern. Siehe Math.pow () .

Warum? Flexibilität, um Leistung vor Bit-für-Bit-Präzision zu priorisieren. Es widerspricht dem Rest der Sprachspezifikation zu sagen, dass das Verhalten der eingebauten mathematischen Operatoren von Plattform zu Plattform variieren kann, während die Math-Klasse ausdrücklich angibt, dass das Verhalten möglicherweise die Präzision für die Leistung einschränkt.

Im Gegensatz zu einigen numerischen Methoden der Klasse StrictMath sind nicht alle Implementierungen der entsprechenden Funktionen der Klasse Math so definiert, dass bitweise dieselben Ergebnisse zurückgegeben werden. Diese Entspannung ermöglicht Implementierungen mit besserer Leistung, bei denen keine strikte Reproduzierbarkeit erforderlich ist.


quelle
6

Exponentiation war von Anfang an Teil von Fortran, weil es sich ausschließlich um wissenschaftliche Programmierung handelte. Ingenieure und Physiker setzen es häufig in Simulationen ein, da Potenzgesetzbeziehungen in der Physik weit verbreitet sind.

Python ist auch im wissenschaftlichen Rechnen stark vertreten (z. B. NumPy und SciPy). Dies legt zusammen mit dem Potenzierungsoperator nahe, dass es sich auch um eine wissenschaftliche Programmierung handelte.

C, Java und C # haben Wurzeln in der Systemprogrammierung. Vielleicht ist das ein Einfluss, der die Potenzierung aus der Gruppe der unterstützten Operatoren herausgehalten hat.

Nur eine Theorie.

Duffymo
quelle
4

C definiert nur Operatoren für allgemeine arithmetische Operationen, die mit der ALU zugänglich sind. Das Hauptziel war die Schaffung einer für Menschen lesbaren Schnittstelle zum Assembly-Code.

C ++ änderte kein Operatorverhalten, da die gesamte in C geschriebene Codebasis kompatibel sein sollte.

Java tat dasselbe, weil es vorhandene C ++ - Programmierer nicht einschüchtern wollte.

Tugrul Ates
quelle
Bei der Erstellung von C fehlten Multiplikation und Division nicht selten an Hardware und mussten in Software implementiert werden. Dennoch hat C Multiplikations- und Divisionsoperatoren.
Siride
@siride: Meines Wissens war der PDP-7 der erste Computer, auf dem Unix ausgeführt wurde. Er verfügte über Hardware-Multiplikation und -Division über seine EAE. Bitte sehen Sie: bitsavers.org/pdf/dec/pdp7/F-75_PDP-7userHbk_Jun65.pdf
Tugrul Ates
1

Nun, weil jeder Betreiber, der für eine Leistung Sinn macht, bereits im Einsatz ist. ^ ist XOR und ** definiert einen Zeiger auf einen Zeiger. Stattdessen haben sie nur eine Funktion, die dasselbe tut. (wie pow ())

Skyler Saleh
quelle
@RTS - Sucht ein Sprachentwickler wirklich mehr nach Sinn als nach Effizienz?
Ein guter Entwickler einer Programmiersprache befasst sich mit beiden. Ich kann nichts über Java sagen. In c ++ wird die Funktion pow () jedoch zur Kompilierungszeit berechnet. Und ist genauso effizient wie die regulären Betreiber.
@RTS: Die pow()Funktion führt ihre Berechnung zur Laufzeit durch, es sei denn, Sie haben einen Compiler, der konstant falten kann pow(), was ich sehr bezweifle. (Einige Compiler bieten Ihnen jedoch die Möglichkeit, die Berechnung mithilfe von Prozessor-Intrinsics durchzuführen.)
In silico
@ In silico habe ich nicht gemeint, dass es den Endwert berechnet, ich habe gemeint, dass die Compiler den Funktionsaufruf wegoptimieren, so dass Sie nur die Rohgleichung haben.
2
@ Josefx: Sicher, es ist ein guter Grund. Ein einzelnes *ist ein lexikalisches Token, egal ob es zur Indirektion oder Multiplikation verwendet wird. Eine **bedeutungsvolle Potenzierung wäre entweder ein oder zwei lexikalische Token, und Sie möchten wirklich nicht, dass Ihr Lexer die Symboltabelle berührt, um die Token zu setzen.
David Thornley
0

Fakt ist, arithmetische Operatoren sind nur Abkürzungen von Funktionen. (Fast) Alles, was Sie damit machen, können Sie mit einer Funktion machen. Beispiel:

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

Es ist nur ausführlicher, daher sehe ich nichts Falsches daran, Funktionen zum Ausführen von 'power of' zu verwenden.

Xeo
quelle
-1

Addition / Subtraktion / Negation und Multiplikation / Division sind grundlegende mathematische Operatoren. Wenn Sie aus Strom einen Betreiber machen würden, wo würden Sie dann aufhören? Quadratwurzeloperator? N-Root-Operator? Logarithmusoperator?

Ich kann nicht für ihre Schöpfer sprechen, aber ich kann sagen, dass es unhandlich und nicht mehr orthogonal wäre, solche Operatoren in der Sprache zu haben. Die Anzahl der nicht alphanumerischen Zeichen / Leerzeichen, die auf der Tastatur verbleiben, ist eher begrenzt. Es ist seltsam, dass es in C ++ einen Modul-Operator gibt.

Sion Sheevok
quelle
+1 - Ich verstehe nicht, warum es modseltsam ist , als Operator zu arbeiten. Es ist normalerweise eine einzelne Anweisung. Es ist eine Grundoperation für ganze Zahlen. Es wird fast überall in der Informatik verwendet. (Dinge wie begrenzte Puffer zu implementieren, ohne modzu stinken)
Billy ONeal
@ Billy ONeal: Seltsam wegen der Inkonsistenz zwischen der Verwendung mit Integer-Typen und Gleitkomma-Typen. Absolut nützlich und ich würde nicht davon träumen, es zu entfernen. Nur schrullig ist alles.