De ce nu există un operator de alimentare în Java / C ++?

În timp ce există un astfel de operator – ** în Python, mă întrebam de ce Java și C ++ nu au una prea.

Este ușor să creați una pentru clasele pe care le definiți în C ++ cu supraîncărcare a operatorului (și cred că așa ceva este posibil și în Java), dar când vorbim despre tipuri primitive precum int, double și așa mai departe, va trebui să utilizați funcția de bibliotecă ca Math.power (și de obicei trebuie să le aruncați pe ambele pentru a dubla).

Deci – de ce să nu definiți un astfel de operator pentru tipurile primitive?

Comentarii

  • În C ++, nu ne putem crea proprii operatori. Puteți supraîncărca numai operatorii existenți.
  • @Mahesh, așa că îmi pot crea propria clasă de Numere și supraîncărcați operatorul ^ pentru a fi o putere. Acest lucru nu este adevărat.
  • @RanZilber: Contează, deoarece precedența operatorului ^ nu se potrivește cu precedenta exponențierii. Luați în considerare expresia a + b ^ c. În matematică, exponențierea se realizează mai întâi (b ^ c), apoi puterea rezultată este adăugată la a. În C ++, adăugarea se efectuează mai întâi (a + b) apoi operatorul ^ este efectuat cu c. Deci, chiar dacă ați implementat operatorul ^ pentru a însemna exponențierea, prioritatea va surprinde pe toată lumea.
  • @RamZilber – ^ este un XOR în C ++. Se recomandă ca operatorul supraîncărcat să nu facă diferit de ceea ce face un tip de date primitiv folosindu-l.
  • @RanZilber: Deoarece nu este deloc intuitiv de utilizat ‘ oricare dintre acei operatori pe care îi menționați înseamnă însemnare de exponențiere. Aș pune la îndoială competența oricărui programator C ++ care suprasolicită operatorul ++ sau operatorul ! et. al. a însemna exponentare. Dar nu poți ‘ oricum, deoarece operatorii despre care vorbești acceptă doar un singur argument; exponențierea necesită două argumente.

Răspuns

În general vorbind, operatorii primitivi din C (și prin extensie C ++) sunt concepute pentru a fi implementabile de hardware simplu în aproximativ o singură instrucțiune. Ceva ca exponențierea necesită adesea suport pentru software; deci nu este implicit acolo.

De asemenea, este furnizat de biblioteca standard a limbii sub forma std::pow.

În cele din urmă, a face acest lucru pentru tipurile de date întregi nu ar avea mult sens, deoarece majoritatea valorilor chiar mici pentru exponențiere aruncă intervalul necesar pentru int, adică până la 65.535. Sigur, ați putea face acest lucru pentru duble și plutitoare, dar nu ints, dar de ce să facă limbajul să fie incoerent pentru o caracteristică rar utilizată?

Comentarii

  • Deși sunt de acord cu cea mai mare parte a acestui fapt, faptul că modulul operatorul nu poate fi utilizat pe tipurile cu virgulă mobilă este neconcordant pentru tipurile de date primitive, dar prea probabil că nu ar fi o singură instrucțiune pentru niciun hardware pe care mi-l imaginez că este vreo prevalență acum.
  • @ Sion: Cel puțin pe x86, modulul este o singură instrucțiune. (DIV face atât diviziune, cât și modul). Totuși, ‘ m-ați ajutat la punctul de consistență.
  • @Billy ONeal: modul în virgulă mobilă lus într-o singură instrucțiune? ‘ nu m-am ascuns în asamblare până târziu să știu pentru mine. Dacă ‘ este cazul, atunci operatorul de modul ar trebui să fie aplicabil tipurilor de virgulă mobilă.
  • @DonalFellows: FORTRAN a avut operatorul de exponențiere cu mult înainte ca acesta să aibă orice seamănă cu suportul bignum.
  • @DonalFellows: un operator de putere nu este ‘ la fel de util cu numerele întregi ca și cu plutitoarele, dar pentru puteri mici (în special pătratul) ar putea cu siguranță au utilizările sale. Personal îmi place abordarea de a crea operatori din litere (așa cum face Pascal cu div sau FORTRAN cu .EQ.); în funcție de regulile de spațiu al limbii, poate fi posibil să existe un număr arbitrar de operatori fără a necesita ca acestea să fie cuvinte rezervate.

Răspuns

Această întrebare răspunde pentru C ++: Stroustrup,” Design and Evolution of C ++ „discută acest lucru în secțiunea 11.6.1, pp. 247-250.

Au existat obiecții generale la adăugarea unui operator nou. S-ar adăuga la tabelul de precedențe deja prea complicat. Membrii grupului de lucru au crezut că va oferi doar o comoditate minoră față de a avea o funcție și au dorit să poată înlocui uneori propriile funcții.

