زبان برنامه نویسی D بخش پنجم

مقادیر واسطه ممیز شناور

در بسیاری کامپیوترها ،‌اعمال با دقت بالا بیشتر از اعمال با دقت کمتر وقت نمی گیرند
.این باعث می شوند که مفاهیم شمارشی بالاترین دقت ممکن را برای اعمال داخلی موقتی به کار ببرند . فلسفه مورد بحث این نیست که زبان را به پائین مقسوم علیه سخت افزاری محدود کنیم بلکه آن را قادر به بهره‌برداری از بهترین توانایی های سخت افزار مورد نظر نماییم .
برای اعمال ممیز شناور و مقادیر واسطه دستورات یک دقت بالاتر می تواند به کار رود . تنها حد پایین دقت توسط نوع عملوندها مشخص می شود نه حد بالای آن . نکته پیاده سازی : در ماشین های اینتل x 86 برای نمونه انتظار می رود ( اما لازم نیست ) که محاسبات واسطه ای در دقت کامل هشتاد بیتی که توسط سخت افزار پیاده سازی می شود انجام شود .
امکان دارد که در مسیر استفاده از مقادیر موقت و زیر عبارات معمول ، کد بهینه شده یک جواب دقیقتر از کد بهینه نشده فراهم سازد .
الگوریتم ها باید طوری نوشته شود که براساس حداقل دقت محاسبات کار کند .‌ آنها نباید در مواقعی که دقت واقعی بالاتر است افت عملکرد یابند یا شکست بخورند . انواع double یا float برخلاف نوع گسترش یافته فقط باید در موارد زیر به کار رود :

  1. ۱. کاهش مصرف حافظه برای آرایه های بزرگ .
    ۲. داده ها و آرگومان های توابع سازگار با C .

<DD DIR="RTL" STYLE="margin-bottom: 0.5cm; text-align: right">

انواع موهومی و مختلط

در زبان های موجود ، یک تلاش عجیب برای به زور جا دادن انواع مختلط در تسهیلات تعریف نوع موجود مانند قالب ها ،‌ساختمان ها و … وجود داردو تمام این ها معمولاً در نهایت با شکست مواجه می‌شود.
شکست می خورند چون مفاهیم اعمال مختلط می تواند بسیار دقیق باشد و کامپایلر نمی داند که برنامه نویس در تلاش برای انجام چه کاری است بنابراین نمی تواند پیاده سازی معنایی را بهینه نماید .
تمام این کارها برای اجتناب از اضافه کردن یک نوع جدید انجام شده است . اضافه کردن یک نوع جدید بدین معناست که کامپایلر می تواند تمامی مفاهیم اعمال مختلط را دقیق پیاده کند . پس برنامه نویس می تواند بر یک پیاده سازی صحیح ( یا حداقل دارای ثبات ) اعداد مختلط اعتماد کند .
همراه بودن با یک بسته نوع مختلط برای یک نوع موهومی مورد نیاز است .یک نوع موهومی برخی از پیامدهای ظریف معنایی را حذف می کند و کارآیی را بهبود می بخشد بدون اینکه مجبور به انجام اعمال اضافی روی قسمت حقیقی واضح صفر ، باشیم . الفاظ موهومی دارای یک پسوند i می باشند .
imaginary j = 1.3 i ;
هیچ املای خاص برای نوع مختلط وجود ندارد فقط یک نوع حقیقی و موهومی را با هم جمع کنید :
complex c= 4.5 + 2i ;
افزودن دو نوع جدید به زبان کافی است از این رو انواع مختلط و موهومی دارای دقت توسعه یافته هستند . هیچ نوع اعشاری مختلط و موهومی یا نوع دابل مختلط یا موهومی وجود ندارد ( توجه : راه برای افزودن آنها در آینده باز است ) .
اعداد مختلط دارای دو صفت خاصه هستند :
قسمت حقیقی را به عنوان گسترش یافته بدست می دهد // .re قسمت موهومی را به عنوان عدد موهومی بدست می دهد // .im برای مثال :‌

c . re is 4.5
c . im is 2i


کنترل گرد کردن

حسابگر ممیز شناور IEEE 754 شامل توانایی تنظیم کردن چهار روش گرد کردن است . D املایی خاص برای دسترسی به آنها افزوده است : [ blah , blah , blah ]


پرچمهای استثناء

حسابگر ممیز شناور IEEE 754 می تواند پرچمهای مختلف را براساس آن چه در یک محاسبه رخ داده است تنظیم نماید : [ blah , blah , blah ]. این پرچمها می توانند به وسیله املای زبان SET / Reset شوند .


مقایسه های ممیز شناور

علاوه بر عملگرهای مقایسه معمولی < , < = , > , >= , == , != زبان D تعداد بیشتری که خاص اعداد ممیز شناور است اضافه می کند .
مدیریت حافظه

هر برنامه غیر جزیی نیاز به تخصیص و آزاد سازی حافظه دارد . هر چه پیچیدگی ، اندازه و کارآیی برنامه ها افزایش می یابد تکنیکهای مدیریت حافظه مهمتر می شوند . D اختیارات متعددی در زمینه مدیریت حافظه پیشکش می کند .


سه روش پایه تخصیص حافظه در D :
۱. داده استاتیک : در سگمنت داده پیش فرض تخصیص می یابند .
۲. داده پشته : در پشته برنامه CPU تخصیص می یابند .
۳. داده زباله جمع آوری شده :‌ به صورت پویا در heap جمع آوری زباله تخصیص می یابند .
قسمت بعدی تکنیک ها را برای استفاده از آنها توضیح می دهد به همراه برخی قابلیت های پیشرفته:
رشته ها ( و آرایه ها ) copy – on – write
فرستادن یک آرایه به یک تابع را در نظر بگیرید و احتمالاً‌ تغییر دادن آرایه و برگرداندن آرایه جدید . از آنجا که آرایه ها با ارجاع فرستاده می شوند نه با مقدار ، یک پیامد وخیم این است که ندانیم محتویات آرایه از آن کیست ؟ برای مثال تابعی که آرایه ای از کاراکترها را به حروف بزرگ برمی گرداند .
char [] toupper ( char [] s ) { int i ; for ( i =0 ; i < s . length ; i ++ ){ char c = s[i]; if ('a' <= c && c <= 'z') s[i] = c - (cast(char)'a' - 'A'); } return s; }
توجه کنید که نسخه []S که فراخوانی شد تغییر هم کرد شاید این اصلاً آن چیز مورد توقع نبود یا بدتر آنکه []S ممکن است تکه ای از حافظه فقط خواندنی باشد .
اگر یک کپی از S همواره توسط تابع ساخته می شد به طور ناکارا و بدون لزوم ،زمان و حافظه برای حروفی که خودشان بزرگ هستند مصرف می شد .
راه حل پیاده سازی copy – on – write است که یعنی یک کپی ساخته می شود فقط اگررشته ها نیاز به تغییر دارند . بعضی زبان های پردازنده رشته ها این عمل را به عنوان پیش فرض انجام می دهند اما هزینه بسیار سنگین است .
در نتیجه آن رشته “abcdwF” پنج مرتبه بوسیله تابع کپی می شود. برای اینکه از این قرارداد به نحوی با حداکثر کارآیی استفاده شود باید به صورت واضح در کد ظاهر شود .
char [] toupper (char [] s) { int changed ; int i ; changed = 0 ; for (i=0 ; i <s.length ; i ++ ){ char c = s[i ] ; if (‘a’ <= c && c<= ‘z’ ){ if ( ! changed ){ char [] r = new char [ s.length] ; r []= s ; changed = 1 ; } s [i] = c – ( cast ( char ) ‘a’ – ‘A’ ); } } return s ; }
copy – on – write پروتکلی است که به وسیله توابع پردازش آرایه ها در کتابخانه ی زمان اجرای phibo زبان D پیاده سازی شده است .


جمع آوری زباله

D زبانی دارای جمع آوی زباله کامل می باشد . بدین معنی که هیچ وقت نیاز به آزادسازی حافظه نیست . فقط به هنگام نیاز حافظه را تخصیص دهید و جمع آور زباله به طور دوره ای تمام حافظه بی استفاده را به توده حافظه آزاد برمی گرداند .
برنامه نویسان C ++ , C که به کنترل دستی حافظه هنگام تخصیص و آزاد سازی آن عادت دارند احتمالاً به مزایا و تأثیر جمع آوری زباله یقین ندارند . تجربه‌ی پروژه های جدید که با در نظر گرفتن جمع آوری زباله نوشته شده اند همچنین پروژه های موجود که به سبک جمع آوری زباله برگردانده شده اند نشان می دهد که :

  1. ۱. برنامه های دارای جمع آور زباله سریعتر هستند . این واضح است اما دلایلی قابل بیان است .
    ۲. شمارش در جاعات یک روش معمول برای حل مسائل تخصیص حافظه آشکار است . کد پیاده سازی اعمال اضافه و تفریق هر جا که انتساب صورت می گیرد یکی از دلایل کندی است .
    ۳.پنهان کردن کد مذکور در پس کلاسهای اشاره گر هوشمند به افزایش سرعت کمک نمی کند . ( روش شمارش ارجاعات به هیچ وجه راه حل عمومی نیست جایی که ارجاعات حلقه ای هرگز حذف نمی شوند . )
    ۴. مخرب های کلاس برای آزادسازی منابع مورد نیاز یک شیئ به کار می رود . برای اغلب کلاسها این منابع ، حافظه تخصیص یافته است . با جمع آوری زباله اغلب مخرب ها خالی می شوند و در نهایت می توانند دور انداخته شوند .
    ۵. تمام مخرب هایی که حافظه را آزاد می کنند می توانند معنی دار شوند در مواقعی که اشیاء ، بر روی پشته تخصیص حافظه می یابند . برای هر کدام مکانیزمی باید در نظر گرفته شود طوری که اگر یک استثناء رخ داد تمام مخربها از هر چارچوب فراخوانی شوند تا هر حافظه تخصیص یافته برای آنها را رها کنند . اگر مخرب ها نامربوط شوند هیچ نیازی برای در نظر گرفتن چارچوب های خاص پشته برای پردازش استثناها نیست در نتیجه کد سریعتر اجرا می شود .
    ۶. تمام کدهای لازم برای مدیریت حافظه می تواند برای تکامل جزیی اضافه شود . برنامه بزرگتر کمتر در حافظه اصلی و بیشتر آن در حافظه مجازی قرار می گیرد و آرامتر و کندتر اجرا می شود .
    ۷. جمع آور حافظه هنگامی صورت می گیرد که حافظه تنگ و کم شود . تا وقتی حافظه جا دارد برنامه در حداکثر سرعت ممکن اجرا میشود و هیچ وقتی برای آزاد کردن حافظه ، صرف نمی کند .
    ۸.جمع آورنده های زباله مدرن ، اکنون به مراتب پیشرفته تر و سریع تر هستند . جمع آورنده های تولید کننده و کپی کننده ، قسمت عمده ناکارایی الگوریتم های جارو کردن و اختصاص دادن را حذف می کنند .
    ۹.جمع آورنده های زباله مدرن فشرده سازی توده حافظه را انجام می دهند . فشرده سازی توده مراقب است که تعداد صفحاتی که به طور فعال به وسیله یک برنامه ارجاع شده اند را کاهش دهد بدین معنی که دسترسی های حافظه احتمالاً بیشتر به حافظه می رسند تا به مبادله حافظه .
    ۱۰. جمع آورنده های زباله حافظه استفاده شده را اصلاح می کنند . بنابراین به رخنه های حافظه - که باعث می شوند برنامه های با اجرای طولانی مدت آن قدر حافظه مصرف کننده تا سیستم هنگ کند- تن در نمی دهد .
    ۱۱. برنامه های دارای جمع آور زباله دارای اشکالات کمتر یافتن اشاره گرها می باشند به این خاطر که هیچ ارجاع سرگردان به حافظه آزاد شده نمی ماند .
    ۱۲. برنامه های دارای جمع آور زباله برای گسترش و اشکال زدایی سریعترند . چون هیچ نیازی برای گسترش ، اشکال زدایی ، امتحان ، یا ابقاء کد آزاد سازی حافظه دستی وجود ندارد .
    ۱۳. برنامه های دارای جمع زباله به طور معنی داری کوچکترند چون هیچ کد آزادسازی حافظه وجود ندارد و از این رو نیازی به پردازشگرهای استثناها برای آزاد سازی حافظه وجود ندارد .
    جمع آوی زباله یک نوشداروی همه کاره نیست بعضی اشکالات هم دارد :
    ۱. وقتی یک مجموعه برنامه همزمان اجرا می شود قابل پیشگویی نیست بنابراین برنامه به طور دلخواه می تواند مکث کند.
    ۲. زمانی که برای اجرای یک مجموعه مصرف می شود نامحدود است با اینکه در عمل بسیار کوتاه است اما ضمانتی وجود ندارد .
    ۳. تمام رشته های اجرا به غیر از رشته جمع آوری زباله در حالی که جمع آوری در جریان است باید مکث کند .