Chociaż istnieje taki operator - **
w Pythonie zastanawiałem się, dlaczego Java i C ++ też go nie mają.
Łatwo jest utworzyć jedną dla klas, które definiujesz w C ++ z przeciążeniem operatora (i uważam, że takie rzeczy są możliwe również w Javie), ale mówiąc o prymitywnych typach, takich jak int, double i tak dalej, będziesz musiał użyć biblioteki działają jak Math.power
(i zwykle muszą rzutować oba na podwójne).
Dlaczego więc nie zdefiniować takiego operatora dla typów pierwotnych?
^
operatora nie jest zgodny z priorytetem potęgowania. Rozważ wyrażeniea + b ^ c
. W matematyce najpierw potęguje się potęgowanie (b ^ c
), a następnie dodaje się wynikową moca
. W C ++ dodawanie odbywa się najpierw (a + b
), a następnie za pomocą^
operatorac
. Więc nawet jeśli zaimplementowałeś^
operatora jako potęgowanie, pierwszeństwo zaskoczy wszystkich.^
jest XOR w C ++. Zaleca się, aby przeciążony operator nie robił inaczej, niż robi to prymitywny typ danych.++
operatora lub!
operatora et. glin. znaczy potęgowanie. Ale i tak nie możesz, ponieważ operatorzy, o których mówisz, akceptują tylko jeden argument; potęgowanie wymaga dwóch argumentów.Odpowiedzi:
Mówiąc ogólnie, prymitywne operatory w C (i przez rozszerzenie C ++) są zaprojektowane tak, aby mogły być implementowane przez prosty sprzęt w mniej więcej jednej instrukcji. Coś w rodzaju potęgowania często wymaga wsparcia oprogramowania; więc nie ma go domyślnie.
Ponadto jest dostarczany przez standardową bibliotekę języka w postaci
std::pow
.Wreszcie, robienie tego dla typów liczb całkowitych nie miałoby większego sensu, ponieważ większość nawet niewielkich wartości potęgowania wyklucza zakres wymagany dla int, czyli do 65 535. Jasne, możesz to zrobić dla podwójnych i zmiennoprzecinkowych, ale nie ints, ale po co sprawić, że język jest niespójny dla rzadko używanej funkcji?
źródło
DIV
robi zarówno podział, jak i moduł) Masz mnie jednak w punkcie zgodności.div
FORTRAN.EQ.
); w zależności od reguł białych znaków w języku, może istnieć możliwość posiadania dowolnej liczby operatorów bez wymagania, aby były to słowa zastrzeżone.Na to pytanie można odpowiedzieć w przypadku C ++: Stroustrup, „Projektowanie i ewolucja C ++” omawia to w sekcji 11.6.1, s. 247–250.
Były ogólne zastrzeżenia do dodania nowego operatora. Dodałoby to do już skomplikowanej tabeli pierwszeństwa. Członkowie grupy roboczej sądzili, że zapewni to jedynie niewielką wygodę w sprawowaniu funkcji, i czasami chcieli móc zastąpić własne funkcje.
Nie było dobrego kandydata na operatora.
^
jest wyłącznym-lub, i^^
zaprosił zamieszanie ze względu na związek pomiędzy&
a|
i&&
a||
.!
był nieodpowiedni, ponieważ naturalna tendencja do pisania w!=
celu potęgowania istniejącej wartości była już zajęta. Być może najlepszy dostępny*^
, które najwyraźniej nikt naprawdę nie lubił.Stroustrup zastanowił się
**
jeszcze raz, ale ma już znaczenie w C:a**p
jesta
czasem, któryp
wskazuje, ichar ** c;
deklarujec
jako wskaźnik do wskaźnikachar
. Wprowadzenie**
jako tokena oznaczającego „deklarację wskaźnika do wskaźnika”, „razy”, co wskazuje następna rzecz „(jeśli jest to wskaźnik) lub„ wykładnik ”(jeśli następuje po nim liczba), spowodowało problemy z pierwszeństwem.a/b**p
musiałby parsować tak,a/(b**p)
jakby p był liczbą, ale(a/b) * *p
gdyby p był wskaźnikiem, to musiałoby to zostać rozwiązane w parserze.Innymi słowy, byłoby to możliwe, ale skomplikowałoby to tabelę pierwszeństwa i parser, a oba są już zbyt skomplikowane.
Nie znam historii o Javie; wszystko, co mogłem zrobić, to spekulować. Jeśli chodzi o C, w którym się zaczął, wszystkie operatory C są łatwo tłumaczone na kod asemblera, częściowo w celu uproszczenia kompilatora, a częściowo w celu uniknięcia ukrywania czasochłonnej funkcjonalności w prostych operatorach (fakt, że
operator+()
i inni mogli ukryć wielką złożoność i wydajności wydajności był jednym z nich wczesnych skarg na C ++).źródło
*^
. : Da**p
„zabójca”. (Włamania do obejścia tego problemu… Brr!)I podejrzewam, że to dlatego, że każdy operator przedstawisz zwiększa złożoność języka. Bariera wejścia jest zatem bardzo wysoka. Używam potęgowania bardzo, bardzo rzadko - i cieszę się, że mogę to zrobić za pomocą wywołania metody.
źródło
x**2
ix**3
nie tak rzadko. Przydałaby się magiczna implementacja pow, o której kompilator wie i optymalizuje dla prostych przypadków.x * x
ix * x * x
nie są złym zamiennikiem kwadratu i sześcianu.x*x
jeśli x jest wyrażeniem. W najlepszym przypadku kod staje się nieporęczny, aw najgorszym wolniejszy lub nawet błędny. Musisz więc zdefiniować własne funkcje Square i Cube. I nawet wtedy kod byłby brzydszy niż użycie ** jako operatora mocy.Projektanci języka Java i głównych bibliotek postanowili przenieść większość operacji matematycznych do klasy Math . Zobacz Math.pow () .
Czemu? Elastyczność w celu nadania priorytetu wydajności w porównaniu z precyzją bit-za-bit. Stwierdzenie, że zachowanie wbudowanych operatorów matematycznych może się różnić w zależności od platformy, byłoby sprzeczne z resztą specyfikacji językowej, podczas gdy klasa Math wyraźnie stwierdza, że zachowanie potencjalnie poświęca precyzję wydajności, dlatego nabywca powinien się wystrzegać:
źródło
Potęgowanie było częścią Fortran od samego początku, ponieważ było ukierunkowane wprost na programowanie naukowe. Inżynierowie i fizycy często używają go w symulacjach, ponieważ związki prawa mocy są powszechne w fizyce.
Python jest również mocno obecny w informatyce naukowej (np. NumPy i SciPy). To, wraz z operatorem potęgowania, sugeruje, że miał on również na celu programowanie naukowe.
C, Java i C # mają swoje korzenie w programowaniu systemu. Być może jest to wpływ, który utrzymywał potęgowanie poza grupą obsługiwanych operatorów.
Po prostu teoria.
źródło
C zdefiniował tylko operatory 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ł, aby cała baza kodu napisana w C była zgodna.
Java zrobiła to samo, ponieważ nie chciała zastraszyć istniejących programistów C ++.
źródło
Cóż, ponieważ każdy operator, który miałby sens dla mocy, jest już w użyciu. ^ oznacza XOR, a ** definiuje wskaźnik do wskaźnika. Zamiast tego mają po prostu funkcję, która robi to samo. (jak pow ())
źródło
pow()
Funkcja wykonuje swoje obliczenia w czasie wykonywania, chyba że masz kompilator, który może wykonywać ciągłe składaniepow()
, o co bardzo wątpię. (Niektóre kompilatory dają jednak możliwość użycia wewnętrznych funkcji procesora do wykonania obliczeń.)*
to token leksykalny, bez względu na to, czy jest używany do pośredniego czy mnożenia.**
Sens potęgowanie będzie jeden lub dwa tokeny leksykalne, a ty naprawdę nie chcesz lexer musiał uderzyć tablicę symboli do tokenize.Faktem jest, że operatory arytmetyczne są jedynie skrótami funkcji. (Prawie) Wszystko, co z nimi zrobisz, można wykonać za pomocą funkcji. Przykład:
Jest to po prostu bardziej szczegółowe, więc nie widzę nic złego w używaniu funkcji do wykonywania „mocy”.
źródło
Dodawanie / odejmowanie / negowanie i mnożenie / dzielenie to podstawowe operatory matematyczne. Gdybyś miał uczynić moc operatorem, gdzie byś przestał? Operator pierwiastka kwadratowego? Operator N-root? Operator logarytmiczny?
Nie mogę mówić za ich twórcami, ale mogę powiedzieć, że myślę, że takie operatory w języku stałyby się niewygodne, a nie ortogonalne. Pozostała na klawiaturze liczba znaków alfanumerycznych / białych znaków jest raczej ograniczona. W tej chwili dziwne jest, że w C ++ jest operator modułu.
źródło
mod
jako operatora jest dziwne. Zwykle jest to pojedyncza instrukcja. Jest to operacja pierwotna na liczbach całkowitych. Najczęściej stosuje się go w informatyce. (Wdrażanie rzeczy takich jak ograniczone bufory bezmod
śmierdziałoby)