Nu exista un candidat bun pentru un operator.^ este exclusiv sau, și ^^ a provocat confuzie din cauza relației dintre & și | și && și ||. ! nu a fost adecvat, deoarece ar exista tendința naturală de a scrie != pentru exponențierea unei valori existente, iar aceasta a fost deja luată. Cel mai bun disponibil poate să fi fost *^, ceea ce aparent nimănui nu i-a plăcut cu adevărat.

Stroustrup a considerat din nou **, dar are deja o semnificație în C: a**p este a ori de câte ori p indică și char ** c; declară c ca un pointer către pointer către char. Introducerea ** ca simbol indicând „declarația unui pointer către pointer către”, „ori la care indică următorul lucru” (dacă este „pointer) sau” exponențiere „(dacă este urmat) de un număr) a cauzat probleme de prioritate. a/b**p ar trebui să fie analizat ca a/(b**p) dacă p ar fi un număr, dar (a/b) * *p dacă p ar fi un indicator, deci acest lucru ar trebui rezolvat în analiză.

Cu alte cuvinte, ar fi fost posibil, dar ar fi complicat tabelul de priorități și parser și ambele sunt deja prea complicate.

Nu știu povestea despre Java; tot ce aș putea face ar fi să speculez. În ceea ce privește C, de unde a început, toți operatorii C sunt traduși cu ușurință în cod de asamblare, parțial pentru a simplifica compilatorul și parțial pentru a evita ascunderea funcționalității consumatoare de timp în operatorii simpli (faptul că operator+() și alții ar putea ascunde o mare complexitate, iar rezultatele au fost una dintre reclamațiile timpurii despre C ++).

Comentarii

  • Răspuns frumos. Cred că Java a încercat să fie simplificat C în acest sens, așa că nimeni nu a vrut să adauge un nou operator. Că ‘ este păcat că nu m-a întrebat nimeni, cu siguranță mi-aș fi dorit *^. : D
  • C a fost construit pentru a efectua formatarea textului. Fortran a fost construit pentru a face matematică și avea matematică complexă, de putere și matrice cu 20 de ani mai devreme.
  • @ Martin Beckett: Puteți găsi dovezi că C a fost construit pentru formatarea textului? Mi se pare un limbaj foarte neîndemânatic pentru asta și ceea ce am citit despre originea lui C spune că a fost conceput pentru programarea de sistem pentru Unix în primul rând.
  • i ‘ > @DavidThornley – A fost conceput pentru a scrie în Unix, dar toate primele utilizări ale Unix par să fi fost formatarea textului, iar pentru ‘ timpul său are un șir extins și i / o bibliotecă.

  • +1: semnificația existentă pentru a**p este ucigașul. (Hacks pentru a rezolva această problemă … Brr!)

Răspuns

Am suspect pentru că fiecare operator pe care îl introduceți mărește complexitatea limbii. Bariera de intrare este, prin urmare, foarte mare. Mă trezesc folosind exponențierea foarte, foarte rar – și sunt mai mult decât fericit să folosesc o metodă de apel pentru a face deci.

Comentarii

  • Fiecare caracteristică începe cu -100 puncte.
  • Eu ‘ foloseam x**2 și x**3 nu atât de rar . Și o implementare magic pow pe care compilatorul o cunoaște și o optimizează pentru cazurile simple ar fi frumoasă.
  • @CodeInChaos: Cu toate acestea, x * x și x * x * x nu ‘ sunt înlocuitori răi pentru pătrat și cub.
  • @David puteți ‘ t pur și simplu scrieți x*x dacă x este o expresie. În cel mai bun caz, codul devine dificil și, în cel mai rău, mai lent sau chiar greșit. Deci, ‘ ar trebui să vă definiți propriile funcții Square și Cube. Și chiar și atunci codul ar fi mai urât decât utilizarea ** ca operator de alimentare.
  • @David Trebuie să pun paranteze da, dar nu ‘ nu trebuie să repet expresia de mai multe ori și umflă codul sursă. Ceea ce reduce lizibilitatea mult. Și eliminarea comună a subexpresiei este posibilă numai dacă compilatorul poate garanta că expresia nu are efecte secundare. Și cel puțin .net jitter nu este ‘ prea prea inteligent în această privință.

Răspuns

Limba Java și proiectanții de biblioteci de bază au decis să retrogradeze majoritatea operațiilor matematice în clasa Math . Consultați Math.pow () .

De ce? Flexibilitate pentru a acorda prioritate performanței față de precizia bit pentru bit.Ar fi contrar celorlalte specificații de limbaj să spunem că comportamentul operatorilor matematici încorporați ar putea varia de la o platformă la alta, în timp ce clasa Math afirmă în mod specific că comportamentul sacrifică potențial precizia pentru performanță, astfel încât cumpărătorul să fie atent:

