مسابقه چهارم: کدام حلقه سریع‌تر است؟

مسابقه چهارم: کدام حلقه سریع‌تر است؟

مسابقه چهارم: کدام حلقه سریع‌تر است؟
مسابقه چهارم: کدام حلقه سریع‌تر است؟

حدود ۷ ماه پیش، مسابقه سوم سیسوگ رو برگزار کردیم و کلی نکته در مورد خواندن رشته‌های ورودی را بررسی کردیم. فکر کردم که بد نیست یک چالش جدید داشته باشیم! البته چالش‌ها هیچ وقت بی حاشیه نیستند مثل سه مسابقه قبل، در واقع مسئله آینه که کنار هم چیزهای جدیدی یاد بگیریم نه اینکه بخواهیم بگیم کی بهتره!‌ هرکسی هرچقدر هم عالی باشه توی سطح خودش باز چیزهای جدید برای فراگرفتن هست.

 

مقدمه

اگر شبکه‌های اجتماعی سیسوگ رو دنبال می‌کنید احتمالاً میدانید که چند هفته‌ای هست درگیر ساخت یه هوش مصنوعی شطرنج هستم که روی میکروکنترلر stm32 قابل اجراست و اولین قسمت این پروژه رو تحت عنوان “پیاده سازی هوش مصنوعی شطرنج” منتشر کردم. نکته‌ای که توی این پیاده سازی خیلی مهمه دریافت بهترین پرفورمنس از میکروکنترلر است. برای این که عملکرد قابل قبولی داشته باشه لازمه که یه سری بهینه سازی‌ها روی کد انجام بشه نظیر این که مثلاً این که توابع پر استفاده به حافظه RAM منتقل بشن یا تا جای ممکن کد بهینه بشه. ایده این مسابقه هم دقیقاً از همینجا میاد. برای چالش چهارم با سیسوگ همراه باشید.

 

صورت مساله

با فرض این که از میکروکنترلر STM32Fxxx استفاده می کنیم سرعت اجرای حلقه‌های زیر به چه صورت است؟

یا

فکر می‌کنید کدام حلقه سریع‌تر اجرا می‌شود؟ یا شاید سرعت اجرای برابری دارند! شما چه فکر می‌کنید؟

 

شرایط داوری و جایزه

با توجه به صورت مسئله علاوه بر جواب لازم است دلیل آن نیز ذکر شود. پاسخ‌های صحیح با توضیحات کامل‌تر دارای اولویت بالاتری هستند. منظور از کامل بودن توضیحات صرفاً بلند بودن کامنت نیست بلکه دلیل باید به شکل گویا بیان شده باشد.

به دو نفر از کسانی که بتوانند جواب صحیح را با ذکر دلیل ارائه دهند به قید قرعه مبلغ دو میلیون ریال جایزه نقدی تعلق خواهد گرفت.

 

ارسال جواب

پاسخ‌های خود را در زیر همین پست کامنت کنید.

ممکن است که لازم باشد کدی را برای ما کامنت می‌کنید، در قسمت کامنت نظم کد به هم می‌ریزد، بهتر است که ابتدا به سایت paste.ubuntu.com بروید، Syntax را زبان C انتخاب کنید و کد خود را در قسمت Content کپی کرده و بر روی Paste کلیک کنید و در نهایت فقط URL را در قسمت کامنت برای ما ارسال کنید.

مهلت پاسخ هم تا آخر روز شنبه 16 اسفند ماه ۱۳۹۹ است.

 

پایان و جواب چالش چهارم سیسوگ

پاسخ این مسابقه در ادامه هم به صورت ویدئو و هم به صورت متن وجود دارد.

اگر تمایل به دیدن ویدئو دارید، می‌توانید پاسخ مسابقه را در ویدئوی زیر ببینید و اگر تمایل به خواندن متن دارید، متنی که پس از ویدئو قرار داده شده است، معادل با همین ویدئو است که می‌توانید آن را بخوانید.

 

 

پاسخ متنی:

سوال مسابقه این بود که آیا نوع متغیر استفاده شده در حلقه، تاثیری در سرعت اجرای حلقه دارد یا خیر؟ برای همین شمارنده یک حلقه را از نوع char که یک بایتی است و حلقه دیگر را از نوع int که چهار بایتی است انتخاب کردیم.

و به عنوان یک کار مهم با استفاده از کلمه کلیدی volatile، کامپایلر را مجبور کردیم که متغیرها را درون RAM قرار بدهد. در واقع اگر ما از کلاس volatile استفاده نمی‌کردیم، ممکن بود کامپایلر متغیرها را درون رجیسترهای CPU قرار بدهد، که این موضوع مدنظر ما نبود.

خب برای تست اجازه بدهید برنامه را به صورت عملی بر روی یک میکروکنترلر اجرا کنیم.

برای این کار هر دو حلقه loop_x و loop_y را در main برنامه فراخوانی می‌کنیم، تا هر حلقه یک بار اجرا شود.

پس از این کار وارد محیط دیباگ برنامه می‌شویم تا کدهای اسمبلی معادل را بررسی کنیم.

 

کد اسمبلی

کد اسمبلی

 

خب می‌دانیم که قرار است متغیر i درون یک خانه از حافظه تعریف بشود، حال این خانه حافظه در کجا قرار دارد؟ این خانه حافظه در جایی قرار داد که SP به آن اشاره می‌کند. در ابتدا مقدار 200 را درون رجیستر R3 قرار می‌دهیم، سپس مقدار R3 را درون آن خانه از حافظه که گفتیم بارگذاری می‌کنیم. در واقع این عمل مقداردهی اولیه متغیر را انجام می‌دهد.

پس از آن وارد روتین حلقه می‌شویم، در روتین حلقه اولین کاری که نیاز است انجام بدهیم این است که مقدار متغیر را از حافظه بارگذاری و آن را درون رجیستر R3 قرار بدهیم.

پس از این مرحله، به مرحله‌ای خواهیم رسید که چالش اصلی را ایجاد می‌کند.

همانطور که می‌دانید میکروکنترلر ما 32 بیتی است و محاسباتی که ALU یک میکروکنترلر 32 بیتی می‌تواند انجام بدهد، حتما باید 32 بیت باشد. برای همیسن قبل از اینکه ما بخواهیم مقداری را از رجیستر R3 کم بکنیم، نیاز است که متغیر یک بایتی را به یک متغیر 32 بیتی تبدیل بکنیم.

از آنجایی که متغیر ما علامتدار است، در این مرحله از دستور اسمبلی sxtb استفاده می‌شود که این دستور یک متغیر 8 بیتی علامت‌دار را به یک متغیر 32 بیتی علامت‌دار تبدیل می‌کند.

پس از این مرحله، ALU یک واحد از متغیر کم می‌کند و این متغیر در رجیستر R2 ذخیره می‌شود. و در نهایت R2 را در خانه حافظه ذخیره می‌کنیم.

حال اجازه بدهید ببینیم وقتی متغیر شمارنده 32 بیتی است چه اتفاقی می‌افتد. در اینجا در روتین حلقه، پس از اینکه متغیر بارگذاری شد، بدون اینکه طول متغیر افزایش یا کاهش یابد، متغیر یک واحد کاهش می‌یابد و در دوباره درون حافظه نوشته می‌شود.

