Dlaczego w Javie / C ++ nie ma operatora mocy?

Chociaż istnieje taki operator – ** w Pythonie, zastanawiałem się, dlaczego Java i C ++ nie mają jeden też.

Łatwo jest stworzyć jedną dla klas, które definiujesz w C ++ z przeciążeniem operatorów (i uważam, że coś takiego jest możliwe również w Javie), ale kiedy mówimy o typach pierwotnych, takich jak int, double i tak dalej, będziesz musiał użyć funkcji bibliotecznej, takiej jak Math.power (i zwykle musisz rzutować oba na podwójne).

Więc – dlaczego nie zdefiniować takiego operatora dla typów pierwotnych?

Komentarze

  • W C ++ nie możemy tworzyć własnych operatorów. Możesz przeciążyć tylko istniejące operatory.
  • @Mahesh, więc mogę stworzyć własną klasę Number i operator przeciążenia ^ jako potęgę. To naprawdę nie pasuje.
  • @RanZilber: Ma to znaczenie, ponieważ pierwszeństwo operatora ^ nie pasuje do pierwszeństwa potęgowania. Rozważ wyrażenie a + b ^ c. W matematyce najpierw wykonywane jest potęgowanie (b ^ c), a następnie wynikowa potęga jest dodawana do a. W C ++ dodawanie jest wykonywane najpierw (a + b), a następnie operator ^ jest wykonywany za pomocą c. Więc nawet jeśli zaimplementowałeś operator ^, aby oznaczać potęgowanie, pierwszeństwo zaskoczy wszystkich.
  • @RamZilber – ^ to XOR w C ++. Zaleca się, aby przeciążony operator nie robił inaczej niż prymitywny typ danych, używając go.
  • @RanZilber: Ponieważ ' nie jest wcale intuicyjny w użyciu którykolwiek z tych operatorów, o których wspomniałeś, oznacza potęgowanie. Poważnie kwestionowałbym kompetencje każdego programisty C ++, który przeciąża operator ++ lub operator ! et. glin. to znaczy potęgowanie. Ale i tak możesz ' t, ponieważ operatory, o których mówisz, akceptują tylko jeden argument; potęgowanie wymaga dwóch argumentów.

Odpowiedź

Ogólnie rzecz biorąc, operatory pierwotne w C (i przez rozszerzenie C ++) są zaprojektowane tak, aby można je było zaimplementować za pomocą prostego sprzętu w mniej więcej jednej instrukcji. Coś w rodzaju potęgowania często wymaga wsparcia oprogramowania; więc domyślnie go tam nie ma.

Ponadto jest dostarczany przez standardową bibliotekę języka w postaci std::pow.

Wreszcie zrobienie tego dla typów danych typu integer nie miałoby większego sensu, ponieważ większość nawet małych wartości do potęgowania wykracza poza zakres wymagany dla int, czyli do 65 535. Jasne, możesz to zrobić dla podwójnych i zmiennoprzecinkowych, ale nie ints, ale dlaczego język byłby niespójny dla rzadko używanej funkcji?

Komentarze

  • Chociaż zgadzam się z większością z tego, fakt, że moduł operator nie może być użyty na typach zmiennoprzecinkowych jest niespójny dla prymitywnych typów danych, ale to też prawdopodobnie nie byłoby pojedynczą instrukcją na żadnym sprzęcie, który sobie wyobrażam, jest teraz powszechny.
  • @Sion: Przynajmniej na x86, moduł to pojedyncza instrukcja. (DIV wykonuje zarówno dzielenie, jak i moduł). ' jednak dotarłeś do punktu spójności.
  • @Billy ONeal: moduł zmiennoprzecinkowy lus w jednej instrukcji? Ostatnio ' nie grzebałem w zespole, żeby się o tym przekonać. Jeśli tak jest ', wówczas operator modułu powinien mieć zastosowanie do typów zmiennoprzecinkowych.
  • @DonalFellows: FORTRAN miał operator potęgowania na długo przed tym, jak miał cokolwiek przypominającego obsługę bignum.
  • @DonalFellows: Operator potęgi nie jest ' tak użyteczny z liczbami całkowitymi, jak z liczbami zmiennoprzecinkowymi, ale w przypadku małych potęg (zwłaszcza do kwadratu) mógłby zdecydowanie ma swoje zastosowania. Osobiście podoba mi się podejście polegające na robieniu operatorów z liter (tak jak robi to Pascal z div lub FORTRAN z .EQ.); w zależności od reguł białych znaków języka może istnieć możliwość posiadania dowolnej liczby operatorów bez wymagania, aby były to słowa zastrzeżone.

Odpowiedź

To pytanie dotyczy C ++: Stroustrup,„ Design and Evolution of C ++ ”omawia je w sekcji 11.6.1, str. 247-250.

Pojawiły się ogólne zastrzeżenia co do dodania nowy operator. Dodałoby to do i tak już przesadnie skomplikowanej tabeli pierwszeństwa. Członkowie grupy roboczej uważali, że zapewniłoby to jedynie niewielką wygodę w stosunku do pełnienia funkcji i chcieli czasami móc zastępować swoje własne funkcje.

