Sandera COBOL dan Matematika. Bagian 1

Mari kita hadapi itu: tidak ada yang suka angka pecahan - bahkan komputer.

Ketika datang ke bahasa pemrograman COBOL, pertanyaan pertama yang muncul di kepala semua orang selalu terlihat seperti ini: "Mengapa umat manusia masih menggunakan bahasa ini di banyak bidang penting?" Bank masih menggunakan COBOL. Sekitar 7% dari PDB AS bergantung pada COBOL dalam memproses pembayaran dari CMS . Layanan Pendapatan Internal Amerika Serikat (IRS), seperti yang diketahui semua orang, masih menggunakan COBOL. Bahasa ini juga digunakan dalam penerbangan ( dari sini saya belajar satu hal yang menarik tentang topik ini: nomor reservasi pada tiket pesawat digunakan untuk menjadi pointer biasa). Kita dapat mengatakan bahwa banyak organisasi yang sangat serius, apakah itu sektor swasta atau publik, masih menggunakan COBOL.



β†’ Bagian kedua

Penulis bahan, bagian pertama dari terjemahan yang kami terbitkan hari ini, akan menemukan jawaban untuk pertanyaan mengapa COBOL, bahasa yang muncul pada tahun 1959, masih begitu luas.

Mengapa COBOL masih hidup?


Jawaban tradisional untuk pertanyaan ini sangat sinis. Organisasi adalah kemalasan, ketidakmampuan dan kebodohan. Mereka mengejar murahnya dan tidak cenderung berinvestasi dalam menulis ulang sistem perangkat lunak mereka pada sesuatu yang modern. Secara umum, dapat diasumsikan bahwa alasan bahwa pekerjaan sejumlah besar organisasi tergantung pada COBOL adalah kombinasi dari kelembaman dan kepicikan. Dan dalam hal ini, tentu saja, ada beberapa kebenaran. Menulis ulang sejumlah besar kode membingungkan adalah tugas besar. Itu mahal. Ini rumit. Dan jika perangkat lunak yang ada tampaknya berfungsi dengan baik, organisasi tidak akan memiliki motivasi yang kuat untuk berinvestasi dalam proyek untuk memperbarui perangkat lunak ini.

Semua ini begitu. Tetapi ketika saya bekerja di IRS, para veteran COBOL berbicara tentang bagaimana mereka mencoba menulis ulang kode di Jawa dan ternyata Java tidak dapat melakukan perhitungan dengan benar.

Kedengarannya sangat aneh bagi saya. Sangat aneh sehingga saya langsung berpikir: "Tuhan, itu artinya IRS telah menyelesaikan pembayaran pajak untuk semua orang selama 50 tahun !!!" Saya tidak percaya COBOL dapat berkeliling Jawa dalam hal perhitungan matematis yang diperlukan oleh IRS. Pada akhirnya - mereka tidak meluncurkan orang ke luar angkasa.

Salah satu efek samping yang menarik dari belajar COBOL di musim panas adalah saya mulai memahami yang berikut. Intinya bukan bahwa Java tidak dapat melakukan perhitungan matematika dengan benar. Intinya adalah bagaimana tepatnya Java membuat perhitungan benar. Dan ketika Anda memahami bagaimana perhitungan dilakukan di Jawa, dan bagaimana hal yang sama dilakukan dalam COBOL, Anda mulai memahami mengapa banyak organisasi merasa sangat sulit untuk menyingkirkan warisan komputer mereka.

"Aku" apa yang harus diberi titik?


Saya akan pindah sedikit dari cerita COBOL dan berbicara tentang bagaimana komputer menyimpan informasi sebelum representasi biner data menjadi standar de facto (tetapi materi tentang cara menggunakan antarmuka z / OS; ini adalah sesuatu yang istimewa). Saya pikir dalam mempertimbangkan masalah kita, akan berguna untuk menyimpang dari tema utama ke arah ini. Dalam materi yang disebutkan di atas, saya berbicara tentang berbagai cara menggunakan saklar biner untuk menyimpan angka dalam sistem biner, ternary, desimal, untuk menyimpan angka negatif - dan seterusnya. Satu-satunya hal yang saya tidak cukup perhatikan adalah bagaimana angka desimal disimpan.

Jika Anda mendesain komputer biner Anda sendiri, maka Anda bisa mulai dengan memutuskan bahwa Anda akan menggunakan sistem angka biner. Bit di sebelah kiri titik mewakili bilangan bulat - 1, 2, 4, 8. Dan bit di sebelah kanan - angka pecahan - 1/2, 1/4, 1/8 ...


2,75 dalam representasi biner

Masalahnya di sini adalah memahami bagaimana menyimpan titik desimal itu sendiri (sebenarnya - saya harus mengatakan "titik biner" - karena, setelah semua, kita berbicara tentang angka biner). Ini bukan semacam "alkimia komputer", jadi Anda bisa menebak apa yang saya bicarakan tentang angka titik mengambang dan angka titik tetap. Dalam angka floating point, titik biner dapat ditempatkan di mana saja (yaitu, itu bisa "mengambang"). Posisi titik disimpan sebagai eksponen. Kemampuan untuk memindahkan suatu titik memungkinkan untuk menyimpan rentang angka yang lebih luas daripada yang tersedia tanpa adanya kesempatan seperti itu. Titik desimal dapat dipindahkan ke bagian paling belakang angka dan pilih semua bit untuk menyimpan nilai integer, mewakili angka yang sangat besar. Intinya dapat digeser ke depan angka dan menyatakan nilai yang sangat kecil. Tetapi kebebasan ini datang pada harga keakuratan. Mari kita lihat lagi representasi biner 2,75 dari contoh sebelumnya. Transisi dari empat ke delapan jauh lebih dari transisi dari seperempat ke delapan. Mungkin lebih mudah bagi kita untuk membayangkan ini jika kita menulis ulang contoh seperti yang ditunjukkan di bawah ini.


Saya memilih jarak antara angka dengan mata - hanya untuk menunjukkan ide saya

Perbedaan antara angka-angka itu mudah dihitung sendiri. Misalnya, jarak antara 1/16 dan 1/32 adalah 0,03125, tetapi jarak antara 1/2 dan 1/4 sudah 0,25.

Mengapa ini penting? Dalam kasus representasi bilangan bulat biner, ini tidak masalah - jarak antara angka-angka yang berdekatan dari catatan biner dapat dengan mudah dikompensasi dengan mengisinya dengan kombinasi bit yang sesuai dan tanpa kehilangan akurasi. Tetapi dalam kasus representasi bilangan pecahan, itu tidak begitu sederhana. Jika Anda mencoba "mengisi" "lubang" di antara angka-angka yang berdekatan - sesuatu dapat "jatuh" (dan benar-benar jatuh) ke dalam lubang ini. Ini mengarah pada fakta bahwa dalam format biner tidak mungkin untuk mendapatkan representasi angka pecahan yang tepat.

Ini diilustrasikan oleh contoh klasik angka 0,1 (sepersepuluh). Bagaimana cara merepresentasikan angka ini dalam format biner? 2 -1 adalah 1/2, atau 0,5. Ini terlalu banyak. 1/16 adalah 0,0635. Ini terlalu sedikit. 1/16 + 1/32 sudah lebih dekat (0,09375), tetapi 1/16 + 1/32 + 1/64 sudah lebih dari yang kita butuhkan (0,109375).

Jika Anda yakin bahwa alasan ini dapat dilanjutkan tanpa batas waktu - maka Anda benar - apa adanya .

Di sini Anda dapat berkata kepada diri sendiri: "Mengapa kita tidak menyimpan 0,1 saja dengan cara yang sama seperti kita menyimpan nomor 1? Kami dapat menyimpan angka 1 tanpa masalah - jadi mari kita hapus titik desimal dan simpan angka apa pun dengan cara yang sama seperti kita menyimpan bilangan bulat. "

Ini adalah solusi yang sangat baik untuk masalah ini, kecuali bahwa itu memerlukan memperbaiki titik biner / desimal di beberapa tempat yang telah ditentukan. Kalau tidak, angka 10.00001 dan 100000.1 akan terlihat sama persis. Tetapi jika titik tersebut diperbaiki sehingga, katakanlah, 2 digit dialokasikan ke bagian fraksional dari angka, maka kita dapat membulatkan 10.00001 menjadi 10.00, dan 100000.1 akan berubah menjadi 100000.10.

