Mens det er en slik operatør – **
i Python, lurte jeg på hvorfor Java og C ++ ikke har en også.
Det er lett å lage en for klasser du definerer i C ++ med overbelastning av operatøren (og jeg tror en slik ting er mulig også i Java), men når du snakker om primitive typer som int, double og så videre, du må bruke biblioteksfunksjon som Math.power
(og vanligvis må du kaste begge deler til dobbelt).
Så – hvorfor ikke definere en slik operatør for primitive typer?
Kommentarer
Svar
Generelt sett er de primitive operatorene i C (og i forlengelse C ++) er designet for å kunne implementeres av enkel maskinvare i omtrent en enkelt instruksjon. Noe som eksponentiering krever ofte programvarestøtte; så det er ikke der som standard.
Det leveres også av standardbiblioteket på språket i form av std::pow
.
Til slutt ville det ikke være fornuftig å gjøre dette for heltal datatyper, fordi de fleste til og med små verdiene for eksponentiering blåser ut området som kreves for int, det vil si opptil 65 535. Visst, du kan gjøre dette for dobler og flyter, men ikke ints, men hvorfor gjøre språket inkonsekvent for en sjelden brukt funksjon?
Kommentarer
- Mens jeg er enig i det meste av dette, det faktum at modulen operatør kan ikke brukes på flytende punkttyper er inkonsekvent for primitive datatyper, men det vil sannsynligvis ikke være en eneste instruksjon på noen maskinvare som jeg forestiller meg er noen måte utbredt nå.
- @Sion: I det minste på x86, modul er en enkelt instruksjon. (
DIV
gjør både deling og modul) Du ‘ har skjønt meg på konsistenspunktet. - @Billy ONeal: Flytpunkt modu lus i en enkelt instruksjon? Jeg har ikke ‘ t rundt i forsamlingen for sent å vite for meg selv. Hvis det er ‘, bør modulusoperatøren gjøres gjeldende for flytende punkttyper.
- @DonalFellows: FORTRAN hadde eksponentieringsoperatøren lenge før den hadde alt som ligner bignum-støtte.
- @DonalFellows: En kraftoperatør er ikke ‘ t like nyttig med heltall som med flottører, men for små krefter (spesielt kvadrering) kan det være definitivt har sine bruksområder. Personlig liker jeg tilnærmingen med å lage operatører ut av bokstaver (som Pascal gjør med
div
eller FORTRAN med.EQ.
); avhengig av språkets hvite romregler, kan det være mulig å ha vilkårlig antall operatører uten å kreve at de er reservert ord.
Svar
Dette spørsmålet kan besvares for C ++: Stroustrup,» Design and Evolution of C ++ «diskuterer dette i avsnitt 11.6.1, s. 247-250.
Det var generelle innvendinger mot å legge til et ny operatør. Det vil legge til den allerede overkompliserte forrangstabellen. Medlemmene av arbeidsgruppen mente at det bare ville gi mindre bekvemmelighet enn å ha en funksjon, og de ønsket å kunne erstatte sine egne funksjoner noen ganger.
Det var ingen god kandidat for en operatør.^
er eksklusivt eller, og ^^
inviterte forvirring på grunn av forholdet mellom &
og |
og &&
og ||
. !
var uegnet siden det ville være den naturlige tendensen til å skrive !=
for eksponentiering av en eksisterende verdi, og det var allerede tatt. Den beste tilgjengelige kan ha vært *^
, som tilsynelatende ingen virkelig likte.
Stroustrup betraktet **
igjen, men det har allerede en betydning i C: a**p
er a
ganger hva p
peker på, og char ** c;
erklærer c
som en peker til pekeren til char
. Vi introduserer **
som et token som betyr «erklæring om en peker å peke til», «ganger hva neste ting peker på» (hvis det er «en peker) eller» eksponentiering «(hvis fulgt forårsaket problemer. a/b**p
måtte analysere som a/(b**p)
hvis p var et tall, men (a/b) * *p
hvis p var en peker, så dette måtte løses i parseren.
Med andre ord ville det vært mulig, men det ville ha komplisert forrangstabellen og parser, og begge er allerede for kompliserte.
Jeg vet ikke historien om Java; alt jeg kunne gjøre ville være å spekulere. Når det gjelder C, der det startet, oversettes alle C-operatorer enkelt til monteringskode, delvis for å forenkle kompilatoren og dels for å unngå å skjule tidkrevende funksjonalitet i enkle operatører (det faktum at operator+()
og andre kunne skjule stor kompleksitet, og ytelseshits var en av de tidlige klagene på C ++).
Kommentarer
- Fint svar. Jeg antar at Java prøvde å bli forenklet C i denne forbindelse, så ingen ønsket å legge til en ny operatør. At ‘ er synd at ingen spurte meg, hadde jeg sikkert likt
*^
. : D - C ble bygget for å gjøre tekstformatering. Fortran ble bygget for å gjøre matematikk og hadde komplekse, kraftige og matrise matematikk 20 år tidligere.
- @ Martin Beckett: Kan du finne bevis på at C ble bygget for tekstformatering? Det virker for meg som et veldig klønete språk for det, og det jeg ‘ har lest om opprinnelsen til C sier at det var designet for systemprogrammering for Unix primært.
- @ DavidThornley – Den ble designet for å skrive Unix i, men alle de tidlige Unix-bruksområdene ser ut til å ha vært tekstformatering, og for den har ‘ sin tid en omfattende streng og jeg / o bibliotek.
- +1: Den eksisterende betydningen for
a**p
er morderen. (Hacks for å omgå det problemet … Brr!)
Svar
Jeg mistenker det skyldes at hver operatør du introduserer øker språkets kompleksitet. Barrieren for oppføring er derfor veldig høy. Jeg bruker meg eksponentiering veldig, veldig sjelden – og jeg er mer enn glad for å bruke en metodekall til å gjøre altså.
Kommentarer
- Hver funksjon starter med -100 poeng.
- Jeg ‘ d bruker
x**2
ogx**3
ikke så sjelden . Og en magisk pow-implementering som kompilatoren vet om og optimaliserer for de enkle sakene, ville være fint. - @CodeInChaos: Imidlertid
x * x
ogx * x * x
aren ‘ t dårlige erstatninger for firkanten og kuben. - @David kan du ‘ t skriv bare
x*x
hvis x er et uttrykk. I beste fall blir koden uhåndterlig, og i verste fall tregere eller til og med feil. Så du ‘ d trenger å definere dine egne Square- og Cube-funksjoner. Og selv da ville koden være styggere enn å bruke ** som kraftoperatør. - @ David Jeg må sette parenteser ja, men ikke ‘ t trenger å gjenta uttrykket flere ganger og oppblåser kildekoden. Noe som reduserer lesbarheten mye. Og vanlig eliminering av subuttrykk er bare mulig hvis kompilatoren kan garantere at uttrykket er fritt for bivirkninger. Og i det minste .net jitter er ikke ‘ t for smart i så måte.
Svar
Java-språket og kjernebibliotekdesignerne bestemte seg for å overføre de fleste matematiske operasjoner til klassen Math . Se Math.pow () .
Hvorfor? Fleksibilitet for å prioritere ytelse fremfor bit-for-bit presisjon.Det ville være i motsetning til resten av språkspesifikasjonen å si at oppførselen til innebygde matteoperatører kan variere fra plattform til plattform, mens matematikk-klassen spesifikt sier at oppførselen potensielt ofrer presisjon for ytelse, så kjøper pass opp:
I motsetning til noen av de numeriske metodene i klasse StrictMath , alle implementeringer av de tilsvarende funksjonene i klassen Matematikk er ikke definert for å returnere bit-for-bit-resultatene. Denne avslapningen tillater implementeringer med bedre ytelse der streng reproduserbarhet ikke er nødvendig.
Svar
Eksponentiering var en del av Fortran fra begynnelsen fordi den var rettet mot vitenskapelig programmering. Ingeniører og fysikere bruker det ofte i simuleringer, fordi maktlovsforhold er vanlig i fysikk.
Python har også en sterk tilstedeværelse i vitenskapelig databehandling (f.eks. NumPy og SciPy). Det, sammen med eksponentieringsoperatøren, antyder at det også var rettet mot vitenskapelig programmering.
C, Java og C # har røtter i systemprogrammering. Kanskje det er en innflytelse som holdt eksponentiering utenfor gruppen av støttede operatører.
Bare en teori.
Svar
C definerte operatører bare for vanlige aritmetiske operasjoner som er tilgjengelige med ALU. Hovedmålet var å skape et menneskelig lesbart grensesnitt til forsamlingskoden.
C ++ endret ingen operatøratferd fordi den ville ha alt kodebasen skrevet i C for å være kompatibel.
Java gjorde det samme fordi den ikke ønsket å skremme eksisterende C ++ – programmerere.
Kommentarer
- Da C ble opprettet, manglet mangedobling og deling ikke sjelden maskinvare, og måtte implementeres i programvare. Likevel har C multiplikasjons- og divisjonsoperatører.
- @siride: Så vidt jeg vet, hadde PDP-7 den første datamaskinen som kjørte Unix, maskinvaremultiplikasjon og divisjon gjennom sin EAE. Se: bitsavers.org/pdf/dec/pdp7/F-75_PDP-7userHbk_Jun65.pdf
Svar
Vel, fordi alle operatører som gir mening for en kraft allerede er i bruk. ^ er XOR og ** definerer en peker til en peker. Så i stedet har de bare en funksjon som gjør det samme. (som pow ())
Kommentarer
- @RTS – Ser en språkutvikler virkelig etter sans mer enn effektivitet?
- En god utvikler av et programmeringsspråk ser på begge deler. Jeg kan ‘ ikke si noe om java. Men i c ++ beregnes pow () -funksjonen på kompileringstidspunktet. Og er like effektiv som de vanlige operatørene.
- @RTS:
pow()
-funksjonen utfører sin beregning ved kjøretid, med mindre du har en kompilator som kan gjøre konstant folding forpow()
, som jeg tviler sterkt på. (Noen kompilatorer gir deg imidlertid muligheten til å bruke prosessorens egenart for å utføre beregningen.) - @I silico mente jeg ikke ‘ t at den beregner den endelige verdi, jeg mente at kompilatorene vil optimalisere funksjonsanropet, så du har bare rå ligningen.
- @josefx: Visst det ‘ en god grunn. Et enkelt
*
er et leksikalt token, enten det ‘ brukes til omdirigering eller multiplikasjon. En**
som betyr eksponentiering, vil være enten ett eller to leksikale tokens, og du vil virkelig ikke ‘ t vil at leksisten din skal treffe symbolet tabell for å tokenisere.
Svar
Fakta er at aritmetiske operatorer bare er snarveier til funksjoner. (Nesten) Alt du gjør med dem kan gjøres med en funksjon. Eksempel:
c = a + b; // equals c.set(a.add(b)); // or as free functions set(c, add(a,b));
Det er bare mer detaljert, så jeg ser ingenting galt med å bruke funksjoner til å utføre «power of».
Svar
Addisjon / subtraksjon / negasjon og multiplikasjon / divisjon er grunnleggende matematiske operatorer. Hvis du skulle gjøre makten til en operatør, hvor ville du stoppe? operatør? N-rotoperatør? Logaritmeoperatør?
Jeg kan ikke snakke for skaperne sine, men jeg kan si at jeg synes det ville blitt uhåndterlig og ikke ortogonalt å ha slike operatører på språket. antall ikke-alfanumeriske / mellomromstegn som er igjen på tastaturet er ganske begrenset. Som det er, er det rart at det er en moduloperator i C ++.
Kommentarer
- +1 – Jeg ser ikke ‘ t hvorfor det er rart å ha
mod
som operatør. div id = «749f89ae7f»>
er vanligvis en enkelt instruksjon. Det ‘ er en primativ operasjon på heltall. Det ‘ brukes mest overalt innen informatikk.(Implementering av ting som begrensede buffere utenmod
ville stinke)
^
operatøren ikke samsvarer med forrang for eksponentiering. Tenk på uttrykketa + b ^ c
. I matematikk utføres eksponentieringen først (b ^ c
), deretter blir den resulterende kraften lagt tila
. I C ++ utføres tilsetningen først (a + b
) deretter utføres^
operatøren medc
. Så selv om du implementerte^
-operatøren for å bety eksponentiering, vil forrangene overraske alle.^
er en XOR i C ++. Det anbefales at overbelastet operatør ikke skal gjøre noe annet enn en primitiv datatype som bruker den.++
operatøren eller!
operatøren et. al. å bety eksponentasjon. Men du kan ‘ t uansett, fordi operatørene du snakker om godtar bare ett argument; eksponentiering krever to argumenter.