Nie było dobrego kandydata na operatora.^ to wyłączność lub, a ^^ wywołało zamieszanie ze względu na związek między & a | i && i ||. ! był nieodpowiedni, ponieważ występowałaby naturalna tendencja do zapisywania != w celu potęgowania istniejącej wartości, a ta została już wykorzystana. Najlepszym z dostępnych mógł być *^, którego najwyraźniej nikt nie lubił.

Stroustrup ponownie wziął pod uwagę **, ale ma już znaczenie w C: a**p to a razy cokolwiek p wskazuje na, i char ** c; deklaruje c jako wskaźnik do wskaźnika char. Wprowadzenie ** jako tokenu oznaczającego „deklarację wskaźnika do wskaźnika do”, razy to, na co wskazuje następna rzecz „(jeśli jest to wskaźnik) lub„ potęgowanie ”(jeśli następuje przez liczbę) powodował problemy z pierwszeństwem. a/b**p musiałby przeanalizować jako a/(b**p), gdyby p było liczbą, ale (a/b) * *p gdyby p było wskaźnikiem, więc musiałoby to zostać rozwiązane w parserze.

Innymi słowy, byłoby to możliwe, ale skomplikowałoby to tablicę pierwszeństwa i parser i oba są już zbyt skomplikowane.

Nie znam historii o Javie; wszystko, co mogłem zrobić, to spekulacje. Jeśli chodzi o C, tam, gdzie się zaczęło, wszystkie operatory C można łatwo przetłumaczyć na kod asemblera, częściowo w celu uproszczenia kompilatora, a częściowo w celu uniknięcia ukrywania czasochłonnych funkcji w prostych operatorach (fakt, że operator+() i inni mogli ukryć wielką złożoność, a hity wydajności były jednym z wczesnych zarzutów dotyczących C ++).

Komentarze

  • Dobra odpowiedź. Wydaje mi się, że Java starała się uprościć C pod tym względem, więc nikt nie chciał dodać nowego operatora. To ' szkoda, że nikt mnie o to nie pytał, na pewno spodobałbym się *^. : D
  • C został zbudowany do formatowania tekstu. Fortran został zbudowany do wykonywania obliczeń matematycznych i 20 lat wcześniej miał matematykę złożoną, potęgową i macierzową.
  • @Martin Beckett: Czy możesz znaleźć dowody, że C został zbudowany do formatowania tekstu? Wydaje mi się, że jest to bardzo niezgrabny język, a to, co ' czytałem o pochodzeniu C, mówi, że zostało zaprojektowane głównie do programowania systemowego dla Uniksa.
  • @DavidThornley – Został zaprojektowany do pisania w Uniksie, ale wydaje się, że wszystkie wczesne zastosowania Uniksa dotyczyły formatowania tekstu, a dla niego ' ma obszerny ciąg i / o.
  • +1: Istniejące znaczenie a**p jest zabójcą. (Jak obejść ten problem… Brr!)

Odpowiedź

Podejrzewam to dlatego, że każdy wprowadzony operator zwiększa złożoność języka. Bariera wejścia jest zatem bardzo wysoka. Bardzo, bardzo rzadko używam potęgowania – i jestem bardziej niż szczęśliwy, gdy używam wywołania metody więc.

Komentarze

  • Każdy obiekt zaczyna się z -100 punktami.
  • Ja ' d używam x**2 i x**3 nie tak rzadko . A magiczna implementacja pow, o której kompilator wie i optymalizuje ją pod kątem prostych przypadków, byłaby miła.
  • @CodeInChaos: Jednak x * x i x * x * x nie ' t złe substytuty kwadratu i sześcianu.
  • @David you can ' t po prostu napisz x*x, jeśli x jest wyrażeniem. W najlepszym przypadku kod staje się nieporęczny, aw najgorszym wolniejszy lub nawet zły. Musisz więc ' zdefiniować własne funkcje kwadratu i sześcianu. I nawet wtedy kod byłby brzydszy niż użycie ** jako operatora potęgi.
  • @David Muszę wstawić nawiasy tak, ale nie ' nie muszę powtarzać wyrażenie kilka razy i powiększa kod źródłowy. Co znacznie ogranicza czytelność. Zwykła eliminacja podwyrażeń jest możliwa tylko wtedy, gdy kompilator może zagwarantować, że wyrażenie jest wolne od skutków ubocznych. A przynajmniej jitter .net nie jest ' zbyt inteligentny pod tym względem.

Odpowiedź

Projektanci języka Java i podstawowych bibliotek zdecydowali się przenieść większość operacji matematycznych do klasy Math . Zobacz Math.pow () .

Dlaczego? Elastyczność polegająca na nadaniu priorytetu wydajności nad precyzją bit za bit.Byłoby sprzeczne z resztą specyfikacji języka, gdyby powiedzieć, że zachowanie wbudowanych operatorów matematycznych może się różnić w zależności od platformy, podczas gdy klasa Math wyraźnie stwierdza, że zachowanie potencjalnie poświęca precyzję dla wydajności, więc kupujący uważaj:

W przeciwieństwie do niektórych metod numerycznych klasy StrictMath , wszystkie implementacje równoważnych funkcji klasy Math nie są zdefiniowane tak, aby zwracały takie same wyniki bit po bicie. To złagodzenie pozwala na bardziej wydajne implementacje, w których nie jest wymagana ścisła odtwarzalność.

Odpowiedź

Potęgowanie było częścią Fortran od samego początku, ponieważ było ukierunkowane bezpośrednio na programowanie naukowe. Inżynierowie i fizycy często używają go w symulacjach, ponieważ w fizyce relacje prawa potęgowego są powszechne.

Python ma również silną pozycję w obliczeniach naukowych (np. NumPy i SciPy). To, wraz z operatorem potęgowania, sugeruje, że był on również ukierunkowany na programowanie naukowe.

C, Java i C # mają korzenie w programowaniu systemowym. Być może jest to wpływ, który powstrzymał potęgowanie poza grupą obsługiwanych operatorów.

Tylko teoria.

Odpowiedź

C zdefiniował operatory tylko dla typowych operacji arytmetycznych dostępnych z ALU. Jego głównym celem było stworzenie czytelnego dla człowieka interfejsu do kodu asemblera.

C ++ nie zmienił żadnego zachowania operatora, ponieważ chciał wszystko baza kodu napisana w C, aby była zgodna.

Java zrobiła to samo, ponieważ nie chciała zastraszyć istniejących programistów C ++.

Komentarze

  • Kiedy stworzono C, mnożenie i dzielenie nierzadko brakowało sprzętu i musiało być zaimplementowane w oprogramowaniu. Jednak C ma operatory mnożenia i dzielenia.
  • @siride: O ile mi wiadomo, PDP-7, pierwszy komputer z systemem Unix, miał sprzętowe mnożenie i dzielenie przez EAE. Zobacz: bitsavers.org/pdf/dec/pdp7/F-75_PDP-7userHbk_Jun65.pdf

Odpowiedz

Cóż, ponieważ każdy operator, który miałby sens dla potęgi, jest już używany. ^ to XOR, a ** definiuje wskaźnik do wskaźnika. Zamiast tego mają po prostu funkcję, która robi to samo. (jak pow ())

Komentarze

  • @RTS – Czy programista językowy naprawdę szuka sensu bardziej niż efektywnego?
  • Dobry programista języków programowania przygląda się obu. Nie mogę ' nie powiedzieć nic o Javie. Ale w języku c ++ funkcja pow () jest obliczana w czasie kompilacji. I jest tak samo wydajna jak zwykłe operatory.
  • @RTS: Funkcja pow() wykonuje obliczenia w czasie wykonywania, chyba że masz kompilator, który potrafi składać ciągłe dla pow(), w co bardzo wątpię. (Jednak niektóre kompilatory dają możliwość korzystania z wewnętrznych funkcji procesora do wykonywania obliczeń).
  • @In silico Nie ' nie oznacza, że oblicza ostateczną wartość, miałem na myśli, że kompilatory zoptymalizują wywołanie funkcji, więc masz tylko surowe równanie.
  • @josefx: Jasne, że ' to dobry powód. Pojedynczy * jest tokenem leksykalnym, niezależnie od tego, czy ' jest używany do pośrednictwa czy mnożenia. ** oznaczające, że potęgowanie będzie jednym lub dwoma tokenami leksykalnymi, a naprawdę nie ' nie chcesz, aby Twój lekser musiał uderzać w symbol table do tokenizacji.

Odpowiedź

Faktem jest, że operatory arytmetyczne to tylko skróty funkcji. (Prawie) Wszystko, co z nimi zrobisz, można wykonać za pomocą funkcji. Przykład:

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

Jest po prostu bardziej szczegółowy, więc nie widzę nic złego w używaniu funkcji do wykonywania funkcji „potęga”.

Odpowiedź

Dodawanie / odejmowanie / negacja i mnożenie / dzielenie to podstawowe operatory matematyczne. Gdybyś miał zrobić potęgę operatorem, na którym miejscu byś się zatrzymał? Operator? Operator N-root? Operator logarytmowy?

Nie mogę mówić w imieniu ich twórców, ale mogę powiedzieć, że uważam, że byłoby nieporęczne i nie ortogonalne, gdyby takie operatory były używane w języku. liczba znaków innych niż alfanumeryczne / białych znaków pozostałych na klawiaturze jest raczej ograniczona. To dziwne, że w C ++ jest operator modułu.

Komentarze

  • +1 – nie ' nie rozumiem, dlaczego operator mod jest dziwny. To ' to zwykle pojedyncza instrukcja. Jest to ' operacja pierwotna na liczbach całkowitych. ' jest używany najczęściej w informatyce.(Wdrażanie takich rzeczy jak bufory ograniczone bez mod śmierdzi)
  • @Billy ONeal: Dziwne z powodu niespójności między możliwością użycia z typami całkowitymi i zmiennoprzecinkowymi . Jednak absolutnie przydatne i nie ' marzy o jego usunięciu. Po prostu dziwaczne to wszystko.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *