Perché non esiste un operatore di alimentazione in Java / C ++?

Anche se esiste un tale operatore – ** in Python, mi chiedevo perché Java e C ++ non hanno anche uno.

È facile crearne uno per le classi definite in C ++ con loverloading di operatori (e credo che una cosa del genere sia possibile anche in Java), ma quando si parla di tipi primitivi come int, double e così via, dovrai usare la funzione di libreria come Math.power (e di solito devi eseguire il cast di entrambi per raddoppiare).

Quindi, perché non definire un tale operatore per i tipi primitivi?

Commenti

  • In C ++, non possiamo creare i nostri operatori. Puoi solo sovraccaricare gli operatori esistenti.
  • @Mahesh, così posso creare la mia classe Number e sovraccaricare loperatore ^ per essere un potere. Non è proprio così.
  • @RanZilber: è importante perché la precedenza delloperatore ^ non corrisponde alla precedenza dellelevamento a potenza. Considera lespressione a + b ^ c. In matematica, lesponenziazione viene eseguita per prima (b ^ c), quindi la potenza risultante viene aggiunta a a. In C ++, laggiunta viene eseguita prima (a + b), quindi loperatore ^ viene eseguito con c. Quindi, anche se hai implementato loperatore ^ per indicare lesponenziazione, la precedenza sorprenderà tutti.
  • @RamZilber – ^ è un XOR in C ++. Si consiglia che loperatore sovraccarico non dovrebbe fare nulla di diverso da ciò che fa un tipo di dati primitivo usandolo.
  • @RanZilber: Perché ‘ non è affatto intuitivo da usare uno qualsiasi di quegli operatori che hai menzionato per indicare esponenziazione. Metterei seriamente in dubbio la competenza di qualsiasi programmatore C ++ che sovraccarica loperatore ++ o loperatore ! et. al. per significare esponente. Ma puoi ‘ in ogni caso, perché gli operatori di cui parli accettano un solo argomento; lesponenziazione richiede due argomenti.

Risposta

In generale, gli operatori primitivi in C (e per estensione C ++) sono progettati per essere implementabili da un semplice hardware in circa una singola istruzione. Qualcosa come lelevazione a potenza spesso richiede il supporto del software; quindi non è presente per impostazione predefinita.

Inoltre, è fornito dalla libreria standard del linguaggio sotto forma di std::pow.

Infine, fare questo per i tipi di dati interi non avrebbe molto senso, perché la maggior parte dei valori anche piccoli per lesponenziazione fanno saltare lintervallo richiesto per int, che è fino a 65.535. Certo, potresti farlo per i doppi e i float ma non int, ma perché rendere il linguaggio incoerente per una funzionalità usata raramente?

Commenti

  • Sebbene sia daccordo con la maggior parte di ciò, il fatto che il modulo operatore non può essere utilizzato su tipi a virgola mobile è incoerente per i tipi di dati primitivi, ma anche quella probabilmente non sarebbe una singola istruzione su alcun hardware che immagino sia prevalente ora.
  • @Sion: Almeno su x86, il modulo è una singola istruzione. (DIV esegue sia la divisione che il modulo) ‘ mi hai fatto capire il punto di coerenza.
  • @Billy ONeal: modu in virgola mobile lus in una singola istruzione? Ultimamente non ho ‘ gironzolato in assemblea per saperlo da solo. Se questo ‘ è il caso, allora loperatore modulo dovrebbe essere applicabile ai tipi a virgola mobile.
  • @DonalFellows: FORTRAN aveva loperatore di esponenziazione molto prima che avesse qualsiasi cosa che assomigli al supporto bignum.
  • @DonalFellows: un operatore di potenza non è ‘ t tanto utile con gli interi quanto con i float, ma per potenze piccole (specialmente quadratura) potrebbe sicuramente ha i suoi usi. Personalmente mi piace lapproccio di creare operatori con lettere (come fa Pascal con div o FORTRAN con .EQ.); a seconda delle regole degli spazi bianchi della lingua, potrebbe essere possibile avere un numero arbitrario di operatori senza richiedere che siano parole riservate.

Risposta

Questa domanda è rispondibile per C ++: Stroustrup,” Design and Evolution of C ++ “discute questo nella sezione 11.6.1, pp. 247-250.

Cerano obiezioni generali allaggiunta di un nuovo operatore. Si aggiungerebbe alla tabella delle precedenze già troppo complicata. I membri del gruppo di lavoro pensavano che avrebbe dato solo una piccola comodità rispetto ad una funzione e volevano essere in grado di sostituire le proprie funzioni a volte.

Non cera un buon candidato per un operatore.^ è esclusivo-or e ^^ ha generato confusione a causa della relazione tra & e | e && e ||. ! non era adatto poiché ci sarebbe stata la naturale tendenza a scrivere != per esponenziare un valore esistente e questo era già stato preso. Il migliore disponibile potrebbe essere stato *^, che a quanto pare non è piaciuto a nessuno.

Stroustrup ha considerato di nuovo **, ma ha già un significato in C: a**p è a volte ciò a cui punta p e char ** c; dichiara c come un puntatore al puntatore a char. Introducendo ** come token che significa “dichiarazione di un puntatore a puntatore a”, “volte ciò a cui punta la cosa successiva” (se “è un puntatore) o” esponenziale “(se seguito da un numero) ha causato problemi di precedenza. a/b**p dovrebbe analizzare come a/(b**p) se p fosse un numero, ma (a/b) * *p se p fosse un puntatore, quindi questo dovrebbe essere risolto nel parser.

In altre parole, sarebbe stato possibile, ma avrebbe complicato la tabella delle precedenze e parser, ed entrambi sono già troppo complicati.

Non conosco la storia di Java; tutto quello che potevo fare sarebbe speculare. Per quanto riguarda C, dove è iniziato, tutti gli operatori C sono facilmente traducibili in codice assembly, in parte per semplificare il compilatore e in parte per evitare di nascondere funzionalità dispendiose in termini di tempo in operatori semplici (il fatto che operator+() e altri potrebbero nascondere una grande complessità e le prestazioni sono state una delle prime lamentele su C ++).

Commenti

  • Bella risposta. Immagino che Java abbia cercato di essere semplificato in C sotto questo aspetto, quindi nessuno voleva aggiungere un nuovo operatore. Questo ‘ è un peccato che nessuno me labbia chiesto, sicuramente mi sarebbe piaciuto *^. : D
  • C è stato creato per la formattazione del testo. Fortran è stato creato per fare matematica e aveva matematica complessa, potente e con matrici 20 anni prima.
  • @Martin Beckett: Riesci a trovare prove che il C sia stato creato per la formattazione del testo? Mi sembra un linguaggio molto goffo per questo, e quello che ‘ ho letto sullorigine di C dice che è stato progettato principalmente per la programmazione di sistema per Unix.
  • @DavidThornley – È stato progettato per scrivere Unix in, ma tutti i primi usi di Unix sembrano essere stati la formattazione del testo, e per questo ‘ è tempo che ha una stringa estesa e i / o libreria.
  • +1: il significato esistente per a**p è lassassino. (Gli hack per aggirare il problema … Brr!)

Answer

sospetto è perché ogni operatore che introduci aumenta la complessità della lingua. La barriera per lingresso è quindi molto alta. Mi trovo ad usare lelevazione a potenza molto, molto raramente – e sono più che felice di usare una chiamata di metodo per fare così.

Commenti

  • Ogni funzione inizia con -100 punti.
  • I ‘ d uso x**2 e x**3 non così di rado . E unimplementazione del potere magico che il compilatore conosce e ottimizza per i casi semplici sarebbe carina.
  • @CodeInChaos: Tuttavia x * x e x * x * x aren ‘ t brutti sostituti per quadrato e cubo.
  • @David puoi ‘ t scrivi semplicemente x*x se x è unespressione. Nel migliore dei casi il codice diventa ingombrante e nel peggiore dei casi più lento o addirittura sbagliato. Quindi ‘ devi definire le tue funzioni Square e Cube. E anche in questo caso il codice sarebbe più brutto rispetto allutilizzo di ** come operatore di alimentazione.
  • @David Devo mettere le parentesi sì, ma non ‘ non è necessario ripetere lespressione più volte e gonfia il codice sorgente. Il che riduce molto la leggibilità. E leliminazione della sottoespressione comune è possibile solo se il compilatore può garantire che lespressione sia priva di effetti collaterali. E almeno .net jitter non è ‘ troppo intelligente in questo senso.

Risposta

I progettisti del linguaggio Java e della libreria principale hanno deciso di relegare la maggior parte delle operazioni matematiche alla classe Math . Vedere Math.pow () .

Perché? Flessibilità per dare priorità alle prestazioni rispetto alla precisione bit per bit.Sarebbe contrario al resto delle specifiche del linguaggio affermare che il comportamento degli operatori matematici incorporati potrebbe variare da piattaforma a piattaforma, mentre la classe Math afferma specificamente che il comportamento potenzialmente sacrifica la precisione per le prestazioni, quindi attenzione dellacquirente:

A differenza di alcuni metodi numerici della classe StrictMath , tutte le implementazioni delle funzioni equivalenti della classe La matematica non è definita per restituire gli stessi risultati bit per bit. Questo rilassamento consente implementazioni a prestazioni migliori dove non è richiesta una rigorosa riproducibilità.

Answer

Lesponenziazione è stata parte di Fortran sin dallinizio perché mirava direttamente alla programmazione scientifica. Ingegneri e fisici lo usano spesso nelle simulazioni, perché le relazioni di legge di potenza sono comuni in fisica.

Python ha una forte presenza anche nellinformatica scientifica (ad esempio NumPy e SciPy). Questo, insieme al suo operatore di esponenziazione, suggerisce che fosse rivolto anche alla programmazione scientifica.

C, Java e C # hanno radici nella programmazione di sistema. Forse è uninfluenza che ha tenuto lelevazione a potenza fuori dal gruppo di operatori supportati.

Solo una teoria.

Risposta

Operatori definiti in C solo per operazioni aritmetiche comuni accessibili con lALU. Il suo scopo principale era creare uninterfaccia leggibile dalluomo per il codice Assembly.

C ++ non ha modificato alcun comportamento delloperatore perché voleva che tutto la base di codice scritta in C per essere conforme.

Java ha fatto lo stesso perché non voleva intimidire i programmatori C ++ esistenti.

Commenti

  • Quando è stato creato C, la moltiplicazione e la divisione non mancavano di rado nellhardware e dovevano essere implementate nel software. Eppure il C ha operatori di moltiplicazione e divisione.
  • @siride: Per quanto ne so, il PDP-7, il primo computer a eseguire Unix, aveva moltiplicazione e divisione hardware tramite il suo EAE. Consulta: bitsavers.org/pdf/dec/pdp7/F-75_PDP-7userHbk_Jun65.pdf

Rispondi

Bene, perché ogni operatore che avrebbe senso per una potenza è già in uso. ^ è XOR e ** definisce un puntatore a un puntatore. Quindi invece hanno solo una funzione che fa la stessa cosa. (come pow ())

Commenti

  • @RTS – Uno sviluppatore di lingue sta davvero cercando il senso più che lefficienza?
  • Un buon sviluppatore di un linguaggio di programmazione guarda ad entrambi. Non posso ‘ dire nulla su java. Ma in c ++ la funzione pow () viene calcolata in fase di compilazione. Ed è efficiente quanto gli operatori normali.
  • @RTS: la funzione pow() esegue i suoi calcoli in fase di esecuzione, a meno che tu non abbia un compilatore in grado di ripiegare costantemente per pow(), di cui dubito fortemente. (Alcuni compilatori ti danno la possibilità di utilizzare gli intrinseci del processore per eseguire il calcolo, tuttavia.)
  • @In silico non ‘ significava che calcola il valore finale value, volevo dire che i compilatori ottimizzeranno la chiamata alla funzione, quindi hai solo lequazione grezza.
  • @josefx: certo ‘ è una buona ragione. Un singolo * è un token lessicale, indipendentemente dal fatto che ‘ venga utilizzato per la moltiplicazione indiretta o indiretta. Un ** che significa esponenziazione sarebbe uno o due token lessicali e tu non ‘ vuoi che il tuo lexer debba premere il simbolo tabella da tokenizzare.

Risposta

Il fatto è che gli operatori aritmetici sono solo scorciatoie di funzioni. (Quasi) Tutto ciò che fai con loro può essere fatto con una funzione. Esempio:

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

È solo più prolisso, quindi non vedo niente di sbagliato nellusare le funzioni per eseguire “power of”.

Risposta

Addizione / sottrazione / negazione e moltiplicazione / divisione sono operatori matematici di base. Se dovessi trasformare la potenza in un operatore, dove ti fermeresti? Radice quadrata operatore? N-root operator? Operatore logaritmo?

Non posso parlare per i loro creatori, ma posso dire che penso che sarebbe diventato ingombrante e non ortogonale avere tali operatori nella lingua. il numero di caratteri non alfanumerici / spazi vuoti rimanenti sulla tastiera è piuttosto limitato. Così comè, è strano che ci sia un operatore modulo in C ++.

Commenti

  • +1 – Non ‘ per vedere perché avere mod come operatore è strano. ‘ di solito è una singola istruzione. ‘ è unoperazione primaria su numeri interi. ‘ è utilizzato quasi ovunque nellinformatica.(Limplementazione di cose come i buffer limitati senza mod farebbe schifo)
  • @Billy ONeal: Strano a causa dellincoerenza tra la possibilità di utilizzarli con tipi interi e tipi in virgola mobile . Assolutamente utile però e ‘ non mi sognerei di rimuoverlo. Semplicemente eccentrico è tutto.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *