Proč v Javě / C ++ neexistuje žádný operátor napájení?

I když existuje takový operátor – ** v Pythonu, zajímalo by mě, proč Java a C ++ nemají taky jeden.

Je snadné vytvořit jeden pro třídy, které definujete v C ++ s přetížením operátorů (a věřím, že taková věc je možná i v Javě), ale když mluvíme o primitivních typech jako int, double a takže dál, budete muset použít funkci knihovny jako Math.power (a obvykle je třeba seslat obojí na dvojnásobek).

Takže – proč nedefinovat takového operátora pro primitivní typy?

Komentáře

  • V jazyce C ++ nemůžeme vytvářet vlastní operátory. Stávající operátory můžete pouze přetížit.
  • @Mahesh, takže můžu vytvořit svoji vlastní třídu čísel a operátor přetížení ^ jako moc. To opravdu není důležité.
  • @RanZilber: Je to důležité, protože přednost operátoru ^ neodpovídá přednostnosti umocňování. Zvažte výraz a + b ^ c. V matematice se nejprve provede umocnění (b ^ c), poté se výsledná mocnina přidá do a. V C ++ se nejprve provede přidání (a + b), poté se provede ^ operátor s c. Takže i kdybyste implementovali operátor ^ ve smyslu umocňování, přednost každého překvapí.
  • @RamZilber – ^ je XOR v C ++. Doporučuje se, aby přetížený operátor neměl dělat nic jiného, než to dělá primitivní datový typ.
  • @RanZilber: Protože použití ‚ není vůbec intuitivní kterýkoli z těch operátorů, které zmiňujete, znamená umocňování. Vážně bych zpochybnil kompetence jakéhokoli programátora v C ++, který přetíží operátor ++ nebo operátor ! atd. al. znamenat umocňování. Ale stejně ‚ t nemůžete, protože operátoři, o kterých mluvíte, přijímají pouze jeden argument; umocňování vyžaduje dva argumenty.

Odpověď

Obecně řečeno, primitivní operátory v jazyce C (a příponou C ++) jsou navrženy tak, aby je bylo možné implementovat jednoduchým hardwarem zhruba do jedné instrukce. Něco jako umocňování často vyžaduje softwarovou podporu; takže ve výchozím nastavení tam není.

Rovněž je poskytována standardní knihovnou jazyka ve formě std::pow.

Nakonec by to pro celočíselné datové typy nemělo smysl, protože většina i malých hodnot pro umocňování vyfoukne rozsah požadovaný pro int, což je až 65 535. Jistě, můžete to udělat pro zdvojnásobení a plovoucí hodnoty, ale ne ints, ale proč dělat jazyk nekonzistentní pro zřídka používanou funkci?

Komentáře

  • I když s většinou souhlasím, skutečnost, že modul operátor nelze použít na typy s plovoucí desetinnou čárkou je pro primitivní datové typy nekonzistentní, ale to by pravděpodobně nebylo jedinou instrukcí na jakémkoli hardwaru, o kterém si teď myslím, že teď převládá.
  • @Sion: Alespoň na x86, modulus je jediná instrukce. (DIV provádí jak dělení, tak modulus) Dostali jste mě ‚ do bodu konzistence.
  • @Billy ONeal: Moduly s plovoucí desetinnou čárkou lus v jediném pokynu? V divadle jsem se ‚ nezastavil, abych se dozvěděl sám za sebe. Je-li tomu tak ‚, měl by být operátor modulu použitelný pro typy s plovoucí desetinnou čárkou.
  • @DonalFellows: FORTRAN měl operátor umocňování dlouho předtím, než měl cokoli, co se podobá podpoře bignum.
  • @DonalFellows: Energetický operátor není ‚ tak užitečný s celými čísly jako s plováky, ale pro malé pravomoci (zejména kvadratury) by to mohl rozhodně mají své využití. Osobně mám rád přístup k vytváření operátorů z písmen (jak to dělá Pascal s div nebo FORTRAN s .EQ.); v závislosti na pravidlech mezer v jazycích je možné mít libovolný počet operátorů, aniž by bylo nutné, aby to byla vyhrazená slova.

Odpovědět

Tato otázka odpovídá pro C ++: Stroustrup,„ Design and Evolution of C ++ „discusses this in section 11.6.1, pp. 247-250.

Proti přidání nový operátor. Přidalo by to k již překomplikované tabulce priorit. Členové pracovní skupiny si mysleli, že by to mělo jen malou výhodu nad funkcí, a chtěli mít možnost někdy nahradit své vlastní funkce.

