سؤال

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

في الكود التالي، intersections تحصل الدالة على نقاط التقاطع:

[points(:,1), points(:,2)] = intersections(...
    obj.modifiedVGVertices(1,:), obj.modifiedVGVertices(2,:), ...
    [vertex1(1) vertex2(1)], [vertex1(2) vertex2(2)]);

النتائج:

>> points
points =
   12.0000   15.0000
   33.0000   24.0000
   33.0000   24.0000

>> vertex1
vertex1 =
    12
    15

>> vertex2    
vertex2 =
    33
    24

نقطتان (vertex1 و vertex2) يجب حذفها من النتيجة.يجب أن يتم ذلك عن طريق الأوامر التالية:

points = points((points(:,1) ~= vertex1(1)) | (points(:,2) ~= vertex1(2)), :);
points = points((points(:,1) ~= vertex2(1)) | (points(:,2) ~= vertex2(2)), :);

وبعد القيام بذلك، لدينا هذه النتيجة غير المتوقعة:

>> points
points =
   33.0000   24.0000

يجب أن تكون النتيجة مصفوفة فارغة.كما ترون، الزوج الأول (أو الثاني؟) من [33.0000 24.0000] تم القضاء عليه، ولكن ليس الثاني.

ثم تحققت من هذين التعبيرين:

>> points(1) ~= vertex2(1)
ans =
     0
>> points(2) ~= vertex2(2)
ans =
     1   % <-- It means 24.0000 is not equal to 24.0000?

ما المشكلة؟


والأكثر إثارة للدهشة أنني قمت بإنشاء برنامج نصي جديد يحتوي فقط على هذه الأوامر:

points = [12.0000   15.0000
          33.0000   24.0000
          33.0000   24.0000];

vertex1 = [12 ;  15];
vertex2 = [33 ;  24];

points = points((points(:,1) ~= vertex1(1)) | (points(:,2) ~= vertex1(2)), :);
points = points((points(:,1) ~= vertex2(1)) | (points(:,2) ~= vertex2(2)), :);

النتيجة كما توقعت:

>> points
points =  
   Empty matrix: 0-by-2
هل كانت مفيدة؟

المحلول

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

الفعلي مقابل.الدقة المعروضة

الآن لمعالجة المثال المحدد في السؤال ... بينما 24.0000 و 24.0000 نكون عرض وبنفس الطريقة، يتبين أنهما يختلفان فعليًا بأرقام عشرية صغيرة جدًا في هذه الحالة.أنت لا ترى ذلك لأن MATLAB يعرض فقط 4 أرقام مهمة بشكل افتراضي, ، والحفاظ على الشاشة الشاملة نظيفة ومرتبة. إذا كنت تريد أن ترى الدقة الكاملة، فيجب عليك إما إصدار format long أمر أو عرض أ التمثيل الست عشري من العدد:

>> pi
ans =
    3.1416
>> format long
>> pi
ans =
   3.141592653589793
>> num2hex(pi)
ans =
400921fb54442d18

القيم المبدئية مقابلالقيم المحسوبة

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

>> a=sum([0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1]);  % Sum 10 0.1s
>> b=1;                                               % Initialize to 1
>> a == b
ans =
  logical
   0                % They are unequal!
>> num2hex(a)       % Let's check their hex representation to confirm
ans =
3fefffffffffffff
>> num2hex(b)
ans =
3ff0000000000000

كيفية التعامل بشكل صحيح مع مقارنات الفاصلة العائمة

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

a = 24;
b = 24.000001;
tolerance = 0.001;
if abs(a-b) < tolerance, disp('Equal!'); end

سيتم عرض "يساوي!".

يمكنك بعد ذلك تغيير الكود الخاص بك إلى شيء مثل:

points = points((abs(points(:,1)-vertex1(1)) > tolerance) | ...
                (abs(points(:,2)-vertex1(2)) > tolerance),:)

تمثيل النقطة العائمة

نظرة عامة جيدة على أرقام الفاصلة العائمة (وعلى وجه التحديد معيار IEEE 754 لحساب الفاصلة العائمة) يكون ما يجب أن يعرفه كل عالم كمبيوتر عن حساب النقطة العائمة بواسطة ديفيد غولدبرغ.

يتم تمثيل رقم الفاصلة العائمة الثنائي فعليًا بثلاثة أعداد صحيحة:قليلا علامة s, ، دلالة (أو معامل/كسر) b, ، والأس e. لتنسيق الفاصلة العائمة مزدوج الدقة, ، يتم تمثيل كل رقم بـ 64 بت موزعة في الذاكرة على النحو التالي:

enter image description here

ويمكن بعد ذلك العثور على القيمة الحقيقية باستخدام الصيغة التالية:

enter image description here

يسمح هذا التنسيق بتمثيل الأرقام في النطاق من 10^-308 إلى 10^308.بالنسبة لـ MATLAB يمكنك الحصول على هذه الحدود من realmin و realmax:

>> realmin
ans =
    2.225073858507201e-308
>> realmax
ans =
    1.797693134862316e+308

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

لفهم أخطاء التقريب هذه بشكل أفضل، من المفيد النظر إلى دقة الفاصلة العائمة النسبية التي توفرها الدالة eps, ، الذي يحدد المسافة من رقم معين إلى أكبر تمثيل للفاصلة العائمة التالية:

>> eps(1)
ans =
     2.220446049250313e-16
>> eps(1000)
ans =
     1.136868377216160e-13

لاحظ أن الدقة نسبي لحجم رقم معين يتم تمثيله؛سيكون للأعداد الأكبر مسافات أكبر بين تمثيلات الفاصلة العائمة، وبالتالي سيكون لها أرقام أقل من الدقة بعد العلامة العشرية.يمكن أن يكون هذا اعتبارًا مهمًا مع بعض الحسابات.خذ بعين الاعتبار المثال التالي:

>> format long              % Display full precision
>> x = rand(1, 10);         % Get 10 random values between 0 and 1
>> a = mean(x)              % Take the mean
a =
   0.587307428244141
>> b = mean(x+10000)-10000  % Take the mean at a different scale, then shift back
b =
   0.587307428244458

لاحظ أنه عندما نغير قيم x من النطاق [0 1] إلى النطاق [10000 10001], ، حساب المتوسط، ثم طرح متوسط ​​الإزاحة للمقارنة، نحصل على قيمة تختلف عن آخر 3 أرقام مهمة.يوضح هذا كيف يمكن لإزاحة البيانات أو قياسها أن يغير دقة الحسابات التي يتم إجراؤها عليها، وهو أمر يجب أخذه في الاعتبار في بعض المشكلات.

نصائح أخرى

وانظروا هذا المقال: الأخطار من النقطة العائمة . على الرغم من الأمثلة التي هي في FORTRAN له معنى بالنسبة تقريبا أي لغة البرمجة الحديثة، بما في ذلك MATLAB. يتم وصف المشكلة (والحل لذلك) في قسم "مقارنات الآمنة".

واكتب

format long g

وهذا الأمر سوف تظهر القيمة الكاملة للعدد. فمن المحتمل أن يكون شيء من هذا القبيل +24.00000021321! = +24.00000123124

وحاول أن تكتب

<اقتباس فقرة>   

0.1 + 0.1 + 0.1 = = 0.3.

تحذير: قد يفاجأ عن نتيجة

وربما رقمين هي في الواقع 24.0 و24،000000001 ولكن كنت لا ترى جميع الأماكن العشرية.

وتحقق من مطلب EPS وظيفة .

وماتلاب يستخدم العائمة الرياضيات نقطة يصل إلى 16 أرقام من الدقة (يتم عرض سوى 5).

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