در واقی تبدیل 8 به 32 و 32 به 8 بیت، سیکل‌های اضافی هستند که ما با تعریف متغیر یک بایتی به CPU تحمیل می‌کنیم. برای بهبود راندمان در اینجور مواقع ما می‌توانیم شمارنده حلقه را 32 بیتی تعریف کنیم.

اما اگر ما متغیرها را درون RAM تعریف نکنیم چه اتفاقی می‌افتد؟

برای اینکه متغیرها درون RAM قرار نگیرند، باید کلاس volatile را از ابتدای تعریف متغیر یک بایتی و چهار بایتی حذف کنیم.

 

کد اسمبلی

کد اسمبلی

در این حالت متغیر دیگر گسترش پیدا نمی‌کند، چون دیگر قرار نیست داخل RAM نوشته بشود. یکی از رجیسترهای CPU به عنوان متغیر در نظر گرفته می‌شود و بر روی آن محاسبات ریاضی انجام می‌شود. اما باز متغیر 32 بیتی سرعت اجرای بالاتری دارد چرا؟

چون برای یک متغیر 8 بیتی نیاز است که بررسی کنیم آیا سرریز رخ داده است یا نه، اما کنترل سرریز در متغیر 32 بیتی نیاز به بررسی توسط نرم‌افزار ندارد و به صورت سخت‌افزاری انجام می‌شود و نیاز به دستور اسمبلی ندارد.

پس توصیه می‌کنیم اگر میکروکنترلر شما 32 بیتی است، حتما از یک متغیر 32 بیتی برای شمارنده حلقه استفاده بکنید.

1 نفر

پــــســنــدیـده انـد

توجه

Zeus ‌
Zeus ‌

زئوس هستم ساکن المپ

دیدگاه ها

98 دیدگاه

  • متنی
    ۱۴ بهمن ۱۴۰۰

    سلام اول ممنون از شما بابت مطرح کردن این نکته مهم ، اما خب باید عرض کنم جوابی که به این سوال دادید کاملا اشتباهه. به کد اسمبلی نگاه کنید متوجه میشوید.
    در واقع بحث سرریز اصلا مطرح نیس

    • Zeus ‌
      Zeus ‌
      ۱۶ بهمن ۱۴۰۰

      سلام دوست عزیز
      ممکنه من اشتباه کرده باشم، خوشحال می‌شدم دلیلش رو از نظر خودتون بیان کنید

      • متین
        ۱۶ بهمن ۱۴۰۰

        والا دلیلش نیاز به توضیحات طولانی داره ،اما به صورت خلاصه اگه برید توضیحات اون دستور اسمبلی را بخونید میبینید که داره Zero extending انجام میده که تئوری خودش را داره و اصلا ربطی به سرریز نداره

        اجالاتا این توضیحاتی که دادید را اصلاح یا پاک کنید تا سر فرصت مناسب یه توضیح طولانی در موردش بنویسم و بدم که جایگزینش کنید

        • Zeus ‌
          Zeus ‌
          ۱۶ بهمن ۱۴۰۰

          سلام متین عزیز
          الان من دوباره مطلب رو مطالعه کردم، به نظر توضیحات مشکلی نداره البته قبول دارم که واژه سرریز احتمالا کژتابی داره و باعث سوءتفاهم میکننه بشه
          منتظرم توضیحات تکمیلی شما هستم تا جایگزین کنم
          متشکرم برای دقت شما

          • متین
            ۱۸ بهمن ۱۴۰۰

            یعنی مقاومتتون در مقابل اینکه اشتباه کردید را دوست دارم
            دوست من خب معلومه که با خوندن دوباره باز هم نمیفهمید که اشتباه کردید ، من گفتم اشتباه کردید که برید یکم معماری بخونید و این مورد را بررسی کنید نه اینکه دوباره نوشته خودتون را بخونید و بگید من بررسی کردم اشتباه نبود

            سری اول اونجوری صحبت کردم که هر ادمی حق داره اشتباه کنه و شما هم دارید برا این نوشته ها زحمت میکشید پس بهتره با اون لحن بهتون بگم که اشتباه میکنید که پیش بقیه حالت بدی نداشته باشه ولی با خوندن یه مسابقه دیگه هم دیدم که اونجا هم یه اشتباه غاحش تر از این کردید و این به ذهن من این رو متبادر میکنه که شما فقط ادای حرفه ای بودن را در میاورید

            بازم ببخشید من یکم تند صحبت کردم حقیقتا وقتی یه نفر اطلاعات غلط به خورد بقیه میده و قبول هم نمیکنه یکم کفری میشم و دوست ندارم بقیه با اطلاعات اشتباه کسی که خودش را در جایگاه معلم میدونه یه عمر یه موضوع را اشتباه یاد بگیرن

            شاید بپرسید چرا خودم درستش را نمیگم حقیقتش اینه که من وقت این کار را ندارم فقط میتونم کیورد بگم و بقیه برن دنبالش و اگه دیدم اطلاعات غلطی داده میشه یاداوری کنم همین
            موفق باشید

            0
          • Sisoog Os
            Sisoog Os
            ۱۸ بهمن ۱۴۰۰

            دوست عزیز ما اینجا سعی میکنیم مطلبی را پاک نکنیم و اگر قرار باشه تصحیح هم انجام بشه حتما ذکر خواهیم کرد و سعی میکنیم مطلب اشتباه را بگذاریم بمونه و دقیقا متذکر بشیم که حتی سابقه اشتباه ما هم بمونه

            هر مسابقه ای برقرار شد دوستانی مثل شما بودند که گفتند پاسخ درست نیست یا فلان جا مشکل هست که برخی از اونها هم ادعاهای زیادی هم داشتند و البته مثل شما هم قضاوت کردند وانتظار دارند که سریعا ما مطلب را حذف کنیم و ویرایش و … ما نمیتونیم برای هر نوع ادعایی مطلب را حذف کنیم و یا ویرایش کنیم و در ضمن خودمون را هم عاری از خطا نمیدونیم

            به جای بحث کردن و عصبانی شدن هم سعی میکنیم مطلب شما را عینا اینجا منعکس کنیم تمایل داشتید وقت بزارید یا نکاتی را عنوان کنید حتما اینحا قرار میگیره و اگر هم ما متوجه بشیم اشتیاه هست صراحتا اعلام میکنیم که همه بدونن, فرصت هم ندارید کیورد های خودتون را بدید ما هم منتشر میکنیم و خودمون هم اگر به جمع بندی شما رسیدیم حتما تصحیحات در پست انجام میشه

            0
          • Zeus ‌
            Zeus ‌
            ۱۸ بهمن ۱۴۰۰

            شما رو نمی فهمم، یه ادعایی می‌کنید و حاضر نیستید به جای دو سه پاراگرف حرف غیر مرتبط یک خط حرف فنی بزنید خوب باید در جوابتون چی بگن واقعا ؟
            منم مدعی نیستم که آدمی هستم که سطح بالایی دارم و اتفاقا گفتم ممکنه اشتباه کرده باشم اگر بهم ثابت بشه اشتباه کردم اتفاقا گفتم مطلب رو ویرایش می‌کنم
            بعد شما چکار کردید؟ فقط حرف زدید، و گفتید نه من میدونم شما اشتباه کردید،‌باشه مرسی که متوجه شدید من اشتباه کردم درستش رو هم زحمت بکشید بگید تا این کار رو نکنید میتونم استدلال کنم شما دارید اشتباه می‌کنید غیر اینه ؟

            0
        • Zeus ‌
          Zeus ‌
          ۱۸ بهمن ۱۴۰۰

          دوست عزیز این چیزی که شما بهش میگی کلید واژه، خودش اشتباهه 😐
          در واقع همونطور که در توضیحات هم ذکر شده داره Sign extension اتفاق می افته نه Zero extension

  • رضا
    ۱۱ آبان ۱۴۰۰

    مطالب خیلی عالی و تاثیر گذاربود.

  • علی
    ۲۰ اسفند ۱۳۹۹

    سلام جناب زئوس
    میبینم از خفا در امدید??
    اتفاق خاصی افتاده قاعده رو عوض کردید??
    خوب لااقل چشممون به جمالتون روشن شد☺☺

    • Sisoog Os
      Sisoog Os
      ۳ فروردین ۱۴۰۰

      سلام دوست عزیز
      البته ایشون خفا هم نبودند و قاعده خاصی هم نبوده:-)

      این هم ساختار متفاوتی برای اموزش هست که البته دوستان زیادی اون را میپسندند سعی کردیم این روش را هم تست کنیم

      • علی
        ۴ فروردین ۱۴۰۰

        بله بله صد البته
        موفق باشید

  • کامین جلیلی
    ۱۷ اسفند ۱۳۹۹

    حلقه loop_y سریع‌تر است، دلیلش هم به Zero extending برمی‌گردد.
    اگر به کد اسمبلی این دو حلقه توجه کنیم، می‌بینیم که در حلقه اول دستور اسمبلی UXTB وجود دارد که در حلقه دوم وجود ندارد.
    دستور اسمبلی UXTB در واقع عمل Zero extending یا همون اضافه کردن 0 به سمت چپ عدد را انجام می‌دهد (به دلیل مثبت بودن، عدد 0 اضافه می‌شود. اگر عدد ما منفی بود، عدد 1 اضافه می‌شد البته با یک دستور اسمبلی دیگر.)
    حالا چرا این کار را انجام می‌دهد؟ چون نوع char با طول 8 بیت است، برای انجام عملیات ریاضی two’s complement که مرجع آن بالاتر از 8 بیت، خواه 16 بیت یا 32 بیت باشد در واقع این یک اجبار است و حتما باید عمل Zero extending انجام بشود.

    اما در نهایت دلیل اصلی این که چرا این کار در ARM انجام می‌شود برمی‌گردد به تئوری two’s complement که بحثش کمی مفصل است. اما به طور خلاصه برای انجام عملیات ریاضی در این سیستم اعداد باید طول اعداد از قبل مشخص باشد و اگر طول عددی کمتر از مرجع در نظر گرفته شده است حتما باید با توجه به علامتش اکستند شود.

    خب می‌شه خیلی بیشتر در این مورد توضیح داد. این توضیحات شاید بنا به کوتاه بودن کمی گنگ باشند، اما سعی کردم خلاصه و مفید دلیلش رو بگم.

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      دقیقا این اتفاق بخاطر ۳۲ بیت بودن پردازنده می افته و جواب شما درسته

  • mobina mosannafat
    ۱۶ اسفند ۱۳۹۹

    با توجه به نوع میکروکنترلر گفته شده که 32 بیتی است ، سرعت اجرای دومین حلقه که با int است بیشتر است. زیرا سخت افزار به گونه ای طراحی شده که برای داده های ۳۲ بیتی کارایی بهتری دارد.
    متغیر int ،
    32 بیت و متغیر char ،
    8 بیتی است … cpu ممکنه ممکن است دستور العمل هایی جهت load , store و opration روی داده های ۳۲ بیتی داشته باشد و چنین دستورالعمل هایی برای داده از نوع char وجود نداشته باشد ، حال برای بارگزاری یک مقدار 8 بیتی ، باید یک مقدار 32 بیتی را بارگزاری کند پس‌مجبور است این 8 بیت را extract کند که خود زمان میبرد …
    همچنین برای ذخیره char که 8 بیتی است ممکن است مجبور باشد ۳۲ بیت را بارگزاری کند ، پس برای تنظیم زیرمجموعه ۸ بیتی مورد نظر باید از عملیات bitwise استفاده کند و سپس آن را ذخیره کند

  • حسین
    ۱۶ اسفند ۱۳۹۹

    سرعت لوپی که کانتر اون int هستش بیشتره، دلیلش هم اینه که دستورالعمل هایی برای عملیات ها وجود داره که به صورت ۳۲ بیتی کار میکنن، حالا ما از داده ۸ بیتی استفاده کنیم باید تبدیل داده انجام بدیدم که زمان میبره

  • سرباز وطن
    ۱۶ اسفند ۱۳۹۹

    ببخشید عجله کردم در ارسال دیدگاه
    دلیلش رو کامل توضیح ندادم
    یکی از دلایلی که دارم ساختار ALU هست وقتی واحد محاسبات منطقی هشت بیتی باشه برای یک داده 16 بیتی نیاز به دوبار پردازش اون داره ولی زمانی که این واحد 16 یا 32 بیتی باشه مسلما فرقی نمیکنه داده 16 32 یا 8 بیتی هست.

    خیلی دوست داشتم شرایط تستش رو سخت افزاری داشتم تا این تئوری رو ازمایش کنم

    به نظر اگر در یک شبیه ساز مانند پروتیوس میشد یک لایبرری قابل شبیه سازی پیدا کردبرای STM32 حتما یک بنچمارک میگرفتم بعد جواب میدادم با اینحا 3 ماه دیگه که خدمتم تموم شد حتما یه سر به این URL میزنم خیلی مشتاق پاسخ درست هستم…

    در سخن پایانی باید بگم وجود یک واحد محاسبه گر منطقی 32 بیتی فقط یکی از دلایل پردازش سریعتر حافظه میتونه باشه! برای اینکه پاسخ سریح تری بدم به وقت بیشتری برای مطالعه دیتاشیت یک میکروکنترلر پیچیده مانند ARM با اینهمه پیشرفت اونم برای اولین بار نیاز دارم

    پاینده و پیروز باشید زنده باد Open sorce

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      برای انجام محاسبات باید عدد توی یکی از رجیسترهای پردازنده لود بشه – و تمام رجیسترها ۳۲ بیت هستند- پس نیازه که برای لود یک عدد یک بایتی اونو کست کرد به ۳۲ بیت که همین کار زمان بیشتری رو در پردازنده میگیره.

  • سرباز وطن
    ۱۶ اسفند ۱۳۹۹

    ببخشید عجله کردم در ارسال دیدگاه

  • سرباز وطن
    ۱۶ اسفند ۱۳۹۹

    با سلام و خسته نباشید
    بنده تازه از AVR به Stm32 مهاجرت کردم (مهاجرت کلمه مناسبی نیست هردو میکروکنترلر عالی هستند) در risc های 8 بیتی داده نوع هشت بیتی زودتر پردازش میشه اما در مورد STM32 به نظرم با اینکه هنوز برگه اطلاعاتی اون رو مطالعه نکردم بخاطر معماریش زمان اجرای دو حلقه برابر هست یقین دارم

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      سلام دوست عزیز
      در واقع به دلیل این که ثبات ها و رجیسترهای میکروکنترلر ۳۲ بیتی هست باید عدد خوانده شده از روی حافظه به یک عدد ۳۲ بیتی تبدیل بشه تا محاسبات ریاضی روی اون انجام بشه و همین امر زمان بیشتری خواهد برد.
      در واقع حلقه دوم سریعتر اجرا میشه چون از همون ابتدا به شکل ۳۲ بیتی است و این عمل ۳۲ بیتی کردن داده نیاز نیست روی اون انجام بشه.

  • محمد امراللهی
    ۱۶ اسفند ۱۳۹۹

    عرض سلام و ادب
    حلقه دوم سریع تر است.
    با توجه به اینکه در stm32 باس حافظه و حافظه 32 بیتی است، در حلقه دوم int 32 بیتی است و بدون هیچ عملیات اضافه ای به آن دسترسی پیدا می کند اما در حلقه اول char یک بایت است و برای دسترسی به آن ابتدا باید تبدیل به 32 بیت شود تا در باس حافظه که 32 بیتی است قرار گیرد و در دسترس CPU قرار گیرد. بنابراین چند عملیات اضافه انجام می دهد.

  • سینا فقیهی
    ۱۵ اسفند ۱۳۹۹

    سرعت اجرا حلقه با متغیر اینتجر سریعتر است. متغیر اینتجر در کامپایلر های معمول اس تی ام ۳۲ به صورت یک عدد ۳۲ بیتی با علامت دیده میشه، با توجه به معماری کورتکس ام ۳ که از دستورات فشرده ۱۶ بیتی استفاده میکنند (بر خلاف نسل های قبلی مثل آرم ۷ ها که هم دستورات قوی ۳۲ بیتی داشتند و هم دستورات فشرده ۱۶ بیتی) محاسبه های ریاضی و منطقی فقط به صورت ۳۲ بیتی انجام میشود. در نتیجه عملیات های ۱۶ بیتی و ۸ بیتی(متغیر کاراکتر) با چند محاسبه و مقایسه به صورت ۳۲ بیتی انجام میشود که سرعت اجرا حلقه را کندتر میکند . برای اطمینان از این عملکرد میکروکنترلر میتوان سرعت اجرا برنامه را با یک تایمر یا حتی سیستیک تایمر هم استفاده کرد.

  • مصطفی حیدری
    ۱۵ اسفند ۱۳۹۹

    متغییر نوع char نمیتونه عدد ۲۰۰ رو ذخیره کنه و بجاش عدد منفی ۶۳ جاش میشینه. بعد اون حلقه char حدود ۶۴ بار اجرا میشه که به مراتب کمتر از حلقه int هست و این حلقه سریعتر اجرا میشه

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      متغییر char به شکل پیش فرض بدون علامت در نظر گرفته میشه !

      • مصطفی حیدری
        ۱۷ اسفند ۱۳۹۹

        نه عزیز. در تمام پلتفرم ها پیشفرض signd هست. از زمان z80 تا امروز صبح !!!!!

        • Zeus ‌
          zeus
          ۱۷ اسفند ۱۳۹۹

          اوه – بله حق با شماست، توی ادیتوری که من استفاده میکنم به شکل پیش فرض تیک بی علامت بودن خورده
          با این حال شک نکنید حلقه ۲۰۰ بار اجرا خواهد شد – چرا ؟
          شما وقتی از منفی ۵۷ یکی کم کنید میشود منفی ۵۸ و این تا منفی ۱۲۸ ادامه خواهد داشت بعد به مثبت ۱۲۷ خواهید رسید و تا صفر ادامه خواهد داشت.
          پس حلقه شما همچنان ۲۰۰ بار اجرا خواهد شد.

          کاری که اغلب دوستان انجام دادند 🙂

        • پویا مرادی
          پویا مرادی
          ۱۷ اسفند ۱۳۹۹

          در واقع نه. signed یا unsigned بودن char بسته به پیاده‌سازی و معماری داره:
          استاندارد C99:
          https://i.imgur.com/NlP7fWK.png
          https://stackoverflow.com/a/40772217/1506761

  • پویا مرادی
    پویا مرادی
    ۱۵ اسفند ۱۳۹۹

    ابتدا باید توجه کرد که برای مقایسه معنادار باید بهینه‌سازی کامپایلر خاموش شود (سوییچ O0). volatile کردن متغیرها هم به این موضوع کمک کرده است.
    تفاوت دو روش مورد اشاره این است که 200 در واقع یک int هست. هنگامی که این مقدار به پارامتر حلقه cast میشود، از آنجایی که نوع پارامتر i از نوع char هست، مقداری که در واقع درون i وجود دارد اصطلاحاً implementation defined است.
    در معماری Arm Cortex M، در حالت char به جای اینکه مقدار ۲۰۰ که قرار بود در یک رجیستر ۳۲ بیتی ذخیره شود،مقدار منفی ۵۵ در یک بایت قرار گرفته است. این باعث می‌شود که پروسسور برای جابه جایی بایت ها، از دو instruction اضافی استفاده نماید. در نتیجه loop باید زمان بیشتری را برای صفر کردن این عدد صرف کند.
    در تصویر زیر، تفاوت disassembly این دو روش (char و int) نشان داده شده است: (خطوط .loc مربوط به دیباگ هستند و حذف شده اند)
    https://i.imgur.com/VcvpnwN.png
    این کد در STM32F103 تست شد (صدهزار مرتبه) :
    https://dpaste.com/GFDQ6YECJ
    تفاوت زمانی به شکل زیر است:

    tests: 100000, total char_version(): 3407 millisecs.
    tests: 100000, total int_version(): 2826 millisecs.

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      بله درسته در واقع نیازه که متغششر قبل از بارگیری کست بشه.

  • مجید
    ۱۵ اسفند ۱۳۹۹

    سلام، اول اینکه باید به بررسی معماری و عرض بیت هسته ها پرداخته بشه، عرض بیت هسته و رجیستر های CortexM دارای 32 بیت هست، این به این معنی هست که وقتی متغیری تعریف میکنیم مقدارش درون رجیستر های 32 بیتی پردازش میشه، حالا میریم سراغ متغیر های تعریف شده:

    1. متغیر اول از نوع int هست و به صورت پیشفرض 32 بیتی به حساب میاد و طولش به اندازه طول رجیستر ها است.
    2. متغیر دوم از نوع char است و طول آن برابر با 8 بیت است.

    تا اینجا متوجه میشیم که متغیر دوم کل بیت های رجیستر را استفاده نمیکند، پس پردازش روی این متغیر به چه صورت هست؟
    در Cortex-M وقتی پردازش روی متغیر هایی کوچکتر از سایز رجیستر هاش انجام میشه کامپایلر بیت های اضافی را با 0 پر میکند! (جهت تبدیل به سایز بزرگتر)

    بررسی کد:
    تا قبل از حلقه while میزان پردازش را میتوان برابر در نظر گرفت (با توجه به اینکه دستورات پردازنده برای هردو وجود دارد)، اما وقتی وارد حلقه میشویم روی متغیر پردازش انجام میدهیم، در کد اول با متغیر int نیازی به پر کردن بیت های دیگر نیست ولی در کد دوم بدلیل استفاده از char پس از بارگزاری داده در رجیستر و بعد از کاهش مقدار متغیر نیاز به پر کردن بیت های 31~8 با مقدار 0 داریم، در نتیجه دو دستور دیگر نیز به ساختار کد اضافه میشود.

    در نتیجه تابع loop_y سرعت بیشتری در اجرا دارد!

  • مهرداد رستمی
    ۱۵ اسفند ۱۳۹۹

    حلقه دوم صحیح است
    در arm ثبات ها و پشته و تمام ورودی های آن اکثر دستورهای پردازش داده arm ۳۲ بیتی هستند.به همین دلیل بایستی درصورت امکان از انواع داده ۳۲ بیتی مثل int برای متغیر های محلی استفاده کنیم (این تفکر اشتباه است چون char فضای کمتر اشغال میکند بهتر است از آن استفاده کنیم….)

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      بله درسته – در اوقع باید ببینیم معماری سخت افزار چی هست و بر اساس اون معماری انتخاب انجام بدیم.

  • امیر
    ۱۵ اسفند ۱۳۹۹

    سلام
    چرا جواب من پاک شده؟
    :-((((

  • سروش موسی پور
    سروش موسی پور
    ۱۵ اسفند ۱۳۹۹

    ابتدا فکر کردم شاید 32-bit بودن باعث شود که فرقی بین 2 کد نباشد. بنابراین گفتم از این مسئله مطمئن شوم و جواب را ارسال کنم. با استفاده از DMA به منظورتغییر وضعیت یه پین با هربار تکرار شدن حلقه، متوجه تفاوت ناچیز فرکانسی 2 حلقه شدم. حلقه ای که از int استفاده میکرد کمی سریعتر بود و تقریبا 3% فرکانس بالاتری داشت.
    برای بررسی بیشتر از تبدیل کد c به اسمبلی استفاده کردم و متوجه شدم کاهش یک واحد توی 4 بایت (DWORD) یک مرحله کوتاه تر از یه تک بایته.
    برای بررسی صحت این قضیه، کد زیر رو توی https://godbolt.org/ با هر کامپایلر c به اسمبلی موجود بررسی کنید.

    void loop_x()
    {
    volatile char i=200;
    while(i–)
    __NOP();
    }

    void loop_y()
    {
    volatile int i=200;
    while(i–)
    __NOP();
    }

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      بله درسته حلقه int سریعتر است.

  • میلاد نیک پندار
    ۱۵ اسفند ۱۳۹۹

    سلام با توجه به استفاده از تابع اصلاح کننده volatile سرعت مقدار دهی متغییر به دلیل نیاز نبودن به درخواست ها و حلقه ها بیشتر میشود هرچند که در اینجا بی تاثیر هست چون داخل یک حلقه فقط برنامه اجرا شده و دوم اینک در هر دو مورد سوال از این تابع استفاده شده
    مثلا بعدی متغیر char هست که ۸ بیت فضا دارد در حالی که متغیر int فقط ۲ بیت فضا دارد و مقدار دهی int به دلیل کم بودن فضا بیشتر است
    به نظر من مورد دوم سوال که با int انجام شده سرعت بیشتری دارد

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      بله حلقه ای که با int است سریعتر است
      و این به دلیل volatile بودن متغیر هاست که کامپایلر را مجبور میکند متغییرها رو داخل رم ذخیره کند.

  • فرید ابراهیمی
    ۱۵ اسفند ۱۳۹۹

    سرعت اجرای تابع loop_x کمتر از تابع loop_y است . ولی حلقه های تعریف شده در هر کدام با سرعتی یکسان اجرا میشوند .

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      من فکر میکنم سرعت اجرای حلقه ها هم متفاوت خواهد بود چون متغییرها درون رم تعریف میشوند

      • فرید ابراهیمی
        ۱۷ اسفند ۱۳۹۹

        در اینجا ما در هر فراخوانی تابع یک ارجاع به آدرس دیگر داریم . به آدرس حلقه . و این ربطی به بیرون حلقه نداره . int یا char بودن متغیر در حلقه تاثیر گذار نیست . چرا که خود char یک نوع int . باید توجه داشته باشیم که حلقه پس از فراخوانی تابع ، فراخوانی میشه .

        • Zeus ‌
          zeus
          ۱۸ اسفند ۱۳۹۹

          دوست عزیز تاثیر گذار هست – اجازه بدید جواب تفصیلی رو منتشر کنیم – خواهید دید

  • علی
    ۱۵ اسفند ۱۳۹۹

    کدی که با int نوشته شده سریعتر خواهد بود
    چونکه کامپایلر نیازی به تبدیلش نداره تا عملیت ریاضی رو انجام بده
    حتی توی کامپیوتر هم همینه
    دلیل وجودی bool هم همینه

  • مهدی
    ۱۵ اسفند ۱۳۹۹

    درود
    باهم فرقی ندارن از لحاظ سرعت اجرا
    معماری آرم ورژن ۷ طبق مستنداتش برای خوندن و نوشتن مقادیر ۸ بیتی ۱۶ بیتی و ۳۲ بیتی میتونه از دستورالعمل های اتومیک که یک سیکل ماشین زمان میخوان استفاده کنه ،تعریف متغیر شما و مقدار دهی بهش یک سیکل زمان میگیره
    ولی احتمال میدم اگه متغیر رو ۳۲ بیتی تعریف میکردین
    حلقه وایل متفاوت تر ترجمه میشد و سرعت اجرا بیشتر میشد.
    کد رو تست نکردم دسترسی ندارم
    ?

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      در واقع مساله اینه که حلقه int سریعتر اجرا میشه
      بخاطر این که متغیرها توی رم هستند و هنگام لودشدن توی رجیسترهای cpu نیازه که به سی و دو بیت کست بشه و همین زمان بر خواهد بود.

  • حسین حسینی
    ۱۵ اسفند ۱۳۹۹

    من فکر میکنم برای میکروکنترلر stm32 فرقی نداره سرعتشون تو اجرای این حلقه ها.
    چون نوع int دو بایت هست میشه ۱۶ بیت ، و میکرو میتونه ۳۲ بیت رو تو یه کلاک پالس بنویسه ، حالا چه فرقی داره داده char یه بایتی یا ۸ بیتی باشه یا int دو بایتی یا ۱۶ بیتی.

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      خوب توی میکروکنترلرهای ۳۲ متغییر int به شکل ۳۲ بیتی تعریف میشه
      مساله دقیقا برمیگرده به لود کردن مقادیر از توی رم که برای int نیاز به کست کردن نداره ولی برای char نیازه این اتفاق بیفته.

  • حسین
    ۱۵ اسفند ۱۳۹۹

    با سلام .
    من فکر میکنم اون کدی که متغیر رو به صورت int تعریف میکنه سریعتر هست .
    stm32 ها 32 بیتی هستن .
    من در حالت دیبا گ کدهای اسمبلی رو در یک مورد نگاه میکردم .
    وقتی متغیر رو 8 بیتی تعریف میکردم برای دسترسی به اون دستورات اسمبلی بیشتری استفاده میشد .
    ولی برای دسترسی به متغیر 32 بیتی فرمانهای کمتری استفاده شده بود. فکر میکنم به خاطر اینکه باس دیتای cpu طولش 32 بیت هست این اتفاق میفته .البته کمپایلری هم که من استفاده کردم GCC بود.
    به نظر میرسه برای stm32 دسترسی 8 بیتی به صورت مستقیم امکانپذیر نباشه و علت این باشه.

  • آرش
    ۱۵ اسفند ۱۳۹۹

    با توجه به ۳۲ بیت بودن این سری میکرو ها، استفاده از متغییر int در تبدیل به دستورات اسمبلی به کدهای کمتری تبدیل می شود همچین به معماری حافظه این میکرو سازگارتر، بطوریکه مدیریت این کدها کمتر و سریع خواهد بود.
    لذا حالت دوم سریعتر هست.

  • مجید باقری
    ۱۵ اسفند ۱۳۹۹

    درکل ۳۲ بیت در stmما هست ک یک ریجستر کامل رو تشکیل بده که ب نامgeneral purposeهست و ثبات هایی ب نام R0,R1,..در ان ها وجود داره هر R ۵بیت هست در حالتchar ۲ تا از Rها درگیر میشن و در حالت کلی برای ریجستر *۳(۲×۵) که میشه ۳۰ بیت پس ۷تا باید R وجود داشته باشد
    چون تو حالت char که 8بیتیه باید 7 تا rداشته باشیم ولی تو int که ۱۶ بیتی هست و ۵*۳ و ۳تا ثبات rنیازه ولی در ۳۲ بیت ۶ تا ثبات r نیاز هست
    6تا rداریم پس در هر صورت intسرعت بیشتری داره

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      چطور به سه تا ثبات برای نگه داری یه عدد ۱۶ بیتی رسیدید ؟
      در ضمن متغییر int در خانواده های ۳۲ بیتی به شکل ۳۲ بیتی تعریف میشه

  • مجید باقری
    ۱۵ اسفند ۱۳۹۹

    چون تو حالت char که 8بیتیه باید 4 تا rداشته باشیم در قسمت ریجیستر (general purpose )
    ولی تو int که ۱۶بیتی هست
    3تا rداریم
    پس intسرعت بیشتری داره

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      ببینید این که حلقه int سریعتره درسته
      ولی توضیح شما رو متوجه نشدم :/

  • امیر علی
    ۱۵ اسفند ۱۳۹۹

    قطعا این کد اصلا اجرا نمیشه چون توی حلقه وایل هیچ شرطی نوشته نشده

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      😐
      چرا اجرا نشه دوست عزیز – همین که i مقداری غیر صفر داشته باشه حلقه صحیح است و تا وقتی که i مقداری غیر صفر داشته باشه اجرا میشه :/

  • مهدی
    ۱۵ اسفند ۱۳۹۹

    سلام . توی یه پست اموزشی داخل سایت در مورد بهینه سازی کد توی میکروهای avr گفته بودید که استفاده از متغیر هشت بیتی برای این پردازنده های هشت بیتی کارامد تر هستش نسبت به استفاده از متغییر 16 بیتی . پس اینجا هم چون میکروی مورد نظرمون 32 بیتی هست ، اسفاده از int کار امد تر هست. انشاا…

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      بله منطق و جواب درستی است 🙂

  • فرزین
    ۱۴ اسفند ۱۳۹۹

    از مقایسه ی اینستراکشن های دوتابع بصورت disassemble شده، میتوان دید که در حلقه ی while موجود در تابع loop_x برای لود کردن متغیر i از حافظه، کم کردن یک واحد از آن و ذخیره ی متغیر درحافظه، علاوه بر دستورات ldrb، strb، cmp که متناظر این دستورات در حلقه ی while موجود در تابع loop_y نیز مشاهده میشود، شاهد دو دستور and هستیم. از انجایی که این حلقه 201 بار اجرا میشود، در تابع loop_x هزینه ی اجرای 402 (201 * 2) دستور and وجود دارد که این هزینه در تابع loop_y وجود ندارد. در نتیجه میتوان گفت که تابع loop_y سریع تر از تابع loop_x اجرا خواهد شد.
    لینک اینستراکشن توابع:
    https://paste.ubuntu.com/p/2JxszDMgxn

    • فرزین
      ۱۵ اسفند ۱۳۹۹

      برای کامپایل و disassemble کردن این توابع بصورت زیر عمل کردم:
      اول برنامه ای نوشتم که در اون فقط دو تابع رو پیاده سازی کردم و تابع main رو صدا زدم(نیازی به فراخوانی توابع در تابع miain نبود). سپس با کامند زیر برنامه رو کامپایل کردم.

      ( arm-none-eabi-gcc –specs=nosys.specs loop.c -o loop.out )

      سپس توسط دو دستور زیر اینستراکشن های توابع رو استخراج کردم و در دو فایل جدا از هم ذخیره کردم.و محتویات دو فایل رو کنار هم ارسال کردم.

      (arm-none-eabi-objdump –no-show-raw-insn –visualize-jumps –disassemble=loop_x ./loop.out > loopx.objdump )

      (arm-none-eabi-objdump –no-show-raw-insn –visualize-jumps –disassemble=loop_y ./loop.out > loopy.objdump )

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      بله درست است 🙂

  • پوریا
    ۱۴ اسفند ۱۳۹۹

    این نیاز به تست روی معماری همون میکرو داره و همچنین وابسته به کامپایلر هستش ولی با فرض اینکه با -O0 کامپایل میکنید zero extension میتونه overhead داشته باشه و لوپ با uint_8 کندتر باشه

  • amirhos_esm
    ۱۴ اسفند ۱۳۹۹

    حلقه دوم سریع تر است
    شاید به این فکر کرده باشید که اگر این کد را در یک سیستم 8 بیتی مانند avr تست کنیم ، کدام حلقه سریع تر است؟ بله حلقه 1 قطعا در این سیستم سریع تر است چون یک تفریق 32 بیتی در یک سیستم 8 بیتی به چند کلاک متوالی نیاز دارد و این کار باعث کند شدن سیستم می شود
    اما در یک سیستم 32 بیتی چی طور ؟ شاید بگید چون سیستم 32 بیتی هست ، پس یک تفریق 32 بیتی را می تونه تو یک کلاک انجام بده . بدین ترتیب پس یک عملیات 8 بیتی رو هم باید در یک کلاک انجام بده . بله جواب درسته . پس چرا دو حلقه بالا باهم متفاوتند ؟
    جواب به قبل تفریق بر می گرده وقتی می خواد پردازنده دیتا رو از رم به ریجستر ها خودش منتقل کنه. می دونید که در stm32 رجیستر های cpu طولشون 32 بیت هستش . پس وقتی یک داده 32 بیتی رو از رم به یکی از رجیستر های cpu منتقل می کنیم در واقع 32 بیت داده رم ، رو 32 بیت داده رجیستر ریخته میشوند. اما اگه دیتا 8 بیتی داشتیم چی ؟ خوب اون دیتا می یاد رو 8 بیت اول ریجستر cpu ریخته میشه . اما تکلیف 24 بیت بعدی چی میشه ؟ آیا تضمینی وجود داره که اونا صفر باشن ( مشکل ایجاد نکنن ) جواب خیر هستش در واقع کد باید کاری کنه که وقتی یک دیتا 8 بیتی از رم به cpu منتقل میشه یک فکری به حال 24 بیت بعدی بکنه اگر دیتا بی علامت باشد باید عملیات zero extention انجام بده یعنی 24 بیته بعدی رو صفر بکنه اما اگر عدد علامت دار باشه باید signed extention بکنه یعنی مثلا عدد 11110001 که برابر -15 هستش به 32 بیت گسترش بده که مقدار در 32 بیت همون -15 بشه ( 0xfffffff1) . این عملیات ها هستن که باعث میشه پردازش یک داده 8 بیتی در سیستم 32 بیتی با سرعت کمتری به نسبت داده 32 بیتی انجام بشه

    در ادامه با تست عملی مشخص شد که حلقه دوم در cortex m3 و با فعال بودن بهینه سازی رو سایز ، حدود 2017 کلاک و حلقه اول با حدود 402 کلاک بیشتر اجرا می شوند.
    چون حلقه 201 بار اجرا می شود و اختلاف 402 تایی کلاک دو حلقه = دو دستور extetion برای گسترش دادن دیتای 8بیتی توسط کامپایلر ایجاد شده است

    خروجی اسمبلی کامپایلر gcc را برای cortex m3
    https://paste.ubuntu.com/p/zX9hfxQHNG/

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      بله درسته – یکی از کامل ترین جواب هایی که دیدم 🙂

  • Ramin
    ۱۴ اسفند ۱۳۹۹

    با عرض سلام خدمت گروه بسیار فعال و ارزشمند سیسوگ.
    من این دو حلقه رو در دیباگر و محیط دیس اسمبلر مشاهده کردم و طبق مطالعه ای که روی دستورات instruction set Cortex انجام دادم
    به این نتیجه رسیدم که loop_y که متغیر آن از نوع int تعریف شده دارای سرعت بیشتریه.
    چون کامپایلر برای تفسیر کدی که از متغیر char استفاده شده میاد از دستورات اسمبلی مربوط به byte استفاده میکنه مثل دسترور STRB و UXTB
    و … تا بتونه با مقادیر به صورت byte کار بکنه در صورتی که تابعی که با متغیر از نوع int تعریف شده چون سایز متغیر 32 بیتیه و چون آدرس دهی در پردازنده ی ما هم 32 بیتی هست خیلی راحت و با دستورات کمتر کامپایلر میتونه کد رو به اسمبلی ترجمه کنه (همچنین حجم کد اسمبلی while در تابعی که از متغیر int استفاده شده بود کمتر از تابعی بود که از متغیر char استفاده شده )
    با تشکر.

  • qwerty13
    ۱۴ اسفند ۱۳۹۹

    تابع اولی سریعتر باید باشه چون Char یک بایتیه ولی int دو بایتی…

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      البته توی میکروی ۳۲ بیتی اینت هم ۳۲ بیت خواهد بود
      و چون رجیسترها و ثبات ها ۳۲ بیتی هستند در واقع حلقه int سریعتر اجرا میشه

  • Keivan_shakerifar
    keivan_shakerifar
    ۱۴ اسفند ۱۳۹۹

    سلام
    من فکر میکنم حلقه ی دوم جواب درست باشه
    چون که متغیر از نوع int برای این منظور مناسب تره
    چون متغیر از نوع char حجم بیشتری از رم رو اشغال میکنه در صورتی که نیازی نیست و متغیر از نوع int برای این حلقه کفایت میکنه

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      این که حلقه دوم سریعتر اجرا میشه درسته ولی متغییر char رم کمتری میگره ها !

  • Amir
    ۱۴ اسفند ۱۳۹۹

    سلام
    با توجه به اینکه هسته از معماری ۳۲ بیت استفاده میکنه و متغیر ها ۳۲ بیتی آدرس دهی میشن، قاعدتا برای تعریف نوع int یا char چهار بایت در نظر گرفته میشه و با توجه به اینکه برای اجرای دستور x– یا y– یه کلاک صرف خواهد شد، سرعت اجرای هر دو تابع برابر خواهد بود.
    ارادتمند.

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      سلام دوست عزیز
      نکته که ای که باید بهش توجه میکردید این هست که متغییرها قرار از توی رم لود بشن و ذخیره بشن
      همین نکته کوچک معادلات رو بهم میریزه 🙂

  • مرتضی کاظمی
    ۱۴ اسفند ۱۳۹۹

    متغیر char هشت بیت و متغیر int شانزده بیت است پس فضای کمتری اشغال میکنه و نصف اونه، اما اگر از میکرو ۳۲ بیتی استفاده کنید فرقی نداره چون در هر کلاک میتونه تا ۳۲ بیت رو پردازش یا منتقل کنه اما اگر از میکرو ۸ بیتی استفاده می‌کردید تفاوت در سرعت وجود داشت و استفاده از char سریعتر بود. زیرا برای خواندن int دوبار مراجعه به ram نیاز بود.

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      در میکروکنترلرهای ۳۲ بیتی متغییر اینت نیز ۳۲ بیت خواهند بود
      درسته که عملیات ریاضی مورد نظر بر روی هر کدام از این متغییرها یک سیکل نیاز داره ولی بارگذاری اونها توی رجیستر پردازنده متفاوت خواهد بود.

  • دانیال حیدری مقدم
    ۱۴ اسفند ۱۳۹۹

    سلام
    جواب سوال حلقه x هست، به دلیل استفاده از char که یک بایتی هستش.

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      اما حلقه y سریعتر اجرا میشه 🙂
      دقیقا به خاطر معماری ۳۲ بیتی پردازنده و ۳۲ بیتی بودن متغییر ذخیره شده !

  • Omid Azadeh
    Omid Azadeh
    ۱۴ اسفند ۱۳۹۹

    من فکر کنم میکرو حلقه ای رو که متغیرش intهستش رو سریعتر تموم میکنه … بخاطر اینکه نیازی نیست متغیر رو cast کنه …بخاطر ۳۲ بیتی بودن میکرو … چون توابع رو هم اگر ورودی و خروجی تابع int باشه سریعتر اجرا میکنه ( فکر کنم از نوشته های خود شما بود ، مطمئن نیستم ) … امید وارم اشتبا نکرده باشم … ممنون … به امید دیدار ….

  • مریم بایرام دوست
    ۱۴ اسفند ۱۳۹۹

    حلقه دوم سریع تر است

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      بله درسته ای کاش دلایل خودتون رو ارائه می کردید.

  • مریم بایرام دوست
    ۱۴ اسفند ۱۳۹۹

    حلقه دوم

  • حسین
    ۱۴ اسفند ۱۳۹۹

    سلام
    من دقیقا از معماری و دستورات اسمبلی STM32 خبر ندارم ولی به صورت کلی به نظرم کد دوم (loop_y) که متغیر از نوع int داره سریع تر هستش. دلیلش هم اینه که STM32 همونطور که از اسمش مشخصه باس 32 بیتی داره و نوع int هم 32 بیت پهنا داره. پس با کمینه کلاک میتونه به متغیر int دسترسی داشته باشه و روی اون عملیات انجام بده. اما در عوض نوع char پهنای 8 بیتی داره و لازمه علاوه بر این که به این متغیر دسترسی پیدا میکنه، محتویات حافظه مجاور رو هم تغییر نده که این خودش احتیاج به پردازش و کلاک بیشتر داره.

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      بله درسته از منطق خوبی استفاده کردید 🙂

  • Omid
    ۱۴ اسفند ۱۳۹۹

    من با میکروکنترلر و کامپایلرش آشنایی ندارم ولی یک حالت اینه که char یک بایت هست پس عملیات کم‌کردنش باید سبک‌تر باشه و سریعتر. حالت دیگه که احتمال بیشتری میدم، اپتیمایز کردن کامپایلر هست که با دیدن nop یا در حقیقت ندیدن هیچ عملیات داخل حلقه، کل اون را با ست کردن i به 0 جایگزین می‌کنه و در عمل دو تا حلقه یک پرفورمنس خواهند داشت.

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      از اونجایی که عملیات باید به شکلی باشه که روی خونه های دیگر حافظه تغییری ایجاد نکنه توی نوع char پس باید کار بیشتری رو انجام بده منطقا و حلقه char کندتر خواهد بود.

  • نیما
    ۱۴ اسفند ۱۳۹۹

    با توجه به اینکه معماری 32 بیتی هست loop_y باید سریع تر باشه . اگر کامپایلر int رو 32 بیتی بگیره و معماری هم 32 بیتی باشه سریعترین ادرسدهی هست

  • علی
    ۱۴ اسفند ۱۳۹۹

    با int سریع تر است چون میکرو stm32 پردازنده ۳۲ بیتی دارد و محاسبات در همان نوع سریع تر از ۸ بیتی است

    • Zeus ‌
      zeus
      ۱۷ اسفند ۱۳۹۹

      جوابتون درسته ولی نه به این دلیل که محاسبات نوع ۳۲ بیتی سریعتره به دلیل که دسترسی به حافظه ۳۲ بیتی سریعتره

پر بحث ترین ها

مسابقه دوم : چالش برنامه نویسی به زبان C

مسابقه دوم : چالش برنامه نویسی به زبان C

مسابقه اول سیسوگ (مسابقه اول: درک سخت افزار) انتقادهای زیادی رو در پی داشت تا جایی که حتی خودمم به نتیجه مسابقه...

Zeus ‌ Zeus ‌
  • 3 سال پیش
راه اندازی LCD گرافیکی Nokia 1661

راه اندازی LCD گرافیکی Nokia 1661

LCD گرافیکی یکی از مهم ترین پارامترهای موجود در طراحی انواع مدارات الکترونیکی پیچیده و حتی ساده است ، نمایش وضعیت و...

Zeus ‌ Zeus ‌
  • 4 سال پیش
ریموت کدلرن و چکونگی دکد کردن آن به همراه سورس برنامه

ریموت کدلرن و چکونگی دکد کردن آن به همراه سورس برنامه

ریموت کنترل امروزه کاربرد زیادی پیدا کرده است؛ از ریموت‌های درب بازکن تا ریموت‌های دزدگیر و کنترل روشنایی همه از یک اصول اولیه پیروی می‌کنند و آن‌هم ارسال اطلاعات به‌صورت بی‌سیم است....

Zeus ‌ Zeus ‌
  • 5 سال پیش
همه چیز درباره ریموت کنترل‌های هاپینگ

همه چیز درباره ریموت کنترل‌های هاپینگ

امنیت همیشه و در همه‌ی اعصار، مقوله‌ی مهم و قابل‌توجه‌ ای بوده و همیشه نوع بشر به دنبال امنیت بیشتر، دست به ابداعات و اختراعات گوناگونی زده است. ریموت کنترل یکی از این اختراعات است. در این مقاله، به بررسی امنیت انواع ریموت‌های کنترل خواهیم پرداخت....

Zeus ‌ Zeus ‌
  • 5 سال پیش
مسابقه سوم: استخراج داده از رشته ها در زبان C

مسابقه سوم: استخراج داده از رشته ها در زبان C

نزدیک به 5 ماه از مسابقه دوم سیسوگ می‌گذره و فکر کردم که بد نیست یک چالش جدید داشته باشیم! البته چالش‌ها...

Zeus ‌ Zeus ‌
  • 2 سال پیش
مسابقه ششم: بزن میکروکنترلر را بسوزون!

مسابقه ششم: بزن میکروکنترلر را بسوزون!

بزنم میکروکنترلر را بسوزونم اونم تو  این شرایط!، طراحی مسابقه از اون چیزی که به نظر می‌رسه سخت‌تر است، باید حواست باشه...

Zeus ‌ Zeus ‌
  • 12 ماه پیش
آموزش قدم به قدم راه اندازی NRF24L01

آموزش قدم به قدم راه اندازی NRF24L01

آموزش قدم به قدم راه اندازی +NRF24L01  با کتابخانه سازگار با انواع میکروکنترلرها و کامپایلرها قبل از اینکه قسمت بشه با ماژول...

رسول خواجوی بجستانی رسول خواجوی بجستانی
  • 3 سال پیش
ساخت ماینر با FPGA و ARM

ساخت ماینر با FPGA و ARM

چند ماهی هست که تب بیت کوین و ارزهای دیجیتال خیلی بالا رفته! چه شد که این پست را نوشتم همانطور که...

Zeus ‌ Zeus ‌
  • 3 سال پیش
کار با ماژول تمام عیار mc60 – قسمت دوم – راه اندازی OpenCPU

کار با ماژول تمام عیار mc60 – قسمت دوم – راه اندازی OpenCPU

در قسمت اول به یکسری اطلاعات کلی ماژول mc60 پرداختیم، با نرم افزار QNavigator کار کردیم و یک هدربرد هم برای کار...

Mahdi.h   Mahdi.h  
  • 3 سال پیش
مسابقه چهارم: کدام حلقه سریع‌تر است؟

مسابقه چهارم: کدام حلقه سریع‌تر است؟

حدود ۷ ماه پیش، مسابقه سوم سیسوگ رو برگزار کردیم و کلی نکته در مورد خواندن رشته‌های ورودی را بررسی کردیم. فکر...

Zeus ‌ Zeus ‌
  • 2 سال پیش
سیـــســـوگ

مرجع متن باز آموزش الکترونیک