Nebyl vhodný kandidát na operátora.^ je exkluzivní nebo ^^ vyzval ke zmatku kvůli vztahu mezi & a | a && a ||. ! byl nevhodný, protože by existovala přirozená tendence psát != pro umocňování existující hodnoty, a to již bylo přijato. Nejlepší dostupné mohly být *^, což zjevně nikdo opravdu neměl rád.

Stroustrup znovu zvážil **, ale již má význam v C: a**p je a krát, na co p odkazuje, a char ** c; deklaruje c jako ukazatel na ukazatel na char. Představujeme ** jako token, což znamená „deklarace ukazatele na ukazatel“, „časy, na které ukazuje následující věc“ (pokud je to „sa ukazatel) nebo“ umocňování „(pokud následuje) o číslo) způsobil problémy s prioritou. a/b**p by musel analyzovat jako a/(b**p) pokud by p bylo číslo, ale (a/b) * *p kdyby p byl ukazatel, tak by to muselo být vyřešeno v analyzátoru.

Jinými slovy, bylo by to možné, ale zkomplikovalo by to tabulku priorit a analyzátor a oba jsou již příliš komplikované.

Neznám příběh o Javě; vše, co jsem mohl udělat, bylo spekulovat. Pokud jde o C, kde to začalo, jsou všechny operátory C snadno přeloženy do kódu sestavy, částečně pro zjednodušení kompilátoru a částečně pro zabránění skrytí časově náročné funkce v jednoduchých operátorech (skutečnost, že operator+() a další mohli skrýt velkou složitost a výkonnostní hity byly jednou z prvních stížností na C ++).

Komentáře

  • Pěkná odpověď. Myslím, že Java se v tomto ohledu pokusila zjednodušit na C, takže nikdo nechtěl přidat nového operátora. Škoda ‚ škoda, že se mě nikdo neptal, určitě bych si *^ přál. : D
  • C byl vytvořen pro formátování textu. Fortran byl vytvořen pro matematické výpočty a před 20 lety měl složitou, mocninnou a maticovou matematiku.
  • @Martin Beckett: Naleznete důkazy o tom, že C bylo vytvořeno pro formátování textu? Zdá se mi to velmi neohrabaný jazyk a to, co jsem ‚ četl o původu C, říká, že bylo navrženo především pro systémové programování pro Unix.
  • @DavidThornley – Byl navržen pro zápis Unixu, ale zdá se, že všechna jeho raná použití Unixu byla formátování textu a pro tuto dobu ‚ má rozsáhlý řetězec a i / o knihovna.
  • +1: Stávající význam pro a**p je vrah. (Hackeři, jak tento problém vyřešit … Brr!)

Odpověď

Mám podezření Je to proto, že každý operátor, kterého uvedete, zvyšuje složitost jazyka. Bariéra pro vstup je proto velmi vysoká. Zjistil jsem, že používám umocňování velmi, velmi zřídka – a jsem více než šťastný, že mohu použít volání metody ano.

Komentáře

  • Každá funkce začíná -100 body.
  • Používám ‚ x**2 a x**3 ne tak zřídka . A magická implementace pow, o které kompilátor ví a optimalizuje ji pro jednoduché případy, by byla hezká.
  • @CodeInChaos: Nicméně x * x a x * x * x nejsou ‚ špatné náhražky čtverce a krychle.
  • @David můžete ‚ t jednoduše napište x*x pokud x je výraz. V nejlepším případě se kód stane nepraktickým a v nejhorším případě pomalejší nebo dokonce chybný. ‚ Takže musíte definovat své vlastní funkce Square a Cube. A i pak by byl kód ošklivější než použití ** jako provozovatele energie.
  • @David Musím dát závorky ano, ale není třeba opakovat ‚ výraz několikrát nafoukne zdrojový kód. Což značně snižuje čitelnost. Běžná eliminace subexprese je možná pouze v případě, že kompilátor může zaručit, že výraz nebude mít vedlejší účinky. Alespoň .net jitter není ‚ v tomto ohledu příliš chytrý.

Odpovědět

Návrháři jazyka Java a základní knihovny se rozhodli převést většinu matematických operací do třídy Math . Viz Math.pow () .

Proč? Flexibilita k upřednostnění výkonu před přesností bit na bit.Proti zbytku jazykových specifikací by bylo možné říci, že chování integrovaných matematických operátorů se může u jednotlivých platforem lišit, zatímco třída Math výslovně uvádí, že chování potenciálně obětuje přesnost výkonu, takže kupující si dávejte pozor:

