إضافة 64 بت الأرقام باستخدام حساب 32 بت
سؤال
كيف نضيف أرقام 64 بت باستخدام حساب 32 بت ؟؟
المحلول
أضف أقل البايتات المهمة أولاً ، احتفظ بالحمل. أضف أهم البايتات بالنظر إلى الحمل من LSBs:
; x86 assembly, Intel syntax
; adds ecx:ebx to edx:eax
add eax, ebx
adc edx, ecx
نصائح أخرى
فكر في كيفية إضافة رقمين من رقمين باستخدام الحساب المكون من رقم واحد.
42
+39
---
أولاً تضيف العمود الأيمن. ("الوحدات" أو "الوحدات"). 2+9 هو 11. 11 "فائض" حساب واحد من رقم 1 ، لذلك عليك "حمل" 10.
1
42
+39
---
1
الآن يمكنك إضافة عمود "TENS" الأيسر ، بما في ذلك الحمل. 1+4+3 = 8.
1
42
+39
---
81
8 أقل من 10 ، لذلك لا حمل. انت انتهيت.
ماذا حدث للتو؟ عندما تقول أن الرقم هو "42" (في القاعدة 10) تقصد حقًا
4*10+2
أو مكافئ،
4*10^1+2*10^0
(عندما أقول "A^B" ، مثل "10^1" ، أعني "A" تم رفعه إلى القوة b'th ": A مضاعفة بنفسه ب. 10^0 هو 1. 10^1 هو 10. 10 ^2 هو 10*10 = 100 ...)
عندما تضيف "42" و "39" أنت تقول
4*10+2+3*10+9
الذي يساوي
(4+3)*10+(2+9)*1
(4+3)*10+(11)*1
(4+3)*10+(1*10+1)*1
الآن نظرًا لأن "11" ليس رقمًا صحيحًا رقمًا ، فأنت بحاجة إلى حمل 10 من تلك ، وتحويله إلى 1 في مكان العشرات.
(4+3)*10+(1)*10+(1)*1
(4+3+1)*10+(1)*1
(8)*10+(1)*1
وهو 81.
لذا ، لماذا كنت أتحدث عن هذا بدلاً من سؤالك عن 64 بت الأرقام و 32 بت حسابية؟ لأنها في الواقع هي نفسها بالضبط!
يتراوح رقم من 0 إلى 9. يتراوح رقم "32 بت" من 0 إلى 2^32-1. (على افتراض أنها غير موقعة.)
لذلك ، بدلاً من العمل في القاعدة 10 ، دعنا نعمل في القاعدة 2^32. في القاعدة 2^32 ، نكتب 2^32 كـ 10. إذا كتبت رقم 64 بت في القاعدة 2^32 ، فسيكون ذلك
(x)*10+y
حيث x و y هي رموز للأرقام بين 0 و 2^32-1. تلك الرموز هي bitstrings.
إذا كنت ترغب في إضافة رقمين 64 بت ، قم بتكسيرهما في القاعدة 2^32 على النحو التالي:
a_1*10+a_0
+b_1*10+b_0
الآن يمكنك إضافتها في القاعدة 2^32 بنفس الطريقة التي تضيفها بها في القاعدة 10 - فقط ، بدلاً من الإضافة باستخدام حساب الأرقام الذي تضيفه باستخدام حساب 32 بت!
كيف يمكنك تقسيم رقم 64 بت إلى اثنين من أرقام 32 بت A_1 و A_0؟ قسمة A على 2^32. ليس في نقطة عائمة ، ولكن Integrower - حيث تحصل على توزيعات الأرباح والباقي. توزيعات الأرباح هي A_1 ، والباقي هو A_0.
لسوء الحظ ، يتطلب ذلك الحساب 64 بت. ومع ذلك ، عادةً ما يكون A_1 هو "النصف الأكثر أهمية" لـ A ، لذلك ، في بناء جملة النمط C:
a_1=(a >> 32)
a_0=(a & 0xFFFFFFFF)
حيث >> هو bitshift الأيمن و & هو bitwise و.
عادةً إذا لم تتمكن من القيام بإضافة 64 بت ، فإن "رقم 64 بت" سيكون في الواقع أرقام 32 بت A_1 و A_0. لن يكون لديك uint64_t إذا لم تتمكن من القيام بحساب uint64_t!
كل هذا يفترض أنك تقوم بحساب غير موقّع ، لكن التعامل مع العلامات أمر سهل من هنا.
رمز C الذي تم نشره مسبقًا هو مطول غير ضروري:
unsigned a1, b1, a2, b2, c1, c2;
c1 = a1 + b1;
c2 = a2 + b2;
if (c1 < a1)
c2++;
يمكن استبدال "A1" في "if" بـ "B1" أيضًا. على الفائض ، سيكون C1 أقل من A1 و B1.
إذا كانت الأرقام 64 بت (أ2،أ1) وب2،ب1)، أين x2 هل تم أخذ 32 بتات عالية غير موقعة ، و x1 هو 32 بتات منخفضة على أنها غير موقعة ، ثم يتم إعطاء مجموع الرقمين أدناه.
c1 = a1 + b1
c2 = a2 + b2
if (c1 < a1 || c1 < b1)
c2 += 1
يبدو شيئًا كهذا
/* break up the 64bit number into smaller, 16bit chunks */
struct longint {
uint16 word0;
uint16 word1;
uint16 word2;
uint16 word3;
};
uint16 add(longint *result, longint *a, longint *b)
{
/* use an intermediate large enough to hold the result
of adding two 16 bit numbers together. */
uint32 partial;
/* add the chunks together, least significant bit first */
partial = a->word0 + b->word0;
/* extract thie low 16 bits of the sum and store it */
result->word0 = partial & 0x0000FFFF;
/* add the overflow to the next chunk of 16 */
partial = partial >> 16 + a->word1 + b->word1;
/* keep doing this for the remaining bits */
result->word1 = partial & 0x0000FFFF;
partial = partial >> 16 + a->word2 + b->word2;
result->word2 = partial & 0x0000FFFF;
partial = partial >> 16 + a->word3 + b->word3;
result->word3 = partial & 0x0000FFFF;
/* if the result overflowed, return nonzero */
return partial >> 16;
}
لا تستخدم الأجهزة الفعلية 32 بت لإضافة 16 بت في كل مرة ، لا يلزم سوى القليل من الحمل للإضافة ، وكل وحدة المعالجة المركزية تقريبًا لديها علامة حالة حمل عندما تفيض عملية الإضافة ، لذلك إذا كنت تستخدم ملف 32 بت وحدة المعالجة المركزية ، يمكنك إضافة 64 بت المعاملات في عمليتين ، 32 بت.
إلى حد كبير ، كل معالج لديه عملية حمل وإضافات ، والتي تهتم بها فقط إذا كنت تقوم برمجة في التجميع. إذا كنت تستخدم لغة أعلى ، فإن برنامج التحويل البرمجي يتفصل عن نفس عمليات الإضافة الدقيقة. أعطاني AVR-GCC هذا عند إضافة رقمين 16 بت-AVR هو 8 بت-ولكن نفس المفاهيم سوف تنطبق على المعالجات العليا.
بالنظر إلى الأرقام في السجلات R1: R2 و R3: R4:
ADD R2,R4 ; first add the two low-bytes, result stored into R2
ADC R1,R3 ; then the two high-bytes and the carry bit, into R1
يتم تخزين النتيجة في R1: R2.