الرهائن كوبول والرياضيات. الجزء 1

دعونا نواجه الأمر: لا أحد يحب الأرقام الكسرية - حتى أجهزة الكمبيوتر.

عندما يتعلق الأمر بلغة البرمجة COBOL ، فإن السؤال الأول الذي ينبثق في رأس الجميع يبدو دائمًا كما يلي: "لماذا لا تزال البشرية تستخدم هذه اللغة في العديد من المجالات الحيوية؟" البنوك لا تزال تستخدم كوبول. يعتمد حوالي 7٪ من الناتج المحلي الإجمالي الأمريكي على COBOL في معالجة المدفوعات من CMS . لا تزال خدمة الإيرادات الداخلية للولايات المتحدة (IRS) ، كما يعلم الجميع ، تستخدم كوبول. تُستخدم هذه اللغة أيضًا في مجال الطيران ( من هنا تعلمت شيئًا واحدًا مثيرًا للاهتمام حول هذا الموضوع: رقم الحجز على تذاكر الطيران كان مؤشرًا معتادًا). يمكن القول أن العديد من المنظمات الخطيرة للغاية ، سواء أكانت قطاعًا خاصًا أم عامًا ، لا تزال تستخدم COBOL.



الجزء الثاني

سيجد مؤلف المادة ، وهو الجزء الأول من الترجمة التي ننشرها اليوم ، إجابة على سؤال لماذا لا يزال كوبول ، اللغة التي ظهرت في عام 1959 ، منتشرة على نطاق واسع.

لماذا لا يزال كوبول على قيد الحياة؟


الجواب التقليدي على هذا السؤال هو ساخر للغاية. المنظمات هي الكسل وعدم الكفاءة والغباء. إنهم يطاردون الرخص ولا يميلون إلى الاستثمار في إعادة كتابة أنظمة البرمجيات الخاصة بهم على شيء حديث. بشكل عام ، يمكن افتراض أن السبب وراء اعتماد عمل هذا العدد الكبير من المنظمات على COBOL هو مزيج من الجمود وقصر النظر. وفي هذا ، بالطبع ، هناك بعض الحقيقة. إعادة كتابة كميات كبيرة من التعليمات البرمجية مربكة مهمة هائلة. أنها مكلفة. هذا معقد. وإذا بدا أن البرنامج الحالي يعمل بشكل جيد ، فلن يكون لدى المؤسسة دافع قوي بشكل خاص للاستثمار في مشروع لتحديث هذا البرنامج.

كل هذا صحيح. ولكن عندما عملت في مصلحة الضرائب ، تحدث قدامى المحاربين في كوبول عن كيفية محاولة إعادة كتابة الكود في جافا واتضح أن جافا لم يتمكن من إجراء العمليات الحسابية بشكل صحيح.

بدا غريبا للغاية بالنسبة لي. إنه لأمر غريب أن أكون قد فكرت على الفور في حالة من الفزع: "يا رب ، هذا يعني أن مصلحة الضرائب كانت تقطع مدفوعات الضرائب للجميع منذ 50 عامًا!" لم أستطع أن أصدق أن COBOL قادر على التجول في جافا من حيث الحسابات الرياضية التي يحتاجها مصلحة الضرائب. في النهاية - لم يطلقوا الناس في الفضاء.

أحد الآثار الجانبية المثيرة للاهتمام لتعلم كوبول في الصيف هو أنني بدأت أفهم ما يلي. النقطة ليست أن Java لا يمكنها إجراء العمليات الحسابية بشكل صحيح. النقطة هي بالضبط كيف تجعل جافا الحسابات صحيحة. وعندما تفهم كيفية إجراء العمليات الحسابية في Java ، وكيف يتم إجراء نفس الشيء في COBOL ، فإنك تبدأ في فهم السبب الذي يجعل العديد من المؤسسات تجد صعوبة بالغة في التخلص من إرث الكمبيوتر الخاص بها.

ما "أنا" يجب أن تنتشر؟


سأبتعد قليلاً عن قصة COBOL وأتحدث عن كيفية تخزين أجهزة الكمبيوتر للمعلومات قبل أن يصبح التمثيل الثنائي للبيانات هو المعيار الفعلي (لكن المواد المتعلقة بكيفية استخدام واجهة z / OS ؛ هذا شيء خاص). أعتقد أنه عند النظر في قضيتنا ، سيكون من المفيد الخروج عن الموضوع الرئيسي في هذا الاتجاه. في المادة المذكورة أعلاه ، تحدثت عن طرق مختلفة لاستخدام المحولات الثنائية لتخزين الأرقام في الأنظمة الثنائية ، الثلاثية ، العشرية ، لتخزين الأرقام السالبة - وهكذا. الشيء الوحيد الذي لم أكن أهتم به هو كيفية تخزين الأرقام العشرية.

إذا كنت قد صممت جهاز الكمبيوتر الثنائي الخاص بك ، فيمكنك البدء بتحديد استخدام نظام الأرقام الثنائية. تمثل البتات الموجودة على يسار النقطة عددًا صحيحًا - 1 ، 2 ، 4 ، 8. والبتات إلى الأعداد الصحيحة للكسور - 1/2 ، 1/4 ، 1/8 ...


2.75 في التمثيل الثنائي

المشكلة هنا هي فهم كيفية تخزين الفاصلة العشرية نفسها (في الواقع - يجب أن أقول "النقطة الثنائية" - لأننا ، بعد كل شيء ، نتحدث عن الأرقام الثنائية). هذا ليس نوعًا من "كيمياء الكمبيوتر" ، لذا يمكنك تخمين ما أتحدث عنه حول أرقام الفاصلة العائمة وأرقام النقاط الثابتة. في أرقام الفاصلة العائمة ، يمكن وضع نقطة ثنائية في أي مكان (أي ، يمكن أن "تطفو"). يتم تخزين موضع النقطة كد. تتيح القدرة على تحريك نقطة ما تخزين مجموعة أكبر من الأرقام مما هو متاح في غياب هذه الفرصة. يمكن نقل العلامة العشرية إلى آخر الرقم وتحديد كل البتات لتخزين قيم عدد صحيح ، تمثل أرقامًا كبيرة جدًا. يمكن تحويل النقطة إلى مقدمة الرقم والتعبير عن قيم صغيرة جدًا. لكن هذه الحرية تأتي بسعر الدقة. دعنا نلقي نظرة أخرى على التمثيل الثنائي 2.75 من المثال السابق. الانتقال من أربعة إلى ثمانية هو أكثر بكثير من الانتقال من ربع إلى الثامنة. قد يكون من الأسهل بالنسبة لنا تخيل هذا إذا أعدنا كتابة المثال كما هو موضح أدناه.


اخترت المسافة بين الأرقام عن طريق العين - فقط لإظهار فكرتي

الفرق بين الأرقام يسهل حسابه بنفسك. على سبيل المثال ، تبلغ المسافة بين 1/16 و 1/32 0.03125 ، لكن المسافة بين 1/2 و 1/4 هي بالفعل 0.25.

لماذا هذا مهم؟ في حالة التمثيل الثنائي للأعداد الصحيحة ، لا يهم ذلك - يمكن بسهولة تعويض المسافة بين الأرقام المجاورة للسجل الثنائي عن طريق ملء تلك المجموعات المناسبة من البتات ودون فقد الدقة. ولكن في حالة تمثيل الأرقام الكسرية ، فإنه ليس بهذه البساطة. إذا حاولت "ملء" الثقوب بين الأعداد المجاورة - يمكن أن يحدث شيء ما (ويسقط بالفعل) في هذه الثقوب. هذا يؤدي إلى حقيقة أنه في التنسيق الثنائي لا يمكن الحصول على تمثيل دقيق للأرقام الكسرية.

يتضح هذا من خلال المثال الكلاسيكي للرقم 0.1 (عُشر). كيفية تمثيل هذا الرقم في شكل ثنائي؟ 2 -1 هو 1/2 ، أو 0.5. هذا كثير جدا 1/16 هو 0.0635. هذا قليل جدا 1/16 + 1/32 أقرب بالفعل (0.09375) ، ولكن 1/16 + 1/32 + 1/64 بالفعل أكثر مما نحتاج (0.109375).

إذا كنت تعتقد أن هذا المنطق يمكن أن يستمر إلى أجل غير مسمى - فأنت محق - كما هي .

هنا يمكنك أن تقول لنفسك: "لماذا لا نوفر فقط 0.1 بنفس طريقة تخزين الرقم 1؟ يمكننا حفظ الرقم 1 دون أي مشاكل - لذلك دعونا نزيل العلامة العشرية ونخزن أي أرقام بنفس الطريقة التي نخزن بها أعداد صحيحة. "

هذا حل ممتاز لهذه المشكلة ، إلا أنه يتطلب إصلاح النقطة الثنائية / العشرية في بعض المواقع المحددة مسبقًا. خلاف ذلك ، فإن الأرقام 10.00001 و 100000.1 ستبدو كما هي بالضبط. ولكن إذا كانت النقطة ثابتة ، على سبيل المثال ، يتم تخصيص رقمين للجزء الكسري من الرقم ، فيمكننا التقريب من 10.00001 إلى 10.00 ، وسوف يتحول 100000.1 إلى 100000.10.

نحن فقط "اخترع" أرقام النقاط الثابتة.

من خلال تمثيل قيم مختلفة باستخدام أرقام النقاط الثابتة ، اكتشفنا ذلك. من السهل القيام به. هل من الممكن ، باستخدام أرقام النقاط الثابتة ، تسهيل حل بعض المشاكل الأخرى؟ دعونا نتذكر هنا عن أصدقائنا المقربين - حول الأرقام العشرية الثنائية (Binary Coded Decimal، BCD). بالمناسبة ، لإعلامك ، يتم استخدام هذه الأرقام في معظم الآلات الحاسبة العلمية والرسوم البيانية. من هذه الأجهزة ، وهو أمر واضح تمامًا ، يتوقعون النتائج الصحيحة للحسابات.


حاسبة TI-84 Plus

معدل تكرار مولر وبيثون


تُعتبر أرقام النقاط الثابتة أكثر دقة نظرًا لحقيقة أن "الثقوب" بين الأرقام ثابتة ، ولأن التقريب يحدث فقط عندما تحتاج إلى تخيل رقم لا يوجد فيه مساحة كافية. ولكن عند استخدام أرقام الفاصلة العائمة ، يمكننا تمثيل أرقام كبيرة جدًا وصغيرة جدًا باستخدام نفس مقدار الذاكرة. صحيح ، بمساعدتهم ، من المستحيل تمثيل جميع الأرقام في النطاق المتاح بدقة ، ونحن مضطرون إلى اللجوء إلى التقريب لملء "الثقوب".

تم إنشاء COBOL كلغة يتم فيها استخدام أرقام النقطة الثابتة افتراضيًا. ولكن هل هذا يعني أن كوبول أفضل من اللغات الحديثة لأداء الحسابات الرياضية؟ إذا تابعنا مشكلة مثل نتيجة حساب القيمة 0.1 + 0.2 ، فقد يبدو أنه يجب الإجابة على السؤال السابق "نعم". لكنها ستكون مملة. لذلك دعنا ننتقل.

سنقوم بتجربة COBOL باستخدام ما يسمى بعلاقة تكرار Muller. جان ميشيل مولر هو عالم فرنسي قد يكون اكتشافًا علميًا رئيسيًا في مجال تكنولوجيا المعلومات. وجد طريقة لكسر العملية الصحيحة لأجهزة الكمبيوتر باستخدام الرياضيات. أنا متأكد من أنه سيقول أنه يدرس مشاكل الموثوقية والدقة ، لكن لا ولا مرة أخرى: إنه يخلق مشاكل رياضية "تكسر" أجهزة الكمبيوتر. واحدة من هذه المهام هي صيغة تكرارها. يبدو مثل هذا:


هذا المثال مأخوذ من هنا.

الصيغة لا تبدو مخيفة على الإطلاق. حقا؟ هذه المهمة مناسبة لأغراضنا للأسباب التالية:

  • يتم استخدام قواعد بسيطة فقط من الرياضيات هنا - لا توجد صيغ معقدة أو أفكار عميقة.
  • نبدأ برقم يتكون من رقمين بعد العلامة العشرية. نتيجة لذلك ، من السهل أن نتخيل أننا نعمل بقيم تمثل مبالغ معينة من المال.
  • الخطأ الذي ينتج عن العمليات الحسابية ليس خطأ تقريب صغير. هذا هو الانحراف عن النتيجة الصحيحة بأوامر كاملة الحجم.

فيما يلي نص بيثون صغير يحسب نتائج علاقة تكرار مولر باستخدام أرقام الفاصلة العائمة والنقطة الثابتة:

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]) 

هذه هي نتيجة هذا البرنامج النصي:

 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 

حتى التكرار 12 ، يبدو خطأ التقريب غير مهم إلى حد ما ، ولكن بعد ذلك يبدأ الجحيم الحقيقي. تتقارب حسابات الفاصلة العائمة مع رقم أكبر بعشرين مرة مما ينتج عن حسابات النقطة الثابتة.

ربما تعتقد أنه من غير المحتمل أن يقوم أي شخص بإجراء مثل هذه الحسابات العودية واسعة النطاق. ولكن هذا هو بالضبط ما تسبب في كارثة عام 1991 ، والتي أدت إلى وفاة 28 شخصًا ، عندما قام نظام التحكم في الصواريخ باتريوت بحساب الوقت بشكل غير صحيح. اتضح أن حسابات النقطة العائمة تسببت في الكثير من الضرر. إليك بعض الأشياء الرائعة التي ربما تكون الحوسبة عالية الأداء طريقة أسرع للحصول على الإجابات الخاطئة. اقرأ هذا العمل إذا كنت ترغب في الحصول على مزيد من المعلومات حول المشكلة التي تمت مناقشتها هنا ورؤية المزيد من الأمثلة.

المشكلة هي أن كمية ذاكرة الوصول العشوائي الموجودة في أجهزة الكمبيوتر ليست غير نهائية. لذلك ، من المستحيل تخزين عدد لا حصر له من المواضع العشرية (أو الثنائية). يمكن أن تكون حسابات النقطة الثابتة أكثر دقة من حسابات الفاصلة العائمة إذا كان هناك ثقة بأن هناك حاجة إلى عدد أكبر من الأرقام بعد هذه النقطة أقل من التنسيق المستخدم. إذا كان الرقم غير مناسب لهذا التنسيق ، فسيتم تقريبه. تجدر الإشارة إلى أنه لا يتم حماية حسابات النقطة الثابتة أو حسابات الفاصلة العائمة من المشكلة التي توضحها علاقة تكرار ميلر. كل ذلك والآخرين نتيجة تعطي نتائج غير صحيحة. السؤال هو عندما يحدث هذا. إذا قمت بزيادة عدد التكرارات في برنامج Python ، على سبيل المثال ، من 20 إلى 22 ، فسيكون الرقم النهائي الذي تم الحصول عليه في العمليات الحسابية بنقطة ثابتة هو 0.728107. 23 التكرار؟ -501،7081261. 24؟ 105.8598187.

في لغات مختلفة ، تتجلى هذه المشكلة بطرق مختلفة. يسمح لك البعض ، مثل COBOL ، بالعمل مع أرقام يتم ضبط معلماتها بإحكام. وفي Python ، على سبيل المثال ، هناك قيم افتراضية يمكن تكوينها إذا كان لدى الكمبيوتر ذاكرة كافية. إذا أضفنا السطر getcontext().prec = 60 إلى برنامجنا ، مع إخبار الوحدة النمطية العشرية لـ Python بأنها ستستخدم 60 وظيفة بعد الفترة ، وليس 28 ، كما يتم بشكل افتراضي ، فسيكون البرنامج قادراً على تنفيذ 40 تكرار لعلاقة التكرار دون أخطاء مولر.

أن تستمر ...

أعزائي القراء! هل واجهت مشاكل خطيرة ناشئة عن طبيعة حسابات الفاصلة العائمة؟

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


All Articles