Kami baru saja "menemukan" angka titik tetap.

Dengan representasi nilai yang berbeda menggunakan angka titik tetap, kami baru saja menemukannya. Itu mudah dilakukan. Apakah mungkin, menggunakan nomor-nomor tetap, untuk memfasilitasi solusi dari beberapa masalah lain? Mari kita ingat di sini tentang teman baik kita - tentang angka desimal biner (Binary Coded Decimal, BCD). Ngomong-ngomong, untuk memberi tahu Anda, angka-angka ini digunakan di sebagian besar kalkulator ilmiah dan grafik. Dari perangkat ini, yang cukup jelas, mereka mengharapkan hasil perhitungan yang benar.


TI-84 Plus Calculator

Rasio pengulangan Muller dan Python


Angka titik tetap dianggap lebih akurat karena fakta bahwa "lubang" di antara angka-angka itu konstan, dan karena pembulatan terjadi hanya ketika Anda perlu membayangkan angka yang tidak ada cukup ruang. Tetapi ketika menggunakan angka floating point, kita bisa mewakili angka yang sangat besar dan sangat kecil menggunakan jumlah memori yang sama. Benar, dengan bantuan mereka tidak mungkin untuk mewakili semua angka dalam rentang yang dapat diakses secara akurat dan kami terpaksa menggunakan pembulatan untuk mengisi "lubang".

COBOL dibuat sebagai bahasa di mana, secara default, nomor titik tetap digunakan. Tetapi apakah ini berarti bahwa COBOL lebih baik daripada bahasa modern untuk melakukan perhitungan matematika? Jika kita menangkap masalah seperti hasil penghitungan nilai 0,1 + 0,2, maka sepertinya pertanyaan sebelumnya harus dijawab "ya". Tapi itu akan membosankan. Jadi mari kita lanjutkan.

Kita akan bereksperimen dengan COBOL menggunakan apa yang disebut hubungan Perulangan Muller. Jean-Michel Muller adalah seorang ilmuwan Perancis yang mungkin telah membuat penemuan ilmiah utama di bidang teknologi informasi. Dia menemukan cara untuk memutus operasi yang benar dari komputer menggunakan matematika. Saya yakin bahwa ia akan mengatakan bahwa ia mempelajari masalah keandalan dan akurasi, tetapi tidak dan tidak lagi: ia menciptakan masalah matematika yang β€œmenghancurkan” komputer. Salah satu tugas ini adalah rumus perulangannya. Ini terlihat seperti ini:


Contoh ini diambil dari sini.

Formula itu sepertinya tidak menakutkan sama sekali. Benar? Tugas ini sesuai untuk tujuan kami karena alasan berikut:

  • Hanya aturan matematika sederhana yang digunakan di sini - tidak ada rumus rumit atau ide yang mendalam.
  • Kita mulai dengan angka yang memiliki dua digit setelah titik desimal. Sebagai hasilnya, mudah untuk membayangkan bahwa kita bekerja dengan nilai-nilai yang mewakili jumlah uang tertentu.
  • Kesalahan yang dihasilkan dari perhitungan bukanlah kesalahan pembulatan kecil. Ini adalah penyimpangan dari hasil yang benar oleh seluruh urutan besarnya.

Berikut ini adalah skrip Python kecil yang menghitung hasil relasi pengulangan Mueller menggunakan angka floating-point dan fixed-point:

from decimal import Decimal def rec(y, z):  return 108 - ((815-1500/z)/y)  def floatpt(N):  x = [4, 4.25]  for i in range(2, N+1):   x.append(rec(x[i-1], x[i-2]))  return x  def fixedpt(N):  x = [Decimal(4), Decimal(17)/Decimal(4)]  for i in range(2, N+1):   x.append(rec(x[i-1], x[i-2]))  return x N = 20 flt = floatpt(N) fxd = fixedpt(N) for i in range(N):  print str(i) + ' | '+str(flt[i])+' | '+str(fxd[i]) 

