Mengapa tidak ada operator daya di Java / C ++?

23

Meskipun ada operator seperti itu - **dengan Python, saya bertanya-tanya mengapa Java dan C ++ tidak memilikinya juga.

Sangat mudah untuk membuat satu untuk kelas yang Anda definisikan di C ++ dengan operator overloading (dan saya percaya hal seperti itu mungkin juga di Jawa), tetapi ketika berbicara tentang tipe primitif seperti int, double dan sebagainya, Anda harus menggunakan perpustakaan berfungsi seperti Math.power(dan biasanya harus melakukan keduanya untuk menggandakan).

Jadi - mengapa tidak mendefinisikan operator semacam itu untuk tipe primitif?

RanZilber
sumber
8
Di C ++, kami tidak dapat membuat operator kami sendiri. Anda hanya dapat membebani operator yang ada.
1
@ Mahesh, jadi saya bisa membuat kelas Number saya sendiri dan operator ^ menjadi kekuatan. Benar-benar tidak cocok.
22
@RanZilber: Itu penting karena prioritas ^operator tidak sesuai dengan prioritas eksponen. Pertimbangkan ungkapannya a + b ^ c. Dalam matematika, eksponensial dilakukan pertama kali ( b ^ c), kemudian kekuatan yang dihasilkan ditambahkan a. Dalam C ++, penambahan dilakukan terlebih dahulu ( a + b) kemudian ^operator dilakukan dengan c. Jadi, bahkan jika Anda benar-benar mengimplementasikan ^operator berarti eksponensial, prioritasnya akan mengejutkan semua orang.
Di silico
2
@RamZilber - ^adalah XOR dalam C ++. Disarankan agar operator yang kelebihan beban tidak melakukan apa pun yang dilakukan oleh tipe data primitif.
4
@RanZilber: Karena sama sekali tidak intuitif untuk menggunakan salah satu operator yang Anda sebut berarti eksponensial. Saya akan secara serius mempertanyakan kompetensi setiap programmer C ++ yang membebani ++operator atau !operator et. Al. berarti eksponen. Tetapi Anda tidak dapat melakukannya, karena operator yang Anda bicarakan hanya menerima satu argumen; eksponensial membutuhkan dua argumen.
Di silico

Jawaban:

32

Secara umum, operator primitif dalam C (dan dengan ekstensi C ++) dirancang untuk dapat diterapkan oleh perangkat keras sederhana dalam kira-kira satu instruksi tunggal. Sesuatu seperti eksponensial sering kali memerlukan dukungan perangkat lunak; jadi tidak ada di sana secara default.

Juga, disediakan oleh perpustakaan standar bahasa dalam bentuk std::pow.

Akhirnya, melakukan ini untuk tipe data integer tidak akan masuk akal, karena sebagian besar nilai eksponensial bahkan kecil mengeluarkan kisaran yang diperlukan untuk int, yaitu hingga 65.535. Tentu, Anda bisa melakukan ini untuk ganda dan mengapung tetapi tidak int, tetapi mengapa membuat bahasa tidak konsisten untuk fitur yang jarang digunakan?

Billy ONeal
sumber
4
Sementara saya setuju dengan sebagian besar dari ini, fakta bahwa operator modulus tidak dapat digunakan pada tipe floating point tidak konsisten untuk tipe data primitif, tetapi itu juga mungkin tidak akan menjadi instruksi tunggal pada perangkat keras yang saya bayangkan adalah cara yang lazim sekarang.
@ Sion: Setidaknya pada x86, modulus adalah instruksi tunggal. ( DIVApakah divisi dan modulus) Anda punya saya pada titik konsistensi.
Billy ONeal
@Billy ONeal: Modulus titik apung dalam satu instruksi? Saya belum bergurau di pertemuan sampai akhir untuk tahu untuk diri saya sendiri. Jika itu yang terjadi, maka operator modulus harus dibuat berlaku untuk tipe floating point.
3
@DonalFellows: FORTRAN memiliki operator eksponasi jauh sebelum memiliki sesuatu yang menyerupai dukungan bignum.
supercat
1
@DonalFellows: Operator daya tidak berguna dengan bilangan bulat seperti dengan float, tetapi untuk kekuatan kecil (terutama kuadrat) itu pasti bisa memiliki kegunaannya. Secara pribadi saya suka pendekatan membuat operator keluar dari huruf (seperti Pascal dengan divatau FORTRAN dengan .EQ.); tergantung pada aturan spasi putih bahasa, dimungkinkan untuk memiliki jumlah operator yang sewenang-wenang tanpa mengharuskan mereka untuk memesan kata-kata.
supercat
41

Pertanyaan ini dapat dijawab untuk C ++: Stroustrup, "Desain dan Evolusi C ++" membahas hal ini di bagian 11.6.1, hlm. 247-250.

Ada keberatan umum untuk menambah operator baru. Itu akan menambah tabel prioritas yang sudah terlalu rumit. Para anggota kelompok kerja berpikir bahwa itu hanya akan memberikan sedikit kenyamanan daripada memiliki fungsi, dan mereka ingin dapat mengganti fungsi mereka sendiri kadang-kadang.

Tidak ada kandidat yang baik untuk operator. ^eksklusif-atau, dan ^^kebingungan diundang karena hubungan antara &dan |dan &&dan ||. !tidak cocok karena akan ada kecenderungan alami untuk menulis !=untuk nilai yang sudah ada, dan itu sudah diambil. Yang terbaik mungkin tersedia *^, yang tampaknya tidak ada yang benar-benar suka.

Stroustrup dipertimbangkan **lagi, tetapi sudah memiliki arti dalam C: a**padalah akali apa pun pmenunjuk ke, dan char ** c;menyatakan csebagai pointer ke pointer ke char. Memperkenalkan **sebagai token yang berarti "deklarasi pointer ke pointer ke", "berapa kali hal berikutnya menunjuk ke" (jika itu adalah pointer) atau "eksponensial" (jika diikuti oleh angka) menyebabkan masalah diutamakan. a/b**pharus mengurai seolah- a/(b**p)olah p adalah angka, tetapi (a/b) * *pjika p adalah pointer, jadi ini harus diselesaikan di parser.

Dengan kata lain, itu mungkin saja terjadi, tetapi itu akan memperumit tabel presedensi dan pengurai, dan keduanya sudah terlalu rumit.

Saya tidak tahu cerita tentang Jawa; yang bisa saya lakukan hanyalah berspekulasi. Adapun C, di mana itu dimulai, semua operator C mudah diterjemahkan ke dalam kode assembly, sebagian untuk menyederhanakan kompiler dan sebagian untuk menghindari menyembunyikan fungsi yang memakan waktu dalam operator sederhana (fakta bahwa operator+()dan yang lain dapat menyembunyikan kerumitan besar dan hit kinerja adalah satu dari keluhan awal tentang C ++).

David Thornley
sumber
2
Jawaban bagus. Saya kira Java mencoba menyederhanakan C dalam hal ini, jadi tidak ada yang ingin menambahkan operator baru. Sayang sekali bahwa tidak ada yang bertanya padaku, aku pasti akan suka *^. : D
maaartinus
1
C dibangun untuk melakukan pemformatan teks. Fortran dibangun untuk mengerjakan matematika dan memiliki matematika yang rumit, kuat, dan matriks 20 tahun sebelumnya.
Martin Beckett
@ Martin Beckett: Dapatkah Anda menemukan bukti bahwa C dibuat untuk pemformatan teks? Sepertinya saya bahasa yang sangat canggung untuk itu, dan apa yang saya baca tentang asal C mengatakan itu dirancang untuk pemrograman sistem untuk Unix terutama.
David Thornley
@ Davidvidhorn - Ini dirancang untuk menulis Unix, tetapi semua penggunaan awal Unix tampaknya telah memformat teks, dan untuk saat ini ia memiliki string yang luas dan perpustakaan i / o.
Martin Beckett
6
+1: Arti yang ada untuk a**padalah si pembunuh. (Peretasan untuk mengatasi masalah itu ... Brr!)
Donal Fellows
13

Saya menduga itu karena setiap operator yang Anda perkenalkan meningkatkan kompleksitas bahasa. Karena itu penghalang untuk masuk sangat tinggi. Saya menemukan diri saya menggunakan exponentiation sangat, sangat jarang - dan saya lebih dari senang untuk menggunakan pemanggilan metode untuk melakukannya.

Jon Skeet
sumber
3
Saya akan menggunakan x**2dan x**3tidak jarang. Dan implementasi pow ajaib yang diketahui oleh kompiler dan dioptimalkan untuk kasus-kasus sederhana akan lebih baik.
CodesInChaos
2
@ CodeInChaos: Namun x * xdan x * x * xbukan pengganti yang buruk untuk kuadrat dan kubus.
David Thornley
5
@ David, kamu tidak bisa hanya menulis x*xjika x adalah ekspresi. Dalam kasus terbaik, kode menjadi sulit digunakan, dan dalam kondisi terburuk lebih lambat atau bahkan salah. Jadi, Anda perlu mendefinisikan fungsi Square dan Cube Anda sendiri. Dan bahkan kodenya akan lebih jelek daripada menggunakan ** sebagai operator listrik.
CodesInChaos
1
@ David Saya harus meletakkan tanda kurung ya, tetapi tidak perlu mengulangi ekspresi beberapa kali dan menggembungkan kode sumber. Yang mengurangi keterbacaan banyak. Dan eliminasi subekspresi umum hanya mungkin jika kompiler dapat menjamin ekspresi bebas dari efek samping. Dan setidaknya .net jitter tidak terlalu pintar dalam hal itu.
CodesInChaos
11

Perancang perpustakaan inti dan bahasa Jawa memutuskan untuk menurunkan sebagian besar operasi matematika ke kelas Matematika . Lihat Math.pow () .

Mengapa? Fleksibilitas untuk memprioritaskan kinerja di atas presisi bit-for-bit. Akan bertentangan dengan spesifikasi bahasa lainnya untuk mengatakan bahwa perilaku operator matematika bawaan dapat bervariasi dari platform ke platform, sedangkan kelas Matematika secara khusus menyatakan bahwa perilaku tersebut berpotensi mengorbankan presisi untuk kinerja, sehingga pembeli berhati-hati:

Tidak seperti beberapa metode numerik kelas StrictMath , semua implementasi fungsi setara kelas Math tidak didefinisikan untuk mengembalikan hasil yang sama bit-for-bit. Relaksasi ini memungkinkan implementasi yang berkinerja lebih baik di mana reproduksibilitas yang ketat tidak diperlukan.


sumber
6

Eksponen adalah bagian dari Fortran sejak awal karena ditujukan tepat pada pemrograman ilmiah. Insinyur dan fisikawan sering menggunakannya dalam simulasi, karena hubungan kekuatan hukum umum dalam fisika.

Python memiliki kehadiran yang kuat dalam komputasi ilmiah, juga (misalnya NumPy dan SciPy). Itu, bersama dengan operator eksponensial, menyarankan bahwa itu ditujukan untuk pemrograman ilmiah juga.

C, Java, dan C # memiliki akar dalam pemrograman sistem. Mungkin itu pengaruh yang membuat eksponensial keluar dari kelompok operator yang didukung.

Hanya sebuah teori.

Duffymo
sumber
4

C hanya operator yang ditentukan untuk operasi aritmatika umum yang dapat diakses dengan ALU. Tujuan utamanya adalah menciptakan antarmuka yang dapat dibaca manusia untuk kode Majelis.

C ++ tidak mengubah perilaku operator karena, ia ingin semua basis kode yang ditulis dalam C sesuai.

Java melakukan hal yang sama karena tidak ingin mengintimidasi programmer C ++ yang ada.

Tugrul Ates
sumber
Ketika C dibuat, perkalian dan pembagian tidak jarang kurang dalam perangkat keras dan harus diimplementasikan dalam perangkat lunak. Namun C memiliki operator multiplikasi dan divisi.
siride
@siride: Setahu saya, PDP-7 komputer pertama yang menjalankan Unix, memiliki perkalian dan pembagian perangkat keras melalui EAE-nya. Silakan lihat: bitsavers.org/pdf/dec/pdp7/F-75_PDP-7userHbk_Jun65.pdf
Tugrul Ates
1

Yah karena setiap operator yang masuk akal untuk daya sudah digunakan. ^ adalah XOR dan ** mendefinisikan pointer ke pointer. Jadi alih-alih mereka hanya memiliki fungsi yang melakukan hal yang sama. (seperti pow ())

Skyler Saleh
sumber
@RTS - Apakah pengembang langauge benar-benar mencari akal lebih dari efisiensi?
Pengembang bahasa pemrograman yang baik memperhatikan keduanya. Saya tidak bisa mengatakan apa-apa tentang java. Tetapi dalam c ++ fungsi pow () dihitung pada waktu kompilasi. Dan sama efisiennya dengan operator reguler.
@ RTS: pow()Fungsi melakukan komputasi pada saat runtime, kecuali jika Anda punya kompiler yang dapat melakukan pelipatan konstan pow(), yang saya sangat ragu. (Beberapa kompiler memberi Anda pilihan untuk menggunakan intrinsik prosesor untuk melakukan perhitungan.)
In silico
@In silico Saya tidak bermaksud bahwa itu menghitung nilai akhir, saya maksudkan bahwa kompiler akan mengoptimalkan panggilan fungsi, jadi Anda hanya memiliki persamaan mentah.
2
@ josefx: Tentu itu alasan yang bagus. Satu *adalah token leksikal, apakah itu digunakan untuk tipuan atau perkalian. Sebuah **eksponensial makna akan baik satu atau dua token leksikal, dan Anda benar-benar tidak ingin lexer Anda harus memukul tabel simbol untuk tokenize.
David Thornley
0

Faktanya adalah, operator aritmatika hanyalah pintasan fungsi. (Hampir) Segala sesuatu yang Anda lakukan dengan mereka dapat dilakukan dengan suatu fungsi. Contoh:

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

Itu hanya lebih verbose, jadi saya melihat tidak ada yang salah dengan menggunakan fungsi untuk melakukan 'kekuatan'.

Xeo
sumber
-1

Penambahan / pengurangan / negasi dan perkalian / pembagian adalah operator matematika dasar. Jika Anda menjadikan daya sebagai operator, di mana Anda akan berhenti? Operator akar kuadrat? Operator N-root? Operator logaritma?

Saya tidak dapat berbicara untuk pencipta mereka, tetapi saya dapat mengatakan bahwa saya pikir itu akan menjadi sulit dan tidak ortogonal untuk memiliki operator seperti itu dalam bahasa tersebut. Jumlah karakter non-alfanumerik / spasi putih yang tersisa pada keyboard agak terbatas. Seperti itu, aneh bahwa ada operator modulus di C ++.

Sion Sheevok
sumber
+1 - Saya tidak mengerti mengapa memiliki modsebagai operator itu aneh. Biasanya satu instruksi. Ini adalah operasi primitif pada bilangan bulat. Ini digunakan sebagian besar di mana-mana dalam ilmu komputer. (Menerapkan hal-hal seperti buffer yang dibatasi tanpa modbau)
Billy ONeal
@Billy ONeal: Aneh karena ketidakkonsistenan antara bisa digunakan dengan tipe integer dan tipe floating point. Sangat berguna dan saya tidak akan bermimpi untuk menghapusnya. Hanya unik itu saja.