Technical Article

توابع مهندسی در Delphi: تبدیل مبنا، اعداد مختلط

خانواده توابع مهندسی در Excel مانند ساده‌ترین بخش مرجع توابع به نظر می‌رسند. DEC2BIN یک عدد را به یک رشته باینری تبدیل می‌کند. HEX2DEC آن را برمی‌گرداند. IMSUM دو عدد مختلط را جمع می‌کند. هر کدام شبیه به یک تمرین قالب‌بندی به نظر می‌رسند. اما این‌طور نیست. در پشت این نام‌ها، یک کدگذاری مکمل دو ده بیتی (ten-bit two's complement) قرار دارد که بیشتر توسعه‌دهندگان از زمان کلاس معماری کامپیوتر با آن کار نکرده‌اند، فرمت عدد مختلط که کاملاً در داخل رشته‌ها زندگی می‌کند و اپراتورهای بیتی که در صورت شیفت دادن قبل از بررسی، به طور خاموش سرریز یک عدد صحیح ۶۴ بیتی ایجاد می‌کنند. یک موتور صفحه گسترده که Excel را دقیقاً بازتولید می‌کند، نمی‌تواند هیچ بخشی از آن را نادیده بگیرد.

توابع به سه گروه تقسیم می‌شوند و هر گروه تله متفاوتی را پنهان می‌کند. تبدیل مبنا درباره اعداد منفی و آستانه‌های مربوط به هر مبنا است. محاسبات مختلط در مورد پارس و قالب‌بندی یک رشته است. عملیات بیتی در مورد ماندن در محدوده Int64 است. این مقاله هر گروه را همان‌طور که HotXLS پیاده‌سازی می‌کند، با فراخوانی‌های صفحه کاری که در واقع می‌نویسید، بررسی می‌کند.

تبدیل مبنا و مکمل دو ده بیتی

مسیر مستقیم همان بخشی است که همه انتظار دارند. DEC2BIN(9) مقدار "1001" را می‌دهد و یک آرگومان دوم اختیاری نتیجه را از چپ تا عرض مشخصی پر می‌کند. تله ورودی منفی است. Excel علامت منفی نمی‌نویسد. این برنامه مقدار را به عنوان یک رشته مکمل دو ده رقمی در مبنای هدف کدگذاری می‌کند، به همین دلیل است که DEC2BIN(-5,10) مقدار "1111111011" را برمی‌گرداند تا هر چیز دیگری با علامت. آرگومان مکان‌ها (places) زمانی که مقدار منفی باشد نادیده گرفته می‌شود، زیرا کدگذاری از قبل روی ده رقم پین شده است.

ده رقم یک بودجه ثابت است و آن بودجه محدوده قابل نمایش در هر مبنا را تعیین می‌کند. در باینری، مقداری که به نیمه منفی تغییر می‌کند ۵۱۲ است و پیمانه چرخش ۱۰۲۴ است، بنابراین یک رشته باینری تنها زمانی علامت‌دار است که دقیقاً ده کاراکتر طول داشته باشد و مقدار آن حداقل ۵۱۲ باشد. همین ایده با مبنا مقیاس‌بندی می‌شود. مبنای هشت از آستانه نصف ۲^۲۹ و پیمانه کامل ۲^۳۰ استفاده می‌کند. مبنای شانزده از ۲^۳۹ و ۲^۴۰ استفاده می‌کند. خواننده HotXLS دقیقاً این قانون را اعمال می‌کند: رقم‌ها را جمع می‌کند و تنها زمانی که طول رشته ده کاراکتر باشد و مقدار جمع‌شده در آستانه نصف یا بالاتر قرار گیرد، پیمانه کامل را کم می‌کند تا مقدار علامت‌دار را بازیابی کند. یک رشته نه کاراکتری همیشه غیرمنفی است، بدون توجه به اینکه چقدر بزرگ باشد.

کدگذار تصویر آینه است. یک مقدار غیرمنفی رقم به رقم تبدیل شده و در صورت تمایل با صفر تا عرض درخواستی پر می‌شود و در صورتی که از سقف مثبت مبنا سرریز کند یا اگر عرض درخواستی برای نگهداری آن خیلی باریک باشد، رد می‌شود. یک مقدار منفی ابتدا با افزودن پیمانه کامل به محدوده آورده می‌شود که آن را به مقداری تبدیل می‌کند که نمایش مبنای آن همیشه ده رقم است، و سپس رقم‌ها با صفرهای پیشرو صادر می‌شوند تا عرض را پر کنند. بررسی محدوده مشترک واحد، یعنی باندهای متقارن پایینی و بالایی برای هر مبنا، چیزی است که DEC2BIN ،DEC2OCT و DEC2HEX را در لبه‌هایشان با یکدیگر سازگار نگه می‌دارد.

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

اعداد مختلط رشته هستند، بنابراین کار همان پارس کردن است

برنامه Excel فاقد نوع داده مختلط است. یک مقدار مختلط رشته "a+bi" است و هر تابع در خانواده IM آن رشته‌ها را گرفته و یکی را پس می‌دهد. COMPLEX رشته را از یک بخش حقیقی و یک بخش موهومی می‌سازد. توابع IMSUM ،IMSUB ،IMPRODUCT و IMDIV آرگومان‌های خود را پارس می‌کنند، محاسبات را روی بخش‌های عددی انجام می‌دهند و نتیجه را مجدداً به صورت رشته قالب‌بندی می‌کنند. کار عددی جبر مقدماتی است. سختی کار کاملاً در تبدیل مطمئن متن به دو عدد ممیز شناور است و اینجاست که پارسر داخلی ارزش خود را نشان می‌دهد.

دو جزئیات در آن پارسر به راحتی اشتباه می‌شوند. اولی واحد موهومی خالی است. رشته "i" به معنای یک ضرب در i است، نه صفر و نه خطا، بنابراین وقتی ضریب جلوی پسوند خالی است یا یک علامت مثبت تنها است، پارسر باید آن را به عنوان مقدار ۱ بخواند و یک منفی تنها را به عنوان -۱. این را نادیده بگیرید تا IMSUM("i","i") دیگر 2i نباشد. دومی نماد علمی است که با علامتی که بخش حقیقی و موهومی را جدا می‌کند برخورد می‌کند. پارسر این جداکننده را با اسکن برای مثبت یا منفی پیدا می‌کند، اما عددی که به صورت "1.5E-3" نوشته شده حاوی یک منفی است که به توان تعلق دارد. بنابراین اسکن زمانی که کاراکتر بلافاصله قبل از آن e یا E باشد از برخورد با مثبت یا منفی به عنوان جداکننده خودداری می‌کند. بدون این گارد، بخش حقیقی در علامت توان به دو نیم تقسیم می‌شود و پارس در ورودی کاملاً معتبر شکست می‌خورد.

خود پسوند به جای نرمال شدن حفظ می‌شود. Excel هر دو i و j را می‌پذیرد و HotXLS به یاد می‌آورد که ورودی از کدام یک استفاده کرده است تا نتیجه قالب‌بندی شده همان حرف را حمل کند. قالب‌بندی سپس از میانبرهای متداول استفاده می‌کند: یک بخش موهومی یک فقط به عنوان پسوند چاپ می‌شود، منفی یک به صورت -i، یک بخش موهومی صفر به یک حقیقی ساده خلاصه می‌شود و یک بخش حقیقی صفر، 0+ پیشرو را حذف می‌کند.

var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
begin
  Book := TXLSXWorkbook.Create;
  try
    Sheet := Book.Sheets.Add('Engineering');
    Sheet.Cells[1, 1].Value := Sheet.Calculate('=DEC2BIN(-5,10)');
    Sheet.Cells[2, 1].Value := Sheet.Calculate('=IMPRODUCT("3+4i","1+2i")');
  finally
    Book.Free;
  end;
end;

توابع مختلط فرارونده (transcendental complex functions)، از جمله IMSQRT ،IMEXP ،IMLN و IMPOWER، در مختصات دکارتی کار نمی‌کنند. آن‌ها مقدار پارس شده را به فرم قطبی تبدیل می‌کنند، عملیات را روی قدر مطلق و آرگومان اعمال می‌نمایند و دوباره به حالت قبل بازمی‌گردانند. یک ریشه دوم آرگومان را نصف می‌کند و ریشه قدر مطلق را می‌گیرد. یک توان آرگومان را ضرب می‌کند و قدر مطلق را به توان می‌رساند. انجام آن به هر روش دیگری به معنای مشتق‌گیری مجدد هر اتحاد در فرم دکارتی است که هم کد بیشتری می‌طلبد و هم در نزدیکی نقاط شکست از نظر عددی پایداری کمتری دارد.

اپراتورهای بیتی و سرریزی که باید ابتدا بررسی کنید

برنامه Excel 2013 توابع BITAND ،BITOR ،BITXOR ،BITLSHIFT و BITRSHIFT را اضافه کرد. عملوندها محدود هستند: هر کدام باید یک عدد صحیح غیرمنفی بزرگ‌تر از ۲^۴۸ منهای ۱ نباشند و هر آرگومان اعشاری یا منفی یک خطای عددی است. این سقف به اندازه کافی سخاوتمندانه است تا هر مجموعه پرچم واقعی را پوشش دهد در حالی که کاملاً در محدوده دقیقاً قابل نمایش یک double باقی می‌ماند، که این موضوع مهم است زیرا Excel هر آرگومان عددی را به عنوان یک مقدار ممیز شناور ارسال می‌کند.

توابع شیفت دارای یک قانون ترتیبی هستند که واقعاً مشکل‌ساز است. یک شیفت به چپ می‌تواند مقداری بسیار بزرگ‌تر از ورودی خود ایجاد کند و اگر ابتدا shl را انجام دهید و بعد از آن نتیجه را بررسی کنید، از قبل Int64 سرریز شده و آزمایش بی‌معنی است. بررسی باید قبل از شیفت انجام شود. HotXLS عملوند را با سقفی که به اندازه مقدار شیفت به راست رفته مقایسه می‌کند و تنها در صورتی که عملوند مناسب باشد، شیفت به چپ واقعی را انجام می‌دهد. مقدار شیفت فراتر از ۵۳ِ بیت مستقیماً رد می‌شود و شیفت منفی به سادگی جهت را برعکس می‌کند، بنابراین BITLSHIFT با تعداد منفی مانند یک شیفت به راست رفتار می‌کند. این اصل بسیار فراتر از این یک تابع تعمیم می‌یابد: وقتی گارد برای جلوگیری از سرریز وجود دارد، باید روی ورودی‌ها اجرا شود، نه روی نتیجه‌ای که قرار بود از آن محافظت کند.

// Bitwise calls evaluate the same way through Calculate.
Sheet.Cells[3, 1].Value := Sheet.Calculate('=BITAND(13,11)');    // 9
Sheet.Cells[4, 1].Value := Sheet.Calculate('=BITLSHIFT(5,2)');   // 20
Sheet.Cells[5, 1].Value := Sheet.Calculate('=BITRSHIFT(40,3)');  // 5

توابع آینده و پیشوند نام _xlfn

اپراتورهای بیتی و لیست طولانی از دیگر موارد اضافه شده پس از سال ۲۰۰۷ با یک طرح نام‌گذاری تعامل دارند که هیچ ارتباطی با آنچه محاسبه می‌کنند ندارد و همه چیز به نحوه ذخیره‌سازی آن‌ها توسط Excel مربوط است. فرمت اولیه باینری صفحه کاری به هر تابع داخلی یک اسلات عددی در یک جدول ثابت اختصاص می‌داد. توابعی که پس از فریز شدن آن جدول اختراع شدند اسلاتی ندارند. برای ذخیره چنین تابعی در یک فایل به طوری که یک Excel مدرن آن را تشخیص دهد، نام با یک پیشوند _xlfn. نوشته می‌شود، بنابراین BITAND به صورت _xlfn.BITAND روی دیسک ذخیره می‌شود حتی اگر کاربر فقط BITAND را تایپ کند.

نکته این است که قانون یکنواخت نیست. به برخی از توابع جدیدتر اسلات‌های جدول داده شد و بدون پیشوند نوشته می‌شوند، در حالی که چند تابع پنهان قدیمی نیز علی‌رغم سنشان بدون پیشوند نوشته می‌شوند. HotXLS یک لیست سفید صریح از نام‌هایی که به پیشوند نیاز دارند نگه می‌دارد، آن را در زمان نوشتن اضافه و در زمان خواندن حذف می‌کند، بنابراین متن فرمولی که تنظیم می‌کنید و مجدداً می‌خوانید همیشه نام تمیز و روبه‌روی کاربر Excel است. شما =BITLSHIFT(5,2) را تنظیم می‌کنید، فایل حاوی _xlfn.BITLSHIFT است و مقدار در هر صورت به عنوان ۲۰ بازمی‌گرداند. پیشوند یک جزئیات ذخیره‌سازی است که هرگز نباید به فرمول‌هایی که در کد با آن‌ها کار می‌کنید نفوذ کند.

در کنار هم قرار دادن آن در یک صفحه کاری

سطح عمومی برای همه این موارد کوچک است. یک TXLSXWorkbook ایجاد کنید، یک صفحه کاری اضافه کنید و یا فرمولی را از طریق Cells[Row, Col].Formula در یک سلول بنویسید و دوباره محاسبه کنید، یا عبارتی را مستقیماً با متد Calculate صفحه کاری ارزیابی نمایید که فرمول را در برابر آن صفحه کامپایل کرده و یک Variant برمی‌گرداند. مثال‌های بالا از Calculate استفاده می‌کنند زیرا نتیجه یک فراخوانی مهندسی واحد را بدون حالت صفحه اطراف نشان می‌دهد، اما همین توابع در زمان محاسبه مجدد کتاب کار، در داخل فرمول‌های سلول واقعی کاملاً یکسان ارزیابی می‌شوند.

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

اگر ریاضیات دامنه خود را به همان موتور متصل می‌کنید، مکانیک ثبت یک هندلر و بازگرداندن مقادیر در مقاله ما در مورد گسترش موتور فرمول با توابع سفارشی پوشش داده شده است، و هنگامی که آن فرمول‌ها باید به جای آدرس سلول، بر اساس نام در سراسر صفحات دسترسی داشته باشند، راهنمای نام‌های تعریف شده و فرمول‌های بین‌صفحه‌ای نشان می‌دهد که مراجع چگونه حل می‌شوند. توابع مهندسی توصیف‌شده در اینجا به عنوان بخشی از کامپوننت صفحه گسترده HotXLS برای Delphi و C++Builder در کنار APIهای خواندن، نوشتن و محاسبه که در بخش‌های دیگر این وبلاگ پوشش داده شده‌اند، ارائه می‌شوند.