سؤال

كيف نضيف أرقام 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.

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