منذ عدة سنوات ، عملت في قسم Microsoft Xbox 360. فكرنا في إصدار وحدة تحكم جديدة ، وقررنا أنه سيكون من الرائع أن تتمكن وحدة التحكم هذه من تشغيل الألعاب من وحدة التحكم في الجيل السابق.
إن المحاكاة صعبة دائمًا ، لكن الأمر أكثر صعوبة إذا كان رؤساء الشركات يغيرون باستمرار أنواع المعالجات المركزية. أول Xbox (يجب عدم الخلط بينه وبين Xbox One) استخدم وحدة المعالجة المركزية x86. في Xbox الثاني ، وهو آسف ، استخدم Xbox
360 معالج PowerPC. يستخدم Xbox الثالث ، وهو Xbox
One ، وحدة المعالجة المركزية x86 / x64. هذه القفزات بين مختلف
المعايير الدولية لم تبسط حياتنا.
شاركت في عمل الفريق الذي قام بتدريس Xbox 360 لمحاكاة العديد من ألعاب Xbox الأولى ، أي محاكاة x86 على PowerPC ، ولهذا حصلت على لقب
"مضاهاة النينجا" . ثم طُلب مني دراسة مسألة محاكاة وحدة المعالجة المركزية Xbox 360 PowerPC على وحدة المعالجة المركزية x64. سأقول مقدمًا أنني لم أجد حلاً مرضًا.
FMA! = MMA
أحد الأشياء التي أزعجتني هي الإضافة
المتعددة ، أو إرشادات
FMA . استلمت هذه التعليمات ثلاثة معلمات عند الإدخال ، وضربت الأولين ، ثم أضافت المعلمة الثالثة. تنصهر يعني أن التقريب لم يتم تنفيذها حتى نهاية العملية. بمعنى ، يتم تنفيذ الضرب بدقة كاملة ، وبعد ذلك يتم تنفيذ الإضافة ، وعندها فقط يتم تقريب النتيجة إلى الإجابة النهائية.
لإظهار ذلك بمثال ملموس ، دعونا نتخيل أننا نستخدم أرقام الفاصلة العائمة العشرية ورقمين دقيقين. تخيل هذا الحساب ، كما هو موضح كدالة:
FMA(8.1e1, 2.9e1, 4.1e1), 8.1e1 * 2.9e1 + 4.1e1, 81 * 29 + 41
81*29
يساوي
2349
وبعد إضافة 41 نحصل على
2390
. بتقريب ما يصل إلى رقمين ، نحصل على
2400
أو
2.4e3
.
إذا لم يكن لدينا FMA ، فسوف يتعين علينا أولاً إجراء الضرب ، الحصول على
2349
، والذي سوف يصل إلى رقمين من الدقة ويعطي
2300 (2.3e3)
. ثم نضيف
41
ونحصل على
2341
، والتي
سيتم تقريبها
مرة أخرى 2300 (2.3e3)
النتيجة النهائية
2300 (2.3e3)
، والتي هي أقل دقة من إجابة FMA.
ملاحظة 1: تقوم FMA(a,b, -a*b)
بحساب الخطأ في a*b
، وهو أمر رائع بالفعل.
ملاحظة 2: أحد الآثار الجانبية للملاحظة 1 هو أن x = a * b – a * b
قد لا تُرجع صفر إذا كان الكمبيوتر يقوم تلقائيًا بإنشاء تعليمات FMA.
لذلك ، من الواضح أن FMA تعطي نتائج أكثر دقة من إرشادات الضرب والإضافة الفردية. لن نتعمق ، لكننا سنوافق على أننا إذا كنا بحاجة إلى مضاعفة رقمين ثم إضافة الرقم الثالث ، فإن FMA سيكون أكثر دقة من بدائله. بالإضافة إلى ذلك ، غالبًا ما يكون لتعليمات FMA زمن انتقال أقل من تعليمات الضرب التي يتبعها تعليم الإضافة. في وحدة المعالجة المركزية Xbox 360 ، كانت سرعة معالجة زمن الوصول و FMA مساوية
لسرعة fmul أو
fadd ، لذلك باستخدام FMA بدلاً من
fmul متبوعًا
fadd التابع سمح بتقليل التأخير بمقدار النصف.
مضاهاة FMA
قام برنامج التحويل البرمجي Xbox 360
دائمًا بتكوين
إرشادات FMA ، سواء الموجه أو العددية. لم نكن متأكدين من أن معالجات x64 التي اخترناها ستدعم هذه التعليمات ، لذلك كان من الضروري محاكاة هذه بسرعة وبدقة. كان من الضروري أن يصبح محاكاة هذه التعليمات مثالياً ، لأنه من خلال تجربتي السابقة في محاكاة حسابات الفاصلة العائمة ، كنت أعلم أن النتائج "القريبة جدًا" أسفرت عن سقوط شخصيات على الأرض وسيارات تحلق خارج العالم وما إلى ذلك.
فما
المطلوب لمحاكاة إرشادات FMA بشكل مثالي إذا كانت وحدة المعالجة المركزية x64 لا تدعمهم؟
لحسن الحظ ، يتم إجراء الغالبية العظمى من حسابات الفاصلة العائمة في الألعاب بدقة تعويم (32 بت) ، ويمكنني أن أستخدم التعليمات بسرور مزدوج الدقة (64 بت) في محاكاة FMA.
يبدو أن محاكاة تعليمات FMA بدقة تعويم باستخدام الحسابات ذات الدقة المزدوجة يجب أن تكون بسيطة (
صوت الراوي: لكنها ليست كذلك ؛ عمليات الفاصلة العائمة ليست بسيطة أبدًا ). دقة تعويم 24 بت ، ومضاعفة دقة 53 بت. هذا يعني أنه إذا قمت بتحويل التعويم الوارد إلى الدقة المزدوجة (تحويل بدون فقد) ، فيمكنك إجراء الضرب بدون أخطاء. وهذا يعني أنه لتخزين نتائج دقيقة تمامًا ، يكفي فقط 48 بت من الدقة ، ولدينا المزيد ، أي أن كل شيء على ما يرام.
ثم نحن بحاجة للقيام الإضافة. يكفي أن تأخذ المصطلح الثاني في شكل تعويم ، وتحويله إلى مضاعفة ، ثم إضافته إلى نتيجة الضرب. نظرًا لأن التقريب لا يحدث في عملية الضرب ، ولا يتم تنفيذه إلا بعد الإضافة ، فهذا يكفي تمامًا لمحاكاة FMA. منطقنا مثالي. يمكنك إعلان النصر والعودة إلى الوطن.
كان النصر قريبًا جدًا ...
لكن هذا لا يعمل. أو على الأقل فشلت في بعض البيانات الواردة. تفكر في نفسك لماذا هذا يمكن أن يحدث.
استدعاء أصوات الموسيقى المعلقة ...
يحدث الفشل لأنه ، من خلال تعريف FMA ، يتم إجراء الضرب والإضافة بدقة كاملة ، وبعد ذلك يتم تقريب النتيجة بعائمة دقيقة. تمكنا
تقريبا لتحقيق هذا.
يحدث الضرب دون التقريب ، وبعد ذلك ، يتم التقريب. هذا
مشابه لما نحاول القيام به. لكن التقريب بعد الإضافة يتم بدقة
مضاعفة . بعد ذلك ، نحتاج إلى حفظ النتيجة بدقة تعويم ، ولهذا السبب يحدث التقريب مرة أخرى.
تفو-F.
التقريب المزدوج .
سيكون من الصعب توضيح ذلك بوضوح ، لذلك دعونا نعود إلى تنسيقات الفاصلة العشرية العشرية ، حيث الدقة المفردة عبارة عن منزلتين عشريتين والدقة المزدوجة هي أربعة أرقام. ودعونا نتخيل أننا نحسب
FMA(8.1e1, 2.9e1, 9.9e-1)
، أو
81 * 29 + .99
.
الجواب الدقيق لهذا التعبير سيكون
2349.99
أو
2.34999e3
. عند التقريب إلى الدقة المفردة (رقمان) ، نحصل على
2.3e3
. دعونا نرى ما يحدث عندما نحاول محاكاة هذه الحسابات.
عندما نضرب
81
و
29
بدقة مضاعفة ، نحصل على
2349
. جيد حتى الان
ثم نضيف
.99
2349.99
على
2349.99
. كل شيء لا يزال بخير.
يتم تقريب هذه النتيجة إلى الدقة المزدوجة ونحصل على
2350 (2.350e3)
. أوه، أنها.
نقوم
2400 (2.4e3)
بدقة مفردة ووفقًا لقواعد
التقريب IEEE
إلى الأقرب حتى نحصل على
2400 (2.4e3)
. هذا هو الجواب الخاطئ. يحتوي على خطأ أكبر قليلاً من النتيجة المستديرة بشكل صحيح التي تم إرجاعها بواسطة تعليمة FMA.
يمكنك تحديد أن المشكلة في قاعدة بيئة IEEE حتى أقرب واحد. ومع ذلك ، بغض النظر عن قاعدة التقريب التي تختارها ، ستكون هناك دائمًا حالة حيث يقوم التقريب المزدوج بإرجاع نتيجة مختلفة عن FMA الحقيقية.
كيف انتهى كل شيء؟
لم أتمكن من إيجاد حل مرضٍ تمامًا لهذه المشكلة.
تركت فريق Xbox قبل وقت طويل من إصدار Xbox One ، ومنذ ذلك الحين لم أكن أولي اهتمامًا كبيرًا بوحدة التحكم ، لذلك لا أعرف القرار الذي اتخذوه. تحتوي المعالجات x64 الحديثة على تعليمات FMA يمكنها محاكاة مثل هذه العمليات بشكل مثالي. يمكنك أيضًا استخدام معالج x87 الرياضي بطريقة ما لمحاكاة FMA - لا أتذكر النتيجة التي توصلت إليها عندما درست هذا السؤال. أو ربما قرر المطورون ببساطة أن النتائج قريبة إلى حد ما ويمكن استخدامها.