Mens der er sådan en operatør – **
i Python, spekulerede jeg på, hvorfor Java og C ++ ikke har en også.
Det er let at lave en til klasser, du definerer i C ++ med operatøroverbelastning (og jeg mener, at en sådan ting er mulig også i Java), men når man taler om primitive typer som int, dobbelt og så videre, du bliver nødt til at bruge biblioteksfunktion som Math.power
(og skal normalt kaste begge dele til dobbelt).
Så – hvorfor ikke definere en sådan operatør for primitive typer?
Kommentarer
Svar
Generelt set er de primitive operatorer i C (og i forlængelse af C ++) er designet til at kunne implementeres af simpel hardware i omtrent en enkelt instruktion. Noget som eksponentiering kræver ofte softwaresupport; så det er ikke der som standard.
Det leveres også af sprogets standardbibliotek i form af std::pow
.
Endelig ville det ikke give meget mening at gøre dette for heltal datatyper, fordi de fleste selv små værdier til eksponentiering blæser det område, der kræves for int, det er op til 65.535. Sikker på, du kunne gøre dette for dobbelt og flyder, men ikke ints, men hvorfor gøre sproget inkonsekvent for en sjældent anvendt funktion?
Kommentarer
- Mens jeg er enig i det meste af dette, det faktum, at modulet operatør kan ikke bruges på floating point-typer er inkonsekvent for primitive datatyper, men det ville sandsynligvis heller ikke være en enkelt instruktion på nogen hardware, som jeg forestiller mig, er nogen måde at udbrede nu.
- @Sion: I det mindste x86, modulus er en enkelt instruktion. (
DIV
gør både division og modul) Du ‘ har dog fået mig til konsistenspunktet. - @Billy ONeal: Flydende punkt modu lus i en enkelt instruktion? Jeg har ikke ‘ tøjet rundt i forsamlingen for sent at vide for mig selv. Hvis det er ‘, skal modulusoperatøren gøres gældende for flydende punkttyper.
- @DonalFellows: FORTRAN havde eksponentieringsoperatøren længe før den havde alt, der ligner bignum-understøttelse.
- @DonalFellows: En kraftoperatør er ikke ‘ t så nyttigt med heltal som med flyde, men for små kræfter (især kvadrering) kunne helt sikkert har sine anvendelser. Personligt kan jeg godt lide fremgangsmåden med at gøre operatorer ud af bogstaver (som Pascal gør med
div
eller FORTRAN med.EQ.
); afhængigt af sprogets hvide rumregler kan det være muligt at have vilkårligt antal operatører uden at kræve, at de er reserverede ord.
Svar
Dette spørgsmål kan besvares for C ++: Stroustrup,” Design og udvikling af C ++ “diskuterer dette i afsnit 11.6.1, s. 247-250.
Der var generelle indvendinger mod at tilføje en ny operatør. Det vil føje til den allerede overkomplicerede forrangstabel. Medlemmerne af arbejdsgruppen mente, at det kun ville give mindre bekvemmelighed end at have en funktion, og de ønskede at være i stand til at erstatte deres egne funktioner undertiden.
Der var ingen god kandidat til en operatør.^
er eksklusiv eller, og ^^
inviterede forvirring på grund af forholdet mellem &
og |
og &&
og ||
. !
var uegnet, da der ville være den naturlige tendens til at skrive !=
til eksponentiering af en eksisterende værdi, og det var allerede taget. Den bedst tilgængelige kan have været *^
, som tilsyneladende ingen virkelig kunne lide.
Stroustrup betragtede **
igen, men det har allerede en betydning i C: a**p
er a
gange uanset hvad p
peger på, og char ** c;
erklærer c
som en markør til markør til char
. Introduktion til **
som et token, der betyder “erklæring af en pointer til pegepind til”, “gange hvad den næste ting peger på” (hvis det er “en pegepind) eller” eksponentiering “(hvis fulgt med et tal) forårsagede forrangsproblemer. a/b**p
skulle parse som a/(b**p)
hvis p var et tal, men (a/b) * *p
hvis p var en markør, så dette skulle løses i parseren.
Med andre ord ville det have været muligt, men det ville have kompliceret forrangstabellen og parser, og begge er allerede for komplicerede.
Jeg kender ikke historien om Java; alt hvad jeg kunne gøre, ville være at spekulere. Med hensyn til C, hvor det startede, oversættes alle C-operatorer let til samlingskode, dels for at forenkle compileren og dels for at undgå at skjule tidskrævende funktionalitet i enkle operatorer (det faktum, at operator+()
og andre kunne skjule stor kompleksitet, og performance hits var en af de tidlige klager over C ++).
Kommentarer
- Dejligt svar. Jeg gætter på, at Java forsøgte at blive forenklet C i denne henseende, så ingen ville tilføje en ny operatør. At ‘ er en skam, at ingen spurgte mig, jeg ville helt sikkert have ønsket
*^
. : D - C blev bygget til tekstformatering. Fortran blev bygget til matematik og havde kompleks, kraft- og matrixmatematik 20 år tidligere.
- @ Martin Beckett: Kan du finde beviser for, at C blev bygget til tekstformatering? Det forekommer mig et meget klodset sprog for det, og hvad jeg ‘ har læst om oprindelsen af C siger, at det primært var designet til systemprogrammering til Unix.
- @ DavidThornley – Det var designet til at skrive Unix ind, men alle de tidlige Unix-anvendelser synes at have været tekstformatering, og for det ‘ s tid har den en omfattende streng og i / o bibliotek.
- +1: Den eksisterende betydning for
a**p
er morderen. (Hackerne til at omgå dette problem … Brr!)
Svar
Jeg mistænker det skyldes, at hver operatør, du introducerer, øger sprogets kompleksitet. Barrieren for adgang er derfor meget høj. Jeg finder ud af, at jeg bruger eksponentiering meget, meget sjældent – og jeg er mere end glad for at bruge en metodeopfordring til at gøre så.
Kommentarer
- Hver funktion starter med -100 point.
- Jeg ‘ d brug
x**2
ogx**3
ikke så sjældent . Og en magisk pow-implementering, som compileren kender til og optimerer til de enkle tilfælde, ville være rart. - @CodeInChaos: Dog
x * x
ogx * x * x
aren ‘ t dårlige erstatninger for kvadratet og terningen. - @David kan du ‘ t skriv bare
x*x
hvis x er et udtryk. I bedste fald bliver koden uhåndterlig og i værste fald langsommere eller endda forkert. Så du ‘ behøver at definere dine egne Square- og Cube-funktioner. Og selv da ville koden være grimmere end at bruge ** som strømoperatør. - @ David Jeg skal sætte parenteser ja, men ikke ‘ behøver ikke at gentage udtrykket flere gange og spreder kildekoden. Hvilket reducerer læsbarheden meget. Og almindelig subekspression eliminering er kun mulig, hvis compileren kan garantere, at udtrykket er fri for bivirkninger. Og i det mindste .net jitter er ikke ‘ t for smart i den henseende.
Svar
Java-sprog- og kernebiblioteksdesignerne besluttede at henvise de fleste matematiske operationer til klassen Math . Se Math.pow () .
Hvorfor? Fleksibilitet til at prioritere ydeevne frem for bit-for-bit præcision.Det ville stride mod resten af sprogspecifikationen at sige, at adfærden hos indbyggede matematikoperatører kunne variere fra platform til platform, mens matematikklassen specifikt siger, at adfærden potentielt ofrer præcision for ydeevne, så køber pas på:
I modsætning til nogle af de numeriske metoder i klasse StrictMath , alle implementeringer af de tilsvarende funktioner i klasse Matematik er ikke defineret til at returnere de samme resultater for bit-for-bit. Denne afslapning tillader bedre implementeringer, hvor streng reproducerbarhed ikke er påkrævet.
Svar
Eksponentiering var en del af Fortran fra starten, fordi det var rettet mod videnskabelig programmering. Ingeniører og fysikere bruger det ofte i simuleringer, fordi forhold mellem magt og lov er almindelige i fysik.
Python har også en stærk tilstedeværelse inden for videnskabelig computing (f.eks. NumPy og SciPy). Dette, sammen med eksponentieringsoperatøren, antyder, at det også var rettet mod videnskabelig programmering.
C, Java og C # har rødder i systemprogrammering. Måske er det en indflydelse, der holdt eksponentiering ude af gruppen af understøttede operatører.
Bare en teori.
Svar
C definerede kun operatorer til almindelige aritmetiske operationer, der er tilgængelige med ALU. Dets hovedmål var at skabe en menneskelig læsbar grænseflade til samlingskode.
C ++ ændrede ikke nogen operatørs adfærd, fordi den ønskede alt kodebasen skrevet i C for at være kompatibel.
Java gjorde det samme, fordi det ikke ønskede at skræmme eksisterende C ++ – programmører.
Kommentarer
- Da C blev oprettet, manglede mangedobling og deling ikke sjældent hardware og skulle implementeres i software. Alligevel har C multiplikations- og divisionsoperatører.
- @siride: Efter min viden havde PDP-7 den første computer, der kørte Unix, hardwaremultiplikation og division gennem sin EAE. Se venligst: bitsavers.org/pdf/dec/pdp7/F-75_PDP-7userHbk_Jun65.pdf
Svar
Nå, fordi enhver operatør, der giver mening for en strøm, allerede er i brug. ^ er XOR og ** definerer en markør til en markør. Så i stedet har de bare en funktion, der gør det samme. (som pow ())
Kommentarer
- @RTS – Er en sprogudvikler virkelig på udkig efter sans mere end effektivitet?
- En god udvikler af et programmeringssprog ser på begge dele. Jeg kan ‘ ikke sige noget om java. Men i c ++ beregnes pow () -funktionen ved kompileringstidspunktet. Og er lige så effektiv som de almindelige operatører.
- @RTS: Funktionen
pow()
udfører sin beregning ved kørsel, medmindre du har en kompilator, der kan udføre konstant foldning tilpow()
, hvilket jeg meget tvivler på. (Nogle kompilatorer giver dig dog mulighed for at bruge processorens iboende egenskaber til at udføre beregningen.) - @ I silico betød jeg ikke ‘ t at det beregner den endelige værdi, jeg mente, at kompilatorerne vil optimere funktionsopkaldet, så du har bare den rå ligning.
- @josefx: Sikker på, at det ‘ er en god grund. Et enkelt
*
er et leksikalt token, uanset om det ‘ bruges til omdirigering eller multiplikation. En**
, der betyder eksponentiering, ville enten være et eller to leksikale tokens, og du behøver virkelig ikke ‘ t, at din lexer skal ramme symbolet tabel til tokenisering.
Svar
Fakta er, at aritmetiske operatorer kun er genveje til funktioner. (Næsten) Alt hvad du laver med dem kan gøres med en funktion. Eksempel:
c = a + b; // equals c.set(a.add(b)); // or as free functions set(c, add(a,b));
Det er bare mere detaljeret, så jeg ser intet galt med at bruge funktioner til at udføre “power of”.
Svar
Addition / subtraktion / negation og multiplikation / division er grundlæggende matematiske operatorer. Hvis du skulle gøre magten til en operator, hvor ville du stoppe? operatør? N-rodoperatør? Logaritmeoperatør?
Jeg kan ikke tale for deres skabere, men jeg kan sige, at jeg synes, det ville blive uhåndterligt og ikke ortogonalt at have sådanne operatorer på sproget. antallet af ikke-alfanumeriske / hvide mellemrumstegn, der er tilbage på tastaturet, er ret begrænset. Som det er, er det underligt, at der er en moduloperator i C ++.
Kommentarer
- +1 – Jeg kan ikke ‘ ikke se, hvorfor det er underligt at have
mod
som operatør. div id = “749f89ae7f”>
er normalt en enkelt instruktion. Det ‘ er en primativ operation på heltal. Det ‘ bruges mest overalt inden for datalogi.(Implementering af ting som afgrænsede buffere udenmod
ville stinke)
^
ikke stemmer overens med forrang for eksponentiering. Overvej udtrykketa + b ^ c
. I matematik udføres eksponentieringen først (b ^ c
), derefter føjes den resulterende effekt tila
. I C ++ udføres tilføjelsen først (a + b
) derefter udføres^
operatoren medc
. Så selvom du implementerede^
operatoren for at betyde eksponentiering, vil forrangene overraske alle.^
er en XOR i C ++. Det tilrådes, at overbelastet operatør ikke gør noget anderledes, hvad en primitiv datatype gør ved hjælp af den.++
operatøren eller!
operatøren et. al. at betyde eksponentation. Men du kan ‘ t alligevel, fordi de operatører, du taler om, kun accepterer et argument; eksponentiering kræver to argumenter.