pswin.pooya
چهارشنبه 19 آبان 1395, 01:15 صبح
یکی دو روز پیش از یکی شنیدم که بهش گفته بودن نمی شه عملیات بزرگتر از 32 بیتی روی پردازنده های 32 بیتی داشت. تصمیم گرفتم که یه مقاله کوچیک بنویسم تا این سوء تفاهم حل بشه. شما داخل پردازنده های 32 بیتی هم می تونید عملیات بزرگتر از 32 بیت داشته باشید و هم میزان حافظه بیشتر. اما چه شکلی؟
حافظه بیشتر:
پردازنده های x86 ( و شاید خانواده های دیگه) که 32 بیتی هستن می تونن میزان حافظه بیشتر از 32 بیت رو قبول کنن. این کار توسط یک الحاقی پردازنده صورت می گیره به اسم PAE که میزان آدرس باس پردازنده رو زیاد می کنه. مثلا پردازنده های 32 بیتی هستن که آدرس باس 48 بیتی دارن. اما چه شکلی؟ سیستم عامل یکسری مفصر (descriptor) آدرس برای هر برنامه تعریف می کنه که به اسمهای GDT و LDT معروف هستن. این دو یه چیزی شبیه همون سگمتهای 16 بیتی هستن منتها با ساختارها پیچیده تر و کاملتر و البته قابلیت های بیشتر. توی حالت 32 بیتی میزان هر کدوم از این سگمنت های جدید همون 2 به توان 32 یا چهار گیگ هست اما یه فلگ (پرچم) داخلشون هست که به شما امکان می ده اندازه صفحه رو بجای 4 کیلوبایت به شیش مگابایت تغییر بدین. در نتیجه هر برنامه به تنهایی به همون چهار گیگ حافظه دسترسی داره (که به اصطلاح می گن می تونه آدرس دهی کنه) اما کل سیستم عامل می تونه از حافظه بیشتری بهره ببره. مثلا چهار گیگ رو به یه برنامه و چهار گیگ دیگه رو به یه برنامه دیگه اختصاص بده.
عملیات بیشتر از 32 بیت روی پردازنده 32 بیت:
راستش رو بخوایین یه ثبات 32 بیتی خیلی محدود هست و نمی شه عدد بزرگی توش جا داد مثلا int که حتی روی پردازنده 64 بیتی هم 32 بیت هست خیلی کارهای رو نمی تونه راه بندازه برای همین توی C/C++ شما می تونید از long long برای عملیات و محاسبات 64 بیتی استفاده کنید (حتی اگر پردازنده 32 بیتی باشه).
با عملیات بیشتر از 64 بیت چیکار کنیم؟
راستش رو بخوایین کلی راه حل هست:
1. بعضی از کامپایلر ها مثل GCC و MSVC دارای یکسری الحاقی ساده هستن که به کمک اونها می شه با اعداد 128 بیت و یا 256 بیت کار کرد:
https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html
من دقیقا نمی دونم اینها پشت صحنه چیکار می کنن. اما خب بالاخره دارن ساپورت می دن (به احتمال زیاد از چند دستور اسمبلی و یا دستورهای خاص اسمبلی استفاده می کنن و یا مواردی که در ادامه بررسیشون می کنم)
2. پردازندههایی مثل ARM و Intel دارای یک مجموعه دستور هستند که بهشون Super Scaler و یا بعضا SIMD گفته می شه. (البته توی معماری های دیگه می تونه MIMD هم باشه) این دستورها می تونن چندین عمیات جمع و ضرب و ... رو باهم انجام بدم و در نتیجه ثباتهای بزرگی دارن مثلا ثباتهای MMX در پردازنده x86 (حتی پردازندهایی مثل پنتیوم 3) دارای 128 بیت و سری دستورهای AVX ثباتهاشون 256 بیت هستن. این دستورها این امکان رو می دن که اعدادی به بزرگی 128 بیتی روشون عملیات انجام بگیره (و یا حتی در AVX2 به 512 هم رسیده که می شه چهار عملیات 128 بیتی همزمان). البته اگر برنامه نویس یکم وارد باشه و یکم هم اصول برنامه نویسی بدونه می تونه سوء استفاده خوبی بکنه و عملیات 128 و حتی 256 بیتی رو انجام بده. مثلا در مورد جمع 128 بیتی با دستورهای SSE:
z = _mm_add_epi64(x,y);
c = _mm_unpacklo_epi64(_mm_setzero_si128(), unsigned_lessthan(z,x));
z = _mm_sub_epi64(z,c)
https://en.wikibooks.org/wiki/X86_Assembly/SSE
https://en.wikipedia.org/wiki/Advanced_Vector_Extensions
به هر حال اکثر کامپایلرها از این دستورها پشتیبانی می کنن و شاید هم پشت صحنه الحاقی های همون مورد اول همین دستورها باشن.
3. راه سوم. اگر برنامه نویس یکم اصول برنامه نویسی بلد باشه می تونه با عملیات بیتی خیلی ساده خودش توابعی طراحی کنه که اینکار رو انجام بدن. مثلا برای جمع 128 بیتی کافیه مقدار carry رو برای جمع 32 بیتی بدست بیارین و عملیات معروف xor و and رو انجام بدین. و البته همه عملیات ریاضی به کمک این توابع ساده بیتی قابل پیاده سازی هستن و شما به چند دستور ساده اسمبلی و حتی C می تونید از پس این مشکل بر بیاین. (البته بگذریم از اینکه پردازنده های x86 اصلا برای اینکار هم دستورهای مثل adc و sbb رو دارن.)
4. از کتابخونه ها استفاده کنید:
کتابخونه های زیادی برای کار با عملیات ریاضی و مخصوصا عملیات بزرگ و یا امن داخل سی پلاس پلاس و سی طراحی شدن که می تونن این عملیات رو برای شما انجام بدن و دیگه لازم نیست استعداد خاصی مثل یاد گیری SSE و ... به خرج بدین. تنها کاری که باید بکنید. اینه که باید توابع اونها رو صدا بزنید:
https://gmplib.org/manual/
سخن آخر:
برنامه نویسی C/C++ تفاوتی که با بقیه زبانها داره اینه که برنامه نویس میانی نداره. یعنی یا برنامه نویس حرفه ای هست و یا هیچی نمی دونه و برنامه نویس حرفه ای این زبان برنامه نویسی هست که نه تنها تسلط کافی روی نرم افزار داشته باشه بلکه سخت افزار رو هم خوب بشناسه. لطفا قبل از هرگونه ادعا توی این زمینه و خراب کردن اعصاب بقیه تمرکز خودتون رو بزراید روی یادگیری بیشتر.
حافظه بیشتر:
پردازنده های x86 ( و شاید خانواده های دیگه) که 32 بیتی هستن می تونن میزان حافظه بیشتر از 32 بیت رو قبول کنن. این کار توسط یک الحاقی پردازنده صورت می گیره به اسم PAE که میزان آدرس باس پردازنده رو زیاد می کنه. مثلا پردازنده های 32 بیتی هستن که آدرس باس 48 بیتی دارن. اما چه شکلی؟ سیستم عامل یکسری مفصر (descriptor) آدرس برای هر برنامه تعریف می کنه که به اسمهای GDT و LDT معروف هستن. این دو یه چیزی شبیه همون سگمتهای 16 بیتی هستن منتها با ساختارها پیچیده تر و کاملتر و البته قابلیت های بیشتر. توی حالت 32 بیتی میزان هر کدوم از این سگمنت های جدید همون 2 به توان 32 یا چهار گیگ هست اما یه فلگ (پرچم) داخلشون هست که به شما امکان می ده اندازه صفحه رو بجای 4 کیلوبایت به شیش مگابایت تغییر بدین. در نتیجه هر برنامه به تنهایی به همون چهار گیگ حافظه دسترسی داره (که به اصطلاح می گن می تونه آدرس دهی کنه) اما کل سیستم عامل می تونه از حافظه بیشتری بهره ببره. مثلا چهار گیگ رو به یه برنامه و چهار گیگ دیگه رو به یه برنامه دیگه اختصاص بده.
عملیات بیشتر از 32 بیت روی پردازنده 32 بیت:
راستش رو بخوایین یه ثبات 32 بیتی خیلی محدود هست و نمی شه عدد بزرگی توش جا داد مثلا int که حتی روی پردازنده 64 بیتی هم 32 بیت هست خیلی کارهای رو نمی تونه راه بندازه برای همین توی C/C++ شما می تونید از long long برای عملیات و محاسبات 64 بیتی استفاده کنید (حتی اگر پردازنده 32 بیتی باشه).
با عملیات بیشتر از 64 بیت چیکار کنیم؟
راستش رو بخوایین کلی راه حل هست:
1. بعضی از کامپایلر ها مثل GCC و MSVC دارای یکسری الحاقی ساده هستن که به کمک اونها می شه با اعداد 128 بیت و یا 256 بیت کار کرد:
https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html
من دقیقا نمی دونم اینها پشت صحنه چیکار می کنن. اما خب بالاخره دارن ساپورت می دن (به احتمال زیاد از چند دستور اسمبلی و یا دستورهای خاص اسمبلی استفاده می کنن و یا مواردی که در ادامه بررسیشون می کنم)
2. پردازندههایی مثل ARM و Intel دارای یک مجموعه دستور هستند که بهشون Super Scaler و یا بعضا SIMD گفته می شه. (البته توی معماری های دیگه می تونه MIMD هم باشه) این دستورها می تونن چندین عمیات جمع و ضرب و ... رو باهم انجام بدم و در نتیجه ثباتهای بزرگی دارن مثلا ثباتهای MMX در پردازنده x86 (حتی پردازندهایی مثل پنتیوم 3) دارای 128 بیت و سری دستورهای AVX ثباتهاشون 256 بیت هستن. این دستورها این امکان رو می دن که اعدادی به بزرگی 128 بیتی روشون عملیات انجام بگیره (و یا حتی در AVX2 به 512 هم رسیده که می شه چهار عملیات 128 بیتی همزمان). البته اگر برنامه نویس یکم وارد باشه و یکم هم اصول برنامه نویسی بدونه می تونه سوء استفاده خوبی بکنه و عملیات 128 و حتی 256 بیتی رو انجام بده. مثلا در مورد جمع 128 بیتی با دستورهای SSE:
z = _mm_add_epi64(x,y);
c = _mm_unpacklo_epi64(_mm_setzero_si128(), unsigned_lessthan(z,x));
z = _mm_sub_epi64(z,c)
https://en.wikibooks.org/wiki/X86_Assembly/SSE
https://en.wikipedia.org/wiki/Advanced_Vector_Extensions
به هر حال اکثر کامپایلرها از این دستورها پشتیبانی می کنن و شاید هم پشت صحنه الحاقی های همون مورد اول همین دستورها باشن.
3. راه سوم. اگر برنامه نویس یکم اصول برنامه نویسی بلد باشه می تونه با عملیات بیتی خیلی ساده خودش توابعی طراحی کنه که اینکار رو انجام بدن. مثلا برای جمع 128 بیتی کافیه مقدار carry رو برای جمع 32 بیتی بدست بیارین و عملیات معروف xor و and رو انجام بدین. و البته همه عملیات ریاضی به کمک این توابع ساده بیتی قابل پیاده سازی هستن و شما به چند دستور ساده اسمبلی و حتی C می تونید از پس این مشکل بر بیاین. (البته بگذریم از اینکه پردازنده های x86 اصلا برای اینکار هم دستورهای مثل adc و sbb رو دارن.)
4. از کتابخونه ها استفاده کنید:
کتابخونه های زیادی برای کار با عملیات ریاضی و مخصوصا عملیات بزرگ و یا امن داخل سی پلاس پلاس و سی طراحی شدن که می تونن این عملیات رو برای شما انجام بدن و دیگه لازم نیست استعداد خاصی مثل یاد گیری SSE و ... به خرج بدین. تنها کاری که باید بکنید. اینه که باید توابع اونها رو صدا بزنید:
https://gmplib.org/manual/
سخن آخر:
برنامه نویسی C/C++ تفاوتی که با بقیه زبانها داره اینه که برنامه نویس میانی نداره. یعنی یا برنامه نویس حرفه ای هست و یا هیچی نمی دونه و برنامه نویس حرفه ای این زبان برنامه نویسی هست که نه تنها تسلط کافی روی نرم افزار داشته باشه بلکه سخت افزار رو هم خوب بشناسه. لطفا قبل از هرگونه ادعا توی این زمینه و خراب کردن اعصاب بقیه تمرکز خودتون رو بزراید روی یادگیری بیشتر.