Spre deosebire de unele dintre metodele numerice ale clasei StrictMath , toate implementările funcțiilor echivalente ale clasei Matematica nu este definită pentru a returna aceleași rezultate bit pentru bit. Această relaxare permite implementări mai performante în care nu este necesară o reproductibilitate strictă.

Răspuns

Exponențierea a făcut parte din Fortran de la început, deoarece a vizat în mod clar programarea științifică. Inginerii și fizicienii îl folosesc adesea în simulări, deoarece relațiile legii puterii sunt comune în fizică.

Python are o prezență puternică și în calculul științific (de exemplu, NumPy și SciPy). Acest lucru, împreună cu operatorul său de exponențiere, sugerează că a vizat și programarea științifică.

C, Java și C # au rădăcini în programarea sistemului. Poate că aceasta este o influență care a ținut exponențierea în afara grupului de operatori suportați.

Doar o teorie.

Răspuns

C a definit operatorii numai pentru operații aritmetice comune accesibile cu ALU. Scopul său principal a fost crearea unei interfețe lizibile de către om pentru codul de asamblare.

C ++ nu a schimbat niciun comportament al operatorului, deoarece dorea toate baza de cod scrisă în C să fie compatibilă.

Java a făcut același lucru pentru că nu dorea să intimideze programatorii C ++ existenți.

Comentarii

  • Când a fost creat C, înmulțirea și împărțirea nu erau rareori lipsite de hardware și trebuiau implementate în software. Cu toate acestea, C are operatori de multiplicare și divizare.
  • @siride: Din câte știu eu, PDP-7 primul computer care a rulat Unix, a avut multiplicare și divizare hardware prin EAE. Vă rugăm să consultați: bitsavers.org/pdf/dec/pdp7/F-75_PDP-7userHbk_Jun65.pdf

Răspuns

Ei bine, deoarece fiecare operator care ar avea sens pentru o putere este deja în uz. ^ este XOR și ** definește un pointer la un pointer. Deci, în schimb, au doar o funcție care face același lucru. (cum ar fi pow ())

Comentarii

  • @RTS – Un dezvoltator de limbi străine caută mai mult sens decât eficiență?
  • Un bun dezvoltator al unui limbaj de programare se uită la ambele. Nu pot ‘ să spun nimic despre Java. Dar în c ++ funcția pow () este calculată la momentul compilării. Și este la fel de eficient ca operatorii obișnuiți.
  • @RTS: Funcția pow() își efectuează calculul în timpul rulării, cu excepția cazului în care aveți un compilator care poate face plierea constantă pentru pow(), de care mă îndoiesc foarte mult. (Unele compilatoare vă oferă totuși opțiunea de a utiliza intrinsecele procesorului pentru a efectua calculul.)
  • @In silico ‘ nu înseamnă că calculează finalul valoare, am vrut să spun că compilatoarele vor optimiza apelul funcțional, așa că aveți doar ecuația brută.
  • @josefx: Sigur că ‘ este un motiv bun. Un singur * este un simbol lexical, indiferent dacă este ‘ folosit pentru indirectare sau multiplicare. O ** care înseamnă exponențierea ar fi una sau două jetoane lexicale și nu vrei cu adevărat ‘ să nu vrei ca lexerul tău să lovească simbolul table tokenize.

Răspuns

De fapt, operatorii aritmetici sunt doar comenzi rapide ale funcțiilor. (Aproape) Tot ceea ce faci cu ei poate fi realizat cu o funcție. Exemplu:

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

Este doar mai detaliat, așa că nu văd nimic în neregulă cu utilizarea funcțiilor pentru a efectua „puterea lui”.

Răspuns

Adunarea / scăderea / negarea și înmulțirea / divizarea sunt operatori matematici de bază. Dacă ar fi să faci din putere un operator, unde te-ai opri? Rădăcină pătrată operator? Operator N-root? Operator Logaritm?

Nu pot vorbi pentru creatorii lor, dar pot spune că cred că ar deveni dificil și nu ortogonal să ai astfel de operatori în limbă. numărul de caractere non-alfanumerice / spațiu alb rămas pe tastatură este destul de limitat. Într-adevăr, este „ciudat că există” un operator de modul în C ++.

Comentarii

  • +1 – Nu ‘ nu văd de ce este ciudat să ai mod ca operator. div id = „749f89ae7f”>

este de obicei o singură instrucțiune. Este ‘ o operație primitivă pe numere întregi. Este ‘ s utilizate cel mai mult peste tot în informatică.(Implementarea unor lucruri precum tampoane delimitate fărămodar fi puturoasă)

  • @Billy ONeal: ciudat din cauza inconsecvenței dintre a putea fi utilizat cu tipuri întregi și tipuri cu virgulă mobilă . Totuși, este absolut util și nu aș visa ‘ să visez să îl elimin. Doar ciudat este totul.
  • Lasă un răspuns

    Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *