مرحباً ، خبروفيتيس. لقد كنت مولعا بموضوع سجلات النقطة العائمة لفترة طويلة. كنت دائمًا قلقًا بشأن كيفية إخراج الشاشة ، إلخ. أتذكر ، منذ فترة طويلة في الجامعة كنت أطبق صفي من أرقام الفاصلة العائمة التي تتكون من 512 بت. الشيء الوحيد الذي لم أستطع أن أدركه بأي حال كان الإخراج إلى الشاشة.
بمجرد أن أتيحت لي وقت فراغ ، توليت القديمة. حصلت على نفسي دفتر وقبالة نذهب. أردت أن أفكر في كل شيء بنفسي ، وأحيانًا فقط ابحث عن معيار IEEE 754.
وهذا ما جاء من كل شيء. للمهتمين ، أطلب القط.
لإتقان هذه المقالة ، تحتاج إلى معرفة ما يلي: ما هو قليلاً ، نظام ثنائي ، حسابي على مستوى معرفة الدرجات السلبية. لن تؤثر المقالة على التفاصيل الهندسية للتنفيذ على مستوى المعالج وكذلك على الأرقام الطبيعية وغير الطبيعية. يتم التركيز أكثر على تحويل الأرقام إلى ثنائي والعكس صحيح ، وكذلك شرح كيفية تخزين أرقام الفاصلة العائمة بشكل عام في شكل بت.
تعد أرقام الفاصلة العائمة أداة قوية للغاية تحتاج إلى استخدامها بشكل صحيح. فهي ليست شائعة مثل سجلات الأعداد الصحيحة ، ولكنها ليست معقدة أيضًا إذا تم اختراقها بذكاء وببطء.
في مقالة اليوم ، سأستخدم سجلات 32 بت كمثال. تعمل الأرقام ذات الدقة المزدوجة (64 بت) بنفس المنطق تمامًا.
أولاً ، دعنا نتحدث عن كيفية تخزين أرقام الفاصلة العائمة. أقدم 31 بت كبيرة. المفرد يعني أن الرقم سالب ، والصفر على التوالي هو عكس ذلك. يأتي بعد ذلك 8 بتات من الأس. هذه 8 بت هي الرقم غير الموقّع المعتاد. وفي النهاية هناك 23 بت من السرعوف. للراحة ، نشير إلى العلامة على أنها S ، والأُس باسم E ، والموسى ، بشكل غريب بما فيه الكفاية ، M.
نحصل على الصيغة العامة
ويعتبر السرعوف أن يكون بت واحد ضمني. وهذا يعني أن السرعوف ستكون 24 بت ، لكن بما أن أعلى 23 بت هو دائمًا واحدة ، فلا يمكنك كتابتها. وبالتالي ، فإن هذا "التقييد" سيمنحنا تفرد تمثيل أي رقم.
Mantissa هو رقم ثنائي عادي ، ولكن على عكس الأعداد الصحيحة ، فإن البتة الأكثر أهمية هي 2 ^ 0 درجة ، ثم في درجات متناقصة. هذا هو المكان الذي يأتي العارض في متناول اليدين. اعتمادًا على قيمتها ، تزداد أو تنقص قوة البت العالية اثنين. هذه هي العبقرية الكاملة لهذه الفكرة.
دعنا نحاول إظهار ذلك بمثال جيد:
تخيل الرقم 3.625 في شكل ثنائي. أولاً ، نقسم هذا الرقم إلى سلطات اثنين.

درجة اثنين من كبار يساوي واحد. E - 127 = 1. E = 128.
0 1،000،000 1،101،000،000،000،000،000،000
هذا هو كل رقم لدينا.
دعونا نحاول أيضا في الاتجاه المعاكس. لنفترض أن لدينا 32 بت ، تعسفي 32 بت.
0 10000100 (1) 11011100101000000000000
يشار إلى نفس بت عالية الترتيب الضمنية بين قوسين.
أولاً ، احسب الأس. E = 132. وفقًا لذلك ، فإن درجة الإثنين الأقدم تساوي 5. الإجمالي لدينا العدد التالي:
من السهل تخمين أنه لا يمكننا تخزين سوى مجموعة من 24 درجة اثنين. وفقًا لذلك ، إذا كان هناك رقمان يختلفان بشكل كبير بأكثر من 24 ، ثم عند إضافته ، يظل الرقم مساويًا للعدد الأكبر بينهما.
لتحويل مريح ، قمت بتحميل برنامج صغير في C.
#include <stdio.h> union IntFloat { unsigned int integerValue; float floatValue; }; void printBits(unsigned int x) { int i; for (i = 31; i >= 0; i--) { if ((x & ((unsigned int)1 << i)) != 0) { printf("1"); } else { printf("0"); } if (i == 31) { printf(" "); } if (i == 23) { printf(" "); } } printf("\n"); } int main() { union IntFloat b0; b0.floatValue = 59.578125; printBits(b0.integerValue); b0.integerValue = 0b01000010011011100101000000000000; printf("%f\n", b0.floatValue); return 0; }
خطوة الشبكة هي الفرق الأدنى بين رقمين عشريين متجاورين. إذا كنا نمثل تسلسل البتات من رقم كعدد صحيح منتظم ، فسيختلف رقم الفاصلة العائمة المجاورة في البتات كعدد صحيح لكل وحدة.
يمكن التعبير عنها بطريقة أخرى. سيختلف رقمان الفاصلة العائمة المجاورة بمقدار 2 ^ (E - 127 - 23). أي بفارق يساوي قيمة البتة الأقل دلالة.
كدليل ، يمكنك تغيير الرئيسي في التعليمات البرمجية وتجميع مرة أخرى.
union IntFloat b0, b1, b2; b0.floatValue = 59.578125F; b1.integerValue = b0.integerValue + 1; b2.floatValue = b1.floatValue - b0.floatValue; printBits(b0.integerValue); printBits(b1.integerValue); printBits(b2.integerValue); printf("%f\n", b0.floatValue); printf("%f\n", b1.floatValue); printf("%f\n", b2.floatValue); short exp1 = 0b10000100; short exp2 =0b01101101; b0.integerValue = 0b01000010011111111111111111111111; b1.integerValue = b0.integerValue + 1; b2.floatValue = b1.floatValue - b0.floatValue; printBits(b0.integerValue); printBits(b1.integerValue); printBits(b2.integerValue); printf("%f\n", b0.floatValue); printf("%f\n", b1.floatValue); printf("%f\n", b2.floatValue); printf("%d %d\n", exp1, exp2);
أعتقد أنه يمكنك اليوم التوقف ، وإلا فستتحول إلى فترة طويلة. في المرة القادمة سأكتب عن إضافة أرقام الفاصلة العائمة وفقدان الدقة عند التقريب.
ملاحظة: أنا أفهم أنني لم أتطرق إلى موضوع الأرقام غير الطبيعية ، إلخ. لم أكن أرغب في تحميل المقالة كثيرًا ، ويمكن العثور على هذه المعلومات بسهولة في معيار IEEE 754 في البداية تقريبًا.