Även om det finns en sådan operatör – **
i Python undrade jag varför Java och C ++ inte har en också.
Det är enkelt att skapa en för klasser som du definierar i C ++ med operatörsöverbelastning (och jag tror att sådant är möjligt även i Java), men när man talar om primitiva typer som int, dubbel och så vidare måste du använda biblioteksfunktionen som Math.power
(och vanligtvis måste du casta båda till dubbla).
Så – varför inte definiera en sådan operatör för primitiva typer?
Kommentarer
Svar
Generellt sett är de primitiva operatorerna i C (och i tillägg C ++) är utformade för att implementeras av enkel hårdvara i ungefär en enda instruktion. Något som exponentiering kräver ofta mjukvarusupport; så det är inte där som standard.
Det tillhandahålls också av språkets standardbibliotek i form av std::pow
.
Slutligen skulle det inte vara mycket meningsfullt att göra detta för heltal datatyper, för de flesta till och med små värden för exponentiering blåser ut det intervall som krävs för int, det vill säga upp till 65 535. Visst, du kan göra detta för dubbel och flytande men inte ints, men varför göra språket inkonsekvent för en sällan använd funktion?
Kommentarer
- Även om jag håller med om det mesta, faktumet att modulen operatören kan inte användas på flytande punkttyper är inkonsekvent för primitiva datatyper, men det skulle förmodligen inte vara en enda instruktion på någon hårdvara som jag föreställer mig är något utbrett nu.
- @Sion: Åtminstone på x86, modul är en enda instruktion. (
DIV
gör både delning och modul) Du ’ har dock fått mig på konsistenspunkten. - @Billy ONeal: Floating point modu lus i en enda instruktion? Jag har inte ’ tuttat runt i församlingen för sent för att veta själv. Om så är ’, bör moduloperatorn göras tillämplig på flytande punkttyper.
- @DonalFellows: FORTRAN hade exponentieringsoperatören långt innan den hade allt som liknar bignum-stöd.
- @DonalFellows: En kraftoperatör är inte ’ t lika användbar med heltal som med flottör, men för små krafter (särskilt kvadrering) kan det definitivt har sina användningsområden. Personligen gillar jag tillvägagångssättet att göra operatörer av bokstäver (som Pascal gör med
div
eller FORTRAN med.EQ.
); beroende på språkets blankstegsregler kan det vara möjligt att ha godtyckligt antal operatörer utan att kräva att de är reserverade ord.
Svar
Denna fråga är svarbar för C ++: Stroustrup,” Design och utveckling av C ++ ”diskuterar detta i avsnitt 11.6.1, s. 247-250.
Det fanns allmänna invändningar mot att lägga till en ny operatör. Det skulle lägga till den redan överkomplicerade prioritetstabellen. Medlemmarna i arbetsgruppen trodde att det skulle ge endast mindre bekvämlighet än att ha en funktion, och de ville ibland kunna ersätta sina egna funktioner.
Det fanns ingen bra kandidat för en operatör.^
är exklusivt eller, och ^^
bjöd in förvirring på grund av förhållandet mellan &
|
och &&
och ||
. !
var olämpligt eftersom det skulle finnas den naturliga tendensen att skriva !=
för exponentiering av ett befintligt värde, och det har redan tagits. Det bästa tillgängliga kan ha varit *^
, som ingen uppenbarligen gillade.
Stroustrup ansåg **
igen, men det har redan en mening i C: a**p
är a
gånger vad p
pekar på, och char ** c;
förklarar c
som en pekare till pekare till char
. Vi introducerar **
som en symbol som betyder ”deklaration av en pekare till pekare till”, ”gånger vad nästa sak pekar på” (om det är ”en pekare) eller” exponentiering ”(om följt med ett nummer) orsakade företräde problem. a/b**p
skulle behöva analysera som a/(b**p)
om p var ett nummer, men (a/b) * *p
om p var en pekare, så detta måste lösas i parsern.
Med andra ord skulle det ha varit möjligt, men det skulle ha försvårat prioritetstabellen och parser, och båda är redan för komplicerade.
Jag vet inte historien om Java; allt jag kunde göra skulle vara att spekulera. När det gäller C, där det började, översätts alla C-operatorer enkelt till monteringskod, dels för att förenkla kompilatorn och dels för att undvika att dölja tidskrävande funktionalitet i enkla operatörer (det faktum att operator+()
och andra kunde dölja stor komplexitet och prestationshits var ett av de tidiga klagomålen om C ++).
Kommentarer
- Snyggt svar. Jag antar att Java försökte förenklas C i detta avseende, så ingen ville lägga till en ny operatör. Att ’ är synd att ingen frågade mig, jag skulle säkert ha velat
*^
. : D - C byggdes för att göra textformatering. Fortran byggdes för att göra matte och hade komplex matematik, kraft och matris 20 år tidigare.
- @ Martin Beckett: Kan du hitta bevis för att C byggdes för textformatering? Det verkar för mig som ett väldigt klumpigt språk för det, och vad jag ’ har läst om ursprunget till C säger att det var designat för systemprogrammering för Unix främst.
- @DavidThornley – Det var designat för att skriva Unix in, men alla de tidiga användningarna av Unix verkar ha varit textformatering och för den ’ s gång har den en omfattande sträng och jag / o bibliotek.
- +1: Den befintliga betydelsen för
a**p
är mördaren. (Hackarna att lösa det problemet … Brr!)
Svar
Jag misstänker det beror på att varje operatör du introducerar ökar språkkomplexiteten. Inträdesbarriären är därför mycket hög. Jag använder mig av exponentiering väldigt, mycket sällan – och jag är mer än glad att använda en metod för att göra så.
Kommentarer
- Varje funktion börjar med -100 poäng.
- Jag ’ d använder
x**2
ochx**3
inte så sällan . Och en magisk pow-implementering som kompilatorn vet om och optimerar för de enkla fallen skulle vara trevligt. - @CodeInChaos: Men
x * x
ochx * x * x
aren ’ t dåliga ersättare för kvadrat och kub. - @ David kan du ’ t skriv helt enkelt
x*x
om x är ett uttryck. I bästa fall blir koden otymplig och i värsta fall långsammare eller till och med fel. Så du ’ d måste definiera dina egna Square- och Cube-funktioner. Och även då skulle koden vara fulare än att använda ** som kraftoperatör. - @ David Jag måste sätta parenteser ja, men behöver inte ’ inte behöver upprepa uttrycket flera gånger och sväller källkoden. Vilket minskar läsbarheten mycket. Och vanlig eliminering av subuttryck är endast möjlig om kompilatorn kan garantera att uttrycket är fritt från biverkningar. Och åtminstone .net jitter är inte ’ t för smart i det avseendet.
Svar
Java-språket och kärnbiblioteksdesignerna beslutade att förflytta de flesta matematiska operationer till klassen Math . Se Math.pow () .
Varför? Flexibilitet för att prioritera prestanda framför bit-för-bit-precision.Det skulle strida mot resten av språkspecifikationen att säga att beteendet hos inbyggda matematikoperatörer kan variera från plattform till plattform, medan matematikklassen specifikt säger att beteendet potentiellt offrar precision för prestanda, så köparen se upp:
Till skillnad från några av de numeriska metoderna i klass StrictMath , alla implementeringar av motsvarande funktioner i klass Matematik definieras inte för att returnera bit-för-bit-samma resultat. Denna avslappning möjliggör implementeringar med bättre prestanda där sträng reproducerbarhet inte krävs.
Svar
Exponentiering var en del av Fortran från början eftersom det riktades helt mot vetenskaplig programmering. Ingenjörer och fysiker använder det ofta i simuleringar, eftersom maktlagsförhållanden är vanliga inom fysik.
Python har också en stark närvaro inom vetenskaplig databehandling (t.ex. NumPy och SciPy). Detta, tillsammans med dess exponentieringsoperatör, antyder att det också var inriktat på vetenskaplig programmering.
C, Java och C # har rötter i systemprogrammering. Kanske är det ett inflytande som höll exponentiering utanför gruppen av operatörer som stöds.
Bara en teori.
Svar
C definierade operatörer endast för vanliga aritmetiska operationer som är tillgängliga med ALU. Dess huvudsyfte var att skapa ett mänskligt läsbart gränssnitt till församlingskod.
C ++ ändrade inte något operatörsbeteende eftersom det ville ha kodbasen skriven i C för att överensstämma.
Java gjorde detsamma eftersom den inte ville skrämma befintliga C ++ – programmerare.
Kommentarer
- När C skapades saknades inte multiplicering och delning sällan hårdvara utan måste implementeras i programvara. Ändå har C multiplikations- och divisionsoperatörer.
- @siride: Såvitt jag vet var PDP-7 den första datorn som körde Unix, hårdvarumultiplicering och delning genom sin EAE. Se: bitsavers.org/pdf/dec/pdp7/F-75_PDP-7userHbk_Jun65.pdf
Svar
Nåväl eftersom alla operatörer som skulle vara vettiga för en kraft redan används. ^ är XOR och ** definierar en pekare till en pekare. Så istället har de bara en funktion som gör samma sak. (som pow ())
Kommentarer
- @RTS – Letar en språkutvecklare verkligen efter känsla mer än effektivitet?
- En bra utvecklare av ett programmeringsspråk tittar på båda. Jag kan ’ inte säga något om java. Men i c ++ beräknas pow () -funktionen vid sammanställningstid. Och är lika effektiv som de vanliga operatörerna.
- @RTS:
pow()
-funktionen utför sin beräkning vid körning, såvida du inte har en kompilator som kan göra konstant vikning förpow()
, vilket jag tvivlar mycket på. (Vissa kompilatorer ger dig dock möjlighet att använda processorns inneboende för att utföra beräkningen.) - @ I silico menade jag inte ’ att den beräknar den slutliga värde, jag menade att kompilatorerna kommer att optimera bort funktionssamtalet, så du har bara råekvationen.
- @josefx: Visst att det ’ är en god anledning. En enda
*
är en lexikal token, oavsett om den ’ används för inriktning eller multiplikation. En**
som betyder exponentiering skulle vara antingen en eller två lexikala tokens, och du vill verkligen inte att ’ vill att din lexer måste träffa symbolen tabell för att tokenize.
Svar
Faktum är att aritmetiska operatorer bara är genvägar till funktioner. (Nästan) Allt du gör med dem kan göras med en funktion. Exempel:
c = a + b; // equals c.set(a.add(b)); // or as free functions set(c, add(a,b));
Det är bara mer detaljerat, så jag ser inget fel med att använda funktioner för att utföra ”power of”.
Svar
Addition / subtraktion / negation och multiplikation / division är grundläggande matematiska operatorer. Om du skulle göra makten till en operatör, var skulle du stoppa? operatör? N-root-operatör? Logaritmoperatör?
Jag kan inte tala för deras skapare, men jag kan säga att jag tycker att det skulle bli svårt och inte ortogonalt att ha sådana operatörer på språket. antalet icke alfanumeriska / vita blanksteg som finns kvar på tangentbordet är ganska begränsat. Som det är är det konstigt att det finns en moduloperator i C ++.
Kommentarer
- +1 – Jag ser inte ’ t varför det är konstigt att ha
mod
som operatör. div id = ”749f89ae7f”>
är vanligtvis en enda instruktion. Det ’ är en primativ operation på heltal. Det ’ används mest överallt inom datavetenskap.(Implementering av saker som begränsade buffertar utanmod
skulle stinka)
^
inte överensstämmer med exponentieringens företräde. Tänk på uttrycketa + b ^ c
. I matematik utförs exponentieringen först (b ^ c
), sedan läggs den resulterande effekten tilla
. I C ++ utförs tillägget först (a + b
) sedan utförs^
operatören medc
. Så även om du implementerade operatorn^
för att betyda exponentiering, kommer företräde att överraska alla.^
är en XOR i C ++. Det rekommenderas att överbelastad operatör inte ska göra annorlunda vad en primitiv datatyp gör med den.++
operatören eller!
operatören et. al. menar exponentation. Men du kan ’ t ändå, eftersom operatörerna du pratar om accepterar bara ett argument; exponentiering kräver två argument.