Inilah hasil skrip ini:

 i | floating pt  | fixed pt -- | -------------- | --------------------------- 0 | 4       | 4 1 | 4.25      | 4.25 2 | 4.47058823529 | 4.4705882352941176470588235 3 | 4.64473684211 | 4.6447368421052631578947362 4 | 4.77053824363 | 4.7705382436260623229461618 5 | 4.85570071257 | 4.8557007125890736342039857 6 | 4.91084749866 | 4.9108474990827932004342938 7 | 4.94553739553 | 4.9455374041239167246519529 8 | 4.96696240804 | 4.9669625817627005962571288 9 | 4.98004220429 | 4.9800457013556311118526582 10 | 4.9879092328  | 4.9879794484783912679439415 11 | 4.99136264131 | 4.9927702880620482067468253 12 | 4.96745509555 | 4.9956558915062356478184985 13 | 4.42969049831 | 4.9973912683733697540253088 14 | -7.81723657846 | 4.9984339437852482376781601 15 | 168.939167671 | 4.9990600687785413938424188 16 | 102.039963152 | 4.9994358732880376990501184 17 | 100.099947516 | 4.9996602467866575821700634 18 | 100.004992041 | 4.9997713526716167817979714 19 | 100.000249579 | 4.9993671517118171375788238 

Hingga iterasi 12, kesalahan pembulatan terlihat lebih atau kurang signifikan, tetapi kemudian neraka yang sebenarnya dimulai. Perhitungan floating-point berkumpul untuk angka yang dua puluh kali lebih besar dari apa yang dihasilkan dari perhitungan titik tetap.

Mungkin Anda berpikir tidak mungkin ada orang yang melakukan perhitungan rekursif skala besar. Tetapi justru inilah yang menyebabkan bencana tahun 1991, yang menyebabkan kematian 28 orang, ketika sistem kendali rudal Patriot secara salah menghitung waktu. Ternyata perhitungan floating point secara tidak sengaja banyak merugikan. Inilah beberapa hal hebat yang mungkin komputasi kinerja tinggi hanyalah cara yang lebih cepat untuk mendapatkan jawaban yang salah. Baca karya ini jika Anda ingin mendapatkan informasi lebih lanjut tentang masalah yang dibahas di sini dan lihat lebih banyak contoh.

Masalahnya adalah jumlah RAM yang dimiliki komputer tidak terbatas. Oleh karena itu, mustahil untuk menyimpan jumlah desimal (atau biner) yang tak terbatas. Perhitungan fixed-point bisa lebih akurat daripada perhitungan floating-point jika ada keyakinan bahwa kecil kemungkinan akan lebih banyak angka yang dibutuhkan setelah poin daripada format yang digunakan. Jika nomor tidak sesuai dengan format ini, itu akan dibulatkan. Perlu dicatat bahwa baik perhitungan titik tetap maupun perhitungan titik mengambang tidak terlindungi dari masalah yang ditunjukkan oleh hubungan berulang Mueller. Baik itu dan orang lain sebagai hasilnya memberikan hasil yang salah. Pertanyaannya adalah kapan ini terjadi. Jika Anda menambah jumlah iterasi dalam skrip Python, misalnya, dari 20 menjadi 22, maka angka terakhir yang diperoleh dalam perhitungan dengan titik tetap adalah 0,728107. 23 iterasi? -501.7081261. 24? 105.8598187.

Dalam bahasa yang berbeda, masalah ini memanifestasikan dirinya dengan cara yang berbeda. Beberapa, seperti COBOL, memungkinkan Anda untuk bekerja dengan angka yang parameternya diatur dengan ketat. Dan dengan Python, misalnya, ada nilai default yang dapat dikonfigurasi jika komputer memiliki cukup memori. Jika kita menambahkan baris getcontext().prec = 60 ke program kami, memberi tahu modul desimal Python bahwa ia akan menggunakan 60 posisi setelah periode, dan bukan 28, seperti yang dilakukan secara default, program akan dapat melakukan 40 iterasi relasi perulangan tanpa kesalahan Mueller.

Dilanjutkan ...

Pembaca yang budiman! Sudahkah Anda mengalami masalah serius yang timbul dari sifat perhitungan floating-point?

Source: https://habr.com/ru/post/id467251/


All Articles