Na rozdíl od některých numerických metod třídy StrictMath jsou všechny implementace ekvivalentních funkcí třídy Matematika není definována pro vrácení stejných výsledků bit za bitem. Tato relaxace umožňuje výkonnější implementace, kde není nutná přísná reprodukovatelnost.

Odpovědět

Exponentiace byla od počátku součástí Fortranu, protože byla zaměřena přímo na vědecké programování. Inženýři a fyzici to často používají v simulacích, protože vztahy silového zákona jsou ve fyzice běžné.

Python má také silné zastoupení ve vědeckých počítačích (např. NumPy a SciPy). To spolu s operátorem umocňování naznačuje, že bylo zaměřeno také na vědecké programování.

C, Java a C # mají kořeny v systémovém programování. Možná je to vliv, který udržoval umocňování mimo skupinu podporovaných operátorů.

Jen teorie.

Odpověď

C definované operátory pouze pro běžné aritmetické operace přístupné pomocí ALU. Jeho hlavním cílem bylo vytvořit rozhraní čitelné pro člověka ke kódu Assembly.

C ++ nezměnilo žádné chování operátorů, protože chtělo vše kódová základna napsaná v jazyce C byla kompatibilní.

Java udělala totéž, protože nechtěla zastrašit stávající programátory C ++.

Komentáře

  • Když bylo C vytvořeno, množení a dělení zřídka nechybělo v hardwaru a muselo být implementováno do softwaru. Přesto C má operátory násobení a dělení.
  • @siride: Pokud je mi známo, PDP-7, první počítač, na kterém byl spuštěn Unix, měl hardwarové násobení a dělení prostřednictvím EAE. Viz: bitsavers.org/pdf/dec/pdp7/F-75_PDP-7userHbk_Jun65.pdf

Odpověď

No, protože každý operátor, který by měl smysl pro sílu, se již používá. ^ je XOR a ** definuje ukazatel na ukazatel. Takže místo toho mají pouze funkci, která dělá totéž. (like pow ())

Komentáře

  • @RTS – Hledá vývojář jazyka opravdu smysl pro více než efektivní?
  • Dobrý vývojář programovacího jazyka se dívá na obojí. O divu nemohu ‚ říci nic. Ale v jazyce C ++ je funkce pow () počítána v době kompilace. A je stejně efektivní jako běžné operátory.
  • @RTS: Funkce pow() provádí svůj výpočet za běhu, pokud nemáte kompilátor, který dokáže provádět konstantní skládání pro pow(), o čemž velmi pochybuji. (Někteří kompilátoři vám však nabízejí možnost použít výpočet k provedení výpočtu.)
  • @In silico jsem to ale ‚ neznamenal tak, že počítá konečný hodnota, myslel jsem tím, že kompilátoři optimalizují volání funkce, takže máte pouze surovou rovnici.
  • @josefx: Určitě je to ‚ dobrý důvod. Jeden * je lexikální token, ať už se ‚ používá k nepřímému nebo množení. ** což znamená, že umocňování bude jeden nebo dva lexikální žetony a vy opravdu nechcete, aby váš divák musel na symbol narazit tabulka pro tokenizaci.

Odpověď

Faktem je, že aritmetické operátory jsou pouze zkratkami funkcí. (Téměř) Všechno, co s nimi uděláte, lze provést pomocí funkce. Příklad:

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

Je to jen podrobnější, takže nevidím nic špatného na tom, když používám funkce k provádění „power of“.

Odpověď

Sčítání / odčítání / negace a násobení / dělení jsou základní matematické operátory. Pokud byste z moci udělali operátora, kde byste se zastavili? Druhá odmocnina operátor? N-root operátor? Logaritmický operátor?

Nemohu mluvit za jejich tvůrce, ale mohu říci, že si myslím, že by to bylo nepraktické a ne ortogonální mít takové operátory v jazyce. počet znaků, které nejsou alfanumerické / prázdné znaky, zůstává na klávesnici poměrně omezený. Je zvláštní, že v C ++ existuje operátor modulu.

Komentáře

  • +1 – nechápu ‚, proč mít mod jako operátora je divné. ‚ s obvykle jediná instrukce. ‚ je primitivní operace na celá čísla. ‚ s se v počítačové vědě používá všude.(Implementace věcí jako ohraničené vyrovnávací paměti bez mod by zapáchalo)
  • @Billy ONeal: Zvláštní kvůli nekonzistenci mezi možností použití s typy celých čísel a typy s plovoucí desetinnou čárkou . Absolutně užitečné a já bych ‚ nesnil o jeho odstranění. Prostě nepředvídatelné je vše.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *