سؤال

أنا أدرس C ، وظهرت فكرة أرقام الحراسة وأخطاء التقريب. هل يحتاج ممارسو لغات البرمجة النصية (أفكر في بيثون وبيرل هنا) إلى القلق بشأن هذه الأشياء؟ ماذا لو كانوا يقومون برمجة علمية؟

هل كانت مفيدة؟

المحلول

أود أن أختلف مع لوتز ... بينما توجد أخطاء التقريب التي ذكرتها في بيثون/بيرل/روبي ، لديهم لا شيء مطلقا تتعلق باللغات التي يتم تنفيذها في C. المشكلة أعمق من ذلك.

يتم تمثيل أرقام النقطة العائمة ، مثل جميع البيانات ، في ثنائي على أجهزة الكمبيوتر الحديثة. مثلما توجد أرقام ذات تمثيلات عشرية دورية (على سبيل المثال ، 1/3 = 0.333333 ...) ، هناك أيضًا أرقام ذات تمثيلات ثنائية دورية (على سبيل المثال ، 1/10 = 0.0001100110011 ...). نظرًا لأنه لا يمكن تمثيل هذه الأرقام بالضبط في (كمية محدودة) من ذاكرة الكمبيوتر ، فإن أي حسابات تتضمنها ستقدم خطأ.

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

نصائح أخرى

هذا يعتمد. doubleتتصرف نفس الشيء في كل مكان ، لذلك إذا قمت بالرياضيات مع الزوجي ، فستواجه نفس المشكلة مع أي لغة. إذا كنت تستخدم نوع الدقة التعسفية الأصلية ، فلا ، فهذه ليست مشكلة. يعتبر:

use Math::BigFloat;
my $big   = Math::BigFloat->new("1_000_000_000_000_000_000_000");
my $small = Math::BigFloat->new("0.000000000000000000000000001"); 
print $big + $small;

(أو ، إذا كنت تريد حقًا إخفاء ما يحدث:

use bignum;
print 1_000_000_000_000_000_000_000 + 0.000000000000000000000000001

)

كما هو متوقع ، هذا العائدات:

1000000000000000000000.000000000000000000000000001

أيضا كما هو متوقع ، لم يتم ذلك في تعليمات وحدة المعالجة المركزية واحدة.

هناك عدة أنواع من الأرقام غير السفلية في بيثون:

x = 1 / 2

سوف يعطيك تعويم قياسي. نوعه float, ، هو نفسه كما هو الحال في C ، يتم التعامل معه من قبل الأجهزة ، ولديه نفس المشكلات مثل أيها الآخر float فى العالم.

ومع ذلك ، هناك أيضا نوع كسري:

from fractions import Fraction

x = Fraction(1, 2)

التي لديها الحساب الدقيق مع الأرقام العقلانية.

في الحالة التي ترغب في القيام بها ، ولكنك غير راضٍ عن عدد الأرقام ذات المغزى على جهاز الكمبيوتر الخاص بك ، أو حقيقة أنه يمكن أن يكون مختلفًا عبر المنصات ، نوع عشري هل صديقك:

from decimal import Decimal

x = Decimal('0.5')

ستتمكن من ضبط دقتها على 100 رقم ، على سبيل المثال ، إذا كنت ترغب في ذلك. أو قم بتعيينه على 2 للتطبيقات المصرفية.

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

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

يعتمد ذلك على كيفية تمثيل أرقامك ، وليس اللغة التي تستخدمها.

على سبيل المثال ، إذا كتبت كل الكود الخاص بي في 8051 Assember ، لكنني قمت بتطبيق مكتبة أرقام عقلانية بقعة ، فليس من مشكلة. 1/3 يساوي فقط 1/3.

ومع ذلك ، إذا كنت أستخدم أحدث لغة ديناميكية Snazzy ، وتستخدم عوامات IEE754 ، فكل حدود IEEE754 تنطبق.

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

تحديث:

PDL هي مكتبة شهيرة للقيام بالحوسبة العلمية في بيرل.

منذ أن يتم تنفيذ intepreter الأساسي لكل من Cpython و Perl في C ، فإنها تتصرف مثل برنامج C.

لبيثون هناك سكيبي و نومبي للحساب العلمي.

يمكنك إجراء حسابات دقيقة متعددة مع Python ، مع الوحدات الخارجية. قسم الرياضيات متعدد الدقة في الموقع الرسمي يسرد الكثير منهم.

حسنًا ، أنت لست محصنًا من أخطاء النقطة العائمة في روبي. علي سبيل المثال:

irb(main):033:0> (2.01 * 1000).to_i
=> 2009
irb(main):034:0> ((2.01 * 1000.0) + 0.5).floor
=> 2010

عندما تقوم بالبرمجة العلمية ، يجب أن تقلق دائمًا بشأن التقريب ، بغض النظر عن لغة البرمجة أو المكتبة الرقمية التي تستخدمها.

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

لسبب ما ، تحتاج إلى تدوير هذا الجزيء. التي تنطوي sin() و cos() العمليات والضرب. المضاعفة ليست مشكلة لأن عدد الأرقام الصالحة هو ببساطة مجموع طول كلتا المعاملات. ولكن ماذا عن sin()?

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

بالتأكيد يفعلون!

مثال من بيثون 2.6:

>>> 1440.0 / 900.0
1.6000000000000001

كما يقول لوتز ، نظرًا لأن لغات البرمجة النصية غالباً ما يتم تنفيذها في C ، فإنها ترث هذه "الميزات". إن التعويض عنهم في اللغة يعني بلا شك نوعًا من المفاضلة في الأداء أو قابلية النقل.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top