Apakah ada bahasa pemrograman di mana 1/6 berperilaku sama dengan 1.0 / 6.0?

11

Sementara saya pemrograman di C ++ beberapa hari yang lalu, saya membuat kesalahan ini (bahwa saya memiliki sejarah membuatnya!). Di salah satu bagian dari kode saya, saya memiliki 1/6 dan saya mengharapkannya menjadi 0,16666666666 yang tidak demikian. Seperti yang Anda ketahui hasilnya adalah 0 - C, C ++, Java, Python, semua berperilaku sama.

Saya mempostingnya di halaman Facebook saya dan sekarang ada perdebatan tentang apakah ada bahasa pemrograman di mana 1/6berperilaku sama seperti 1.0/6.0.

Pouya
sumber
5
Haskell. 1/6 = 0.16666666666666666
t123
PowerShell menghasilkan 0.1666666666666667, yang mengejutkan saya karena 1 adalah bilangan bulat. Saya bertaruh ada beberapa bahasa .NET lainnya yang menghasilkan nilai yang Anda harapkan.
JohnL
Ada, secara teori, jumlah mereka yang tidak terbatas .. Berikut ini yang lain: Rebol , serta turunannya seperti Orca, Red, dan sebagainya. >> 1 / 6->== 0.166666666666667
Izkata
Lua melakukan ini. Hanya memiliki satu Nomor jenis, yang biasanya adalah sama dengan C ganda.
Machado
Dalam Clojure 1/6sebenarnya 1/6 (tipe fraksional) yang, dipaksa untuk Double, adalah 1.66666 ...
kaoD

Jawaban:

17

Apakah semua orang lupa Pascal?

1/6hasil 0.1666666...(dengan presisi apa pun didukung).

1 div 6 hasil panen 0

Dapat diperdebatkan apakah aturan C adalah kesalahan. Hampir semua operator aritmatika C, di mana operan memiliki tipe yang sama, menghasilkan hasil dari tipe yang sama. Ada sesuatu yang bisa dikatakan untuk konsistensi.

Selain itu, karena C terutama ditargetkan pada kode tingkat sistem, sebagian besar program C tidak menggunakan floating-point sama sekali. Pada suatu waktu, secara tidak sengaja menambahkan kode floating-point ke program yang sebaliknya tidak memerlukannya bisa menjadi masalah serius. Itu mungkin masih terjadi, untuk sistem tertanam kecil - yang, sekali lagi, merupakan target utama untuk C.

Di sebagian besar program C, memotong divisi integer mungkin adalah apa yang Anda inginkan.

Jika 1 / 6menghasilkan hasil floating-point dalam C, maka:

  • Itu akan menjadi inkonsistensi dalam bahasa.
  • Standar akan harus membuat pilihan yang sewenang-wenang yang tipe floating-point digunakan untuk hasilnya ( doublemungkin tampak seperti pilihan yang alami, tetapi Anda mungkin lebih suka presisi tambahan long double)
  • Bahasa masih harus memiliki operasi untuk divisi integer; melakukan penambahan floating-point dan kemudian memotong kemungkinan tidak akan cukup baik.

C dapat menyediakan operator terpisah untuk dua jenis divisi, tetapi poin kedua di atas masih berlaku: mana dari tiga jenis floating-point yang akan digunakan untuk hasilnya? Dan karena cukup mudah untuk mendapatkan pembagian floating-point jika Anda membutuhkannya (gunakan konstanta floating-point untuk satu atau kedua operan, atau melemparkan satu atau kedua operan ke tipe floating-point), tampaknya tidak tidak dianggap penting.

Dalam versi C manual 1974 (itu 4 tahun sebelum penerbitan edisi pertama K&R), Ritchie bahkan tidak menyebutkan kemungkinan kebingungan:

Biner / operator menunjukkan pembagian. Jenis pertimbangan yang sama seperti untuk multiplikasi berlaku

yang mengatakan bahwa jika kedua operan bertipe intatau char, hasilnya bertipe int.

Ya, ini merupakan sumber kebingungan bagi sebagian programmer C, terutama pemula - tetapi C tidak terkenal karena sangat ramah-pemula.

Keith Thompson
sumber
5
Pascal. Mendapatkan detail tepat sebelum C salah. ™
Mason Wheeler
Dan kemudian Algol merupakan peningkatan dari penerusnya (dalam jumlah yang C dan Pascal berdiri).
Pemrogram
Pascal - mendapatkan rincian dengan benar (memberi atau menerima faktor 10)
Martin Beckett
1
Saya awalnya menulis 1.666666..., yang jelas salah. Alasan lumpuh saya adalah bahwa program tes Pascal yang saya tulis dicetak1.6666666666666667E-0001
Keith Thompson
16

Sebenarnya perilaku ini diubah dalam Python 3 dan sekarang berperilaku seperti yang Anda harapkan ( //sekarang digunakan untuk pembagian integer).

sepp2k
sumber
Terima kasih. Adakah bahasa pemrograman lain yang ada dalam pikiran Anda? Keluarga dasar mungkin?
Pouya
1
@Pouya: Perilaku ini standar untuk keluarga Pascal. /selalu menghasilkan nilai floating-point, dan operator terpisah ( div) digunakan untuk pembagian integer.
Mason Wheeler
13

Di luar bahasa yang menonjol, JavaScript. 1.0 / 6.0 = 1/6 = 0.16666666666666666.

Saya tidak melihat ini mengejutkan. Sebagai aturan praktis, jika suatu bahasa membedakan antara tipe angka integer dan floating point, membagi dua integer akan menghasilkan integer terpotong alih-alih float. Jika tidak, kemungkinan besar akan default ke operasi floating point. Ini harus menjadi perilaku yang diharapkan pada bagian programmer.

Hanya perlu diingat bahwa ada hal-hal tambahan yang juga bisa berperan di sini, seperti operator divisi integer yang telah disebutkan sebelumnya atau tipe casting implisit.

scrwtp
sumber
6
Ini bukan "aturan praktis". Ini adalah aturan C, dan beberapa bahasa yang secara buta menyalin kesalahan C.
Mason Wheeler
4
@MasonWheeler: Apakah FORTRAN "secara buta menyalin kesalahan C"? Saya pribadi percaya bahwa bahasa yang dirancang dengan baik harus menggunakan operator terpisah untuk pembagian terpotong versus perkiraan pembagian jumlah bilangan bulat (dan juga, btw, untuk nilai dan kesetaraan referensial), tetapi keputusan desain pada zaman FORTRAN mungkin masuk akal. Itu tidak berarti setiap bahasa harus melakukan hal-hal seperti FORTRAN di tahun 1950-an.
supercat
3
Bahasa tingkat bawah perlu membuat perbedaan ini. Bahasa tingkat tinggi / dinamis seringkali lebih baik tanpanya. Ini adalah trade-off desain. Saya menghargai hanya memiliki satu konstruktor / tipe Number bodoh besar di JS, tapi saya membayangkan saya akan merasa JS kurang ketika mencoba untuk menulis mesin 3D kinerja tinggi tanpa kontrol tipe yang lebih ketat. JS mungkin memiliki utilitas yang tumpang tindih dengan bahasa lain, tetapi saya tidak berpikir ada orang yang akan menganggapnya sebagai kebohongan untuk menulis hal-hal yang mirip dengan kinerja tinggi yang lebih dekat dengan chrome.
Erik Reppen
2
Matematika di luar pemrograman mempertimbangkan aturan integer-only untuk pembagian.
Erik Reppen
5
@MasonWheeler: Pemrograman bukanlah matematika murni. Secara matematis, 1/6 adalah bilangan rasional dan tidak dapat secara tepat diwakili oleh bilangan floating point biner. Satu-satunya representasi yang tepat adalah sebagai rasio dengan penyebut enam kali pembilang.
kevin cline
7

Ada banyak bahasa di mana ((1/6)*6)hasil dalam 1, bukan dalam 0. Misalnya, PL / SQL, banyak dialek BASIC, Lua.

Secara tidak sengaja, di semua bahasa tersebut hasil 1/6 dalam 0,166666667, atau 0,1666666666666767 atau sesuatu yang serupa. Saya memilih varian ((1/6) * 6) == 1 untuk menghilangkan perbedaan kecil itu.

pengguna281377
sumber
7
Bukan itu pertanyaannya.
Roc Martí
20
Secara tidak sengaja, di semua bahasa tersebut hasil 1/6 dalam 0,166666667, atau 0,1666666666666767 atau sesuatu yang serupa. Saya memilih ((1/6)*6)==1varian untuk menghilangkan perbedaan kecil itu, tetapi sepertinya saya melebih-lebihkan kemampuan matematika beberapa orang.
user281377
1
@ RocMartí ya, itu benar-benar ...
MattDavey
1
Saya akan terkejut melihat (1.0 / 6.0) * 6 persis sama dengan 1! Pembulatan hasil (1.0 / 6.0) akan menyebabkan perbedaan kecil. (Meskipun akan ada beberapa bahasa yang default ke presisi tak terbatas)
Sjoerd
1
@ Soerd: Sebenarnya tidak terlalu mengejutkan bahwa itu tepat. Pertimbangkan dalam desimal skenario 1/11 * 11 dengan semua nilai akurat hingga lima angka signifikan. Nilai 1/11 adalah 9.0909 * 10 ^ -2. Kalikan dengan 11 dan satu akan mendapatkan 99,9999 * 10 / -2 sebelum pembulatan. Membulatkan ke lima angka signifikan dan hasilnya adalah 1,0000 * 10 ^ 0. Perhatikan bahwa kuncinya adalah bahwa mantissa 1/6 adalah "... 0101010101 ...". Jika bit terakhir dari representasi adalah "1", mengalikannya dengan enam dan pembulatan akan menghasilkan 1. Jika bit terakhir adalah nol, itu tidak akan.
supercat
3

Haskell memperlakukan 1/6 dan 1.0 / 6.0 sebagai identik 0,16666666666666666. Ini juga menjadikan 1 / 6.0 dan 1.0 / 6 sebagai nilai yang sama juga.

Ini karena tipe numerik dasar di Haskell tidak sama dengan bahasa lain. Divisi integer sejati agak ... rumit.

Insinyur Dunia
sumber
2

Ya, Perl. Satu garis

perl -e '$x=1/6;print "$x\n";'

menghasilkan output dari:

0.166666666666667

Saya percaya bahwa PHP bekerja dengan cara yang sama.

Diedit untuk menambahkan: Saya juga percaya bahwa syarat yang diperlukan (tetapi tidak cukup) 1/6 == 1.0/6.0adalah untuk bahasa yang dimaksud diketik dengan lemah.


sumber
Mengapa mengetik lemah (apa pun yang seharusnya berarti) diperlukan? Hanya mendefinisikan / untuk (juga) berarti divisi float dalam kasus kedua argumen menjadi bilangan bulat.
1
@delnan - en.wikipedia.org/wiki/Weak_typing Saya kira itu mungkin untuk memiliki bahasa yang sangat diketik di mana /secara otomatis kelebihan tergantung pada jenis argumen, tapi itu sepertinya pelanggaran terhadap Prinsip Least Astonently untuk saya ...
2
Lemah / pengetikan yang kuat tidak didefinisikan dengan baik (seperti yang disiratkan oleh wiki), harap hindari dan spesifikkan. Saya setuju dengan definisi Anda yang melarang konversi implisit, tetapi bukan polimorfisme ad-hoc? Jika demikian, pertimbangkan Haskell, yang tidak memiliki konversi implisit tetapi cukup dieksekusi dengan baik (seperti pada, bekerja 99% dari waktu dan dapat dipahami oleh manusia) polimorfisme numerik. Dan mengapa ini mencengangkan? Akan jauh lebih mencengangkan (bukan untuk mengatakan menjengkelkan) bagi saya jika saya harus menambahkan sejumlah titik untuk setiap contoh dari setiap operator, tergantung pada presisi tepat yang saya inginkan.
2
@JackManey Saya pikir untuk sebagian besar pendatang baru itu jauh lebih mengejutkan bahwa 1/2 harus sama dengan 0 daripada jika membagi dua hasil bilangan bulat menjadi dua. Setelah semua bilangan bulat tidak ditutup di bawah pembagian dalam matematika juga. Juga seperti yang ditunjukkan oleh delnan, Haskell adalah contoh dari bahasa yang sangat diketik di mana / pada dua bilangan bulat, tidak menghasilkan bilangan bulat. Dan Python 3 adalah hal lain.
sepp2k
1
Bahasa Haxe diketik dengan kuat (meskipun disimpulkan), namun tidak memiliki pembagian bilangan bulat, hanya float. Jadi begitulah.
K.Steff
2

Dalam mencicit Smalltalk /pada bilangan bulat menciptakan objek pecahan. Jadi sementara ini tidak sama dengan divisi float, masih (1/6)*6mengembalikan 1.

Cephalopod
sumber
Dalam semua turunan Smalltalk-80 (yaitu, hampir semua Smalltalks). Amber adalah salah satu pengecualian kontemporer (yang dapat dimengerti, dikompilasi dengan JavaScript).
herby
2

Ya, saya baru saja memeriksa TI-99 / 4A saya yang dibangun di TI BASIC . Karena memperlakukan semua ekspresi numerik sebagai titik mengambang, operasi divisi juga merupakan titik mengambang.

 TI BASIC READY
>PRINT 1/6
  .1666666667

>
Jesse C. Slicer
sumber
2

VB ( VB.Net , VB6 , VBA ...)

Operator divisi integer adalah \

MarkJ
sumber
2

MATLAB. Numeric literals secara standar digandakan.

>> 1/6
ans =
    0.1667
Dima
sumber
2

Clojure memang menggunakan pecahan secara default. Ini tidak sama dengan 1.0 / 6.0, tetapi Anda dapat mengubahnya dengan floatatau doubleketika Anda membutuhkannya.

user=> (/ 1 6)
1/6
user=> (* (/ 1 6) 2)
1/3
user=> (pos? (/ 1 6)) ; Is 1/6 > 0?
true
user=> (float (/ 1 6))
0.16666667
defhlt
sumber
1

Anehnya, tampaknya berfungsi dengan baik di Windows PowerShell (versi 3) .

PS C:\> 1.0 / 6.0
0.166666666666667

PS C:\> 1/6
0.166666666666667

Tampaknya juga berfungsi di Python 3 seperti yang disebutkan sepp2k. Dua bahasa lain yang saya sudah tersedia di REPL, Scala dan Ruby, keduanya melakukan pembagian integer dan menghasilkan 0.

KChaloux
sumber
0

Bahasa Rexx selalu menghasilkan jawaban yang benar secara hitung. Sebagai contoh: 5/2 = 2.5. Rexx adalah bahasa yang bagus yang belum cukup dimanfaatkan. Secara teori, ketika kompiler tidak dapat menentukan apa yang Anda inginkan, lebih baik melakukan matematika yang benar, namun, ini mungkin tidak efisien. Rexx juga menyediakan operator //.

Tidak mungkin
sumber