مبانی زبان MQL5 _ بخش 3
در سومین مقاله آموزش زبان mql از سری مقالات مرتبط با برنامه نویسی در بازارهای مالی به شرح و بررسی «انواع دادهها در زبان MQL5» میپردازیم. در مقاله پیشین به شرح «برخی از انواع دادهها در زبان MQL5» پرداختیم. و در این بخش موارد را پی میگیریم.
– – –
مبانی زبان MQL5 و اعداد اعشاری (floating-point numbers)
عدد حقیقی (Real Types)
مقادیری را با یک قسمت کسری نشان می دهند. در زبان MQL5 دو نوع داده برای اعداد اعشاری وجود دارد. روش نمایش اعداد حقیقی در حافظه کامپیوتر توسط استاندارد IEEE 754 تعریف شده است و مستقل از پلتفرمها، سیستمعاملها یا زبانهای برنامه نویسی است.
نام double به این معنی است که دقت این اعداد دو برابر دقت اعداد float است.؛ در بیشتر موارد، نوع double مناسبترین نوع داده است. در بسیاری از موارد دقت محدود اعداد float کافی نیست. دلیل اینکه هنوز از نوع float استفاده می شود ذخیره حافظه است (این نکته برای آرایههای بزرگ اعداد حقیقی نکتهی حائز اهمیتی است).
ثابتهای اعشاری از یک قسمت صحیح، یک نقطه (.) و یک قسمت کسری تشکیل شدهاند. قسمتهای اعداد صحیح و کسری دنبالهای از ارقام اعشاری هستند.
double a=12.111; double b=-956.1007; float c =0.0001; float d =16;
یک روش علمی برای نوشتن ثابتهای حقیقی وجود دارد، اغلب این روش ضبط فشردهتر از روش سنتی است.
double c1=1.12123515e-25; double c2=0.000000000000000000000000112123515; // 24 zero after the decimal point Print("1. c1 =",DoubleToString(c1,16)); // Result: 1. c1 = 0.0000000000000000 Print("2. c1 =",DoubleToString(c1,-16)); // Result: 2. c1 = 1.1212351499999999e-025 Print("3. c2 =",DoubleToString(c2,-16)); // Result: 3. c2 = 1.1212351499999999e-025
باید به خاطر داشت که اعداد حقیقی با دقت محدودی در سیستم باینری در حافظه ذخیره میشوند، در حالی که به طور کلی از نماد اعشاری استفاده میشود. به همین دلیل است که بسیاری از اعدادی که دقیقاً در سیستم اعشاری نشان داده میشوند را می توان فقط به عنوان یک کسر نامتناهی در سیستم دودویی نوشت.
به عنوان مثال، اعداد 0.3 و 0.7 در رایانه به صورت کسرهای بینهایت نشان داده می شوند، در حالی که عدد 0.25 دقیقاً ذخیره می شود، زیرا نشان دهنده توان دو است.
در این رابطه اکیداً توصیه میشود که دو عدد حقیقی را برای برابری با هم مقایسه نکنید، زیرا چنین مقایسهای صحیح نیست.
void OnStart() { //--- double three=3.0; double x,y,z; x=1/three; y=4/three; z=5/three; if(x+y==z) Print("1/3 + 4/3 == 5/3"); else Print("1/3 + 4/3 != 5/3"); // Result: 1/3 + 4/3 != 5/3 }
اگر هنوز نیاز به مقایسه برابری دو عدد واقعی دارید، میتوانید این کار را به دو روش مختلف انجام دهید. راه اول مقایسه تفاوت بین دو عدد با مقدار کمی است که دقت مقایسه را مشخص میکند.
bool EqualDoubles(double d1,double d2,double epsilon) { if(epsilon<0) epsilon=-epsilon; //--- if(d1-d2>epsilon) return false; if(d1-d2<-epsilon) return false; //--- return true; } void OnStart() { double d_val=0.7; float f_val=0.7; if(EqualDoubles(d_val,f_val,0.000000000000001)) Print(d_val," equals ",f_val); else Print("Different: d_val = ",DoubleToString(d_val,16)," f_val = ",DoubleToString(f_val,16)); // Result: Different: d_val= 0.7000000000000000 f_val= 0.6999999880790710 }
توجه داشته باشید که مقدار epsilon در مثال بالا نمیتواند کمتر از ثابت از پیش تعریف شده DBL_EPSILON باشد. مقدار این ثابت 2.2204460492503131e-016 است.
ثابت مربوط به نوع عدد اعشاری FLT_EPSILON = 1.192092896e-07 است. معنای این مقادیر به شرح زیر است: کمترین مقداری است که شرط 1.0 + DBL_EPSILON را برآورده میکند! = 1.0 (برای اعداد از نوع شناور 1.0 + FLT_EPSILON! = 1.0).
راه دوم مقایسه تفاوت نرمال شده دو عدد واقعی با صفر را ارائه میدهد. مقایسه تفاوت اعداد نرمال شده با صفر بی معنی است، زیرا هر عملیات ریاضی با اعداد نرمال شده یک نتیجه غیر عادی میدهد.
bool CompareDoubles(double number1,double number2) { if(NormalizeDouble(number1-number2,8)==0) return(true); else return(false); } void OnStart() { double d_val=0.3; float f_val=0.3; if(CompareDoubles(d_val,f_val)) Print(d_val," equals ",f_val); else Print("Different: d_val = ",DoubleToString(d_val,16)," f_val = ",DoubleToString(f_val,16)); // Result: Different: d_val= 0.3000000000000000 f_val= 0.3000000119209290 }
برخی از عملیات پردازنده کمکی ریاضی می تواند منجر به عدد واقعی نامعتبر شود که نمیتوان از آن در عملیات ریاضی و عملیات مقایسه استفاده کرد، زیرا نتیجه عملیات با اعداد واقعی نامعتبر تعریف نشده است. به عنوان مثال، هنگام تلاش برای محاسبه آرکسین 2(arcsine of 2)، نتیجه بینهایت منفی است.
double abnormal = MathArcsin(2.0); Print("MathArcsin(2.0) =",abnormal); // Result: MathArcsin(2.0) = -1.#IND
علاوه بر بینهایت منفی، بینهایت مثبت و NaN (not a number) نیز وجود دارد. برای تعیین این که این عدد نامعتبر است، میتوانید از ()MathIsValidNumber استفاده کنید. طبق استاندارد IEEE، آنها یک نمایندگی ماشین ویژه دارند. به عنوان مثال، مثبت بینهایت برای double دارای نمایش بیت 0x7FF0 0000 0000 0000 است.
struct str1 { double d; }; struct str2 { long l; }; //--- Start str1 s1; str2 s2; //--- s1.d=MathArcsin(2.0); // Get the invalid number -1.#IND s2=s1; printf("1. %f %I64X",s1.d,s2.l); //--- s2.l=0xFFFF000000000000; // invalid number -1.#QNAN s1=s2; printf("2. %f %I64X",s1.d,s2.l); //--- s2.l=0x7FF7000000000000; // greatest non-number SNaN s1=s2; printf("3. %f %I64X",s1.d,s2.l); //--- s2.l=0x7FF8000000000000; // smallest non-number QNaN s1=s2; printf("4. %f %I64X",s1.d,s2.l); //--- s2.l=0x7FFF000000000000; // greatest non-number QNaN s1=s2; printf("5. %f %I64X",s1.d,s2.l); //--- s2.l=0x7FF0000000000000; // Positive infinity 1.#INF and smallest non-number SNaN s1=s2; printf("6. %f %I64X",s1.d,s2.l); //--- s2.l=0xFFF0000000000000; // Negative infinity -1.#INF s1=s2; printf("7. %f %I64X",s1.d,s2.l); //--- s2.l=0x8000000000000000; // Negative zero -0.0 s1=s2; printf("8. %f %I64X",s1.d,s2.l); //--- s2.l=0x3FE0000000000000; // 0.5 s1=s2; printf("9. %f %I64X",s1.d,s2.l); //--- s2.l=0x3FF0000000000000; // 1.0 s1=s2; printf("10. %f %I64X",s1.d,s2.l); //--- s2.l=0x7FEFFFFFFFFFFFFF; // Greatest normalized number (MAX_DBL) s1=s2; printf("11. %.16e %I64X",s1.d,s2.l); //--- s2.l=0x0010000000000000; // Smallest positive normalized (MIN_DBL) s1=s2; printf("12. %.16e %.16I64X",s1.d,s2.l); //--- s1.d=0.7; // Show that the number of 0.7 - endless fraction s2=s1; printf("13. %.16e %.16I64X",s1.d,s2.l); /* 1. -1.#IND00 FFF8000000000000 2. -1.#QNAN0 FFFF000000000000 3. 1.#SNAN0 7FF7000000000000 4. 1.#QNAN0 7FF8000000000000 5. 1.#QNAN0 7FFF000000000000 6. 1.#INF00 7FF0000000000000 7. -1.#INF00 FFF0000000000000 8. -0.000000 8000000000000000 9. 0.500000 3FE0000000000000 10. 1.000000 3FF0000000000000 11. 1.7976931348623157e+308 7FEFFFFFFFFFFFFF 12. 2.2250738585072014e-308 0010000000000000 13. 6.9999999999999996e-001 3FE6666666666666 */
نوع رنگ (Color Type)
Color Type برای ذخیره اطلاعات مربوط به رنگ در نظر گرفته شده است.
4 بایت در حافظه اشغال میکند. بایت اول نادیده گرفته میشود، 3 بایت باقی مانده شامل اجزای RGB است.
ثابتهای رنگی را میتوان به سه روش نشان داد:
- به صورت literal
- به صورت integer
- با نام (فقط Web-colors)
نمایش literal شامل سه بخش است که مقادیر نرخ عددی سه جزء اصلی رنگ را نشان میدهد: قرمز، سبز، آبی. ثابت با C شروع می شود و در یک ‘ قرار میگیرد. مقادیر نرخ عددی هر جزء رنگی در محدودهی 0 تا 255 قرار دارد.
نمایش با مقدار صحیح به شکل عدد هگزادسیمال یا اعشاری نوشته می شود. یک عدد هگزادسیمال شبیه 0x00BBGGRR است، که در آن RR نرخ جزء رنگ قرمز، GG مربوط به میزان رنگ سبز و BB نمایانگر میزان رنگ آبی است. ثابت های اعشاری مستقیماً در RGB منعکس نمیشوند. آنها یک مقدار اعشاری از نمایش عدد صحیح هگزادسیمال را نشان میدهند.
رنگهای خاص مجموعه به اصطلاح رنگهای وب را منعکس میکنند.
//--- Literals C'128,128,128' // Gray C'0x00,0x00,0xFF' // Blue //color names clrRed // Red clrYellow // Yellow clrBlack // Black //--- Integral representations 0xFFFFFF // White 16777215 // White 0x008000 // Green 32768 // Green
نوع زمان (Datetime Type)
نوع datetime برای ذخیره تاریخ و زمان به عنوان تعداد ثانیههای سپری شده از 01 ژانویه 1970 در نظر گرفته شده است. این نوع 8 بایت حافظه را اشغال میکند.
ثابتهای تاریخ و زمان را میتوان به عنوان یک literal string نشان داد که از 6 قسمت تشکیل شده است که مقدار عددی سال، ماه، روز (یا روز، ماه، سال)، ساعت، دقیقه و ثانیه را نشان میدهد. ثابت در یک علامت نقل قول قرار میگیرد و با کاراکتر D شروع می شود.
مقادیر از 1 ژانویه 1970 تا 31 دسامبر 3000 متغیر است. تاریخ (سال، ماه، روز) یا زمان (ساعت، دقیقه، ثانیه)، یا همه با هم میتوانند حذف شوند.
با مشخصات literal date، مطلوب است که سال، ماه و روز را مشخص کنید. در غیر این صورت کامپایلر یک هشدار در مورد یک ورودی ناقص(an incomplete entry) برمیگرداند.
datetime NY=D'2015.01.01 00:00'; // Time of beginning of year 2015 datetime d1=D'1980.07.19 12:30:27'; // Year Month Day Hours Minutes Seconds datetime d2=D'19.07.1980 12:30:27'; // Equal to D'1980.07.19 12:30:27'; datetime d3=D'19.07.1980 12'; // Equal to D'1980.07.19 12:00:00' datetime d4=D'01.01.2004'; // Equal to D'01.01.2004 00:00:00' datetime compilation_date=__DATE__; // Compilation date datetime compilation_date_time=__DATETIME__; // Compilation date and time datetime compilation_time=__DATETIME__-__DATE__;// Compilation time //--- Examples of declarations after which compiler warnings will be returned datetime warning1=D'12:30:27'; // Equal to D'2024 12:30:27' datetime warning2=D''; // Equal to __DATETIME__
نوع Enumerations
داده های نوع enum متعلق به مجموعه ای محدود از داده ها هستند.
تعریف نوع شمارش:
enum name of enumerable type { list of values };
لیست مقادیر لیستی از شناسههای ثابتهای نامگذاری شده است که با کاما از هم جدا شدهاند.
enum months // enumeration of named constants { January, February, March, April, May, June, July, August, September, October, November, December };
پس از تعریف enum، یک نوع داده 4 بایتی جدید با عدد صحیح ظاهر میشود. تعریف نوع داده جدید به کامپایلر اجازه میدهد تا انواع پارامترهای ارسال شده(passed parameters) را به دقت کنترل کند، زیرا enum ثابتهای نامگذاری شده جدیدی را معرفی می کند. در مثال بالا، ثابت ژانویه دارای مقدار 0، فوریه – 1، دسامبر – 11 است.
قانون: اگر مقدار معینی به ثابت نامگذاری شده که عضوی از enum است اختصاص داده نشود، مقدار جدید آن به طور خودکار تشکیل می شود.
- اگر اولین عضو شمارش باشد، مقدار 0 به آن اختصاص داده می شود.
- برای همه اعضای بعدی، مقادیر بر اساس ارزش اعضای قبلی با اضافه کردن یک محاسبه می شود.
enum intervals // Enumeration of named constants { month=1, // Interval of one month two_months, // Two months quarter, // Three months - quarter halfyear=6, // Half a year year=12, // Year - 12 months };
برخلاف ++c، اندازه نمایش داخلی enum در MQL5 همیشه برابر با 4 بایت است. یعنی sizeof (months) مقدار 4 را برمیگرداند.
بر خلاف ++c، یک enum ناشناس را نمیتوان در MQL5 تعریف کرد. یعنی همیشه باید بعد از کلمه کلیدی enum یک نام منحصر به فرد مشخص شود.
هگزادسیمال(Hexadecimal)
اعداد 0-9، حروف a-f یا A-F برای مقادیر 10-15. با 0x یا 0X شروع میشوند.
// 0x0A, 0x12, 0X12, 0x2f, 0xA3, 0Xa3, 0X7C7 //
برای متغیرهای عدد صحیح، مقادیر را میتوان به صورت باینری با استفاده از پیشوند B تنظیم کرد. به عنوان مثال، میتوانید ساعات کاری یک جلسه معاملاتی را در متغیر نوع int رمزگذاری کنید و از اطلاعات مربوط به آنها مطابق الگوریتم مورد نیاز استفاده کنید:
//+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- set 1 for working hours and 0 for nonworking ones int AsianSession =B'111111111'; // Asian session from 0:00 to 9:00 int EuropeanSession=B'111111111000000000'; // European session 9:00 - 18:00 int AmericanSession =B'111111110000000000000011'; // American session 16:00 - 02:00 //--- derive numerical values of the sessions PrintFormat("Asian session hours as value =%d",AsianSession); PrintFormat("European session hours as value is %d",EuropeanSession); PrintFormat("American session hours as value is %d",AmericanSession); //--- and now let's display string representations of the sessions' working hours Print("Asian session ",GetHoursForSession(AsianSession)); Print("European session ",GetHoursForSession(EuropeanSession)); Print("American session ",GetHoursForSession(AmericanSession)); //--- } //+------------------------------------------------------------------+ //| return the session's working hours as a string | //+------------------------------------------------------------------+ string GetHoursForSession(int session) { //--- in order to check, use AND bit operations and left shift by 1 bit <<=1 //--- start checking from the lowest bit int bit=1; string out="working hours: "; //--- check all 24 bits starting from the zero and up to 23 inclusively for(int i=0;i<24;i++) { //--- receive bit state in number bool workinghour=(session&bit)==bit; //--- add the hour's number to the message if(workinghour )out=out+StringFormat("%d ",i); //--- shift by one bit to the left to check the value of the next one bit<<=1; } //--- result string return out; }
عدد مختلط (Complex number)
ساختار از پیش تعریفشدهای است که از دو بخش double تشکیل شده است.
struct complex { double real; // Real part double imag; // Imaginary part };
عدد مختلط را می توان به صورت passed by value به عنوان پارامتری برای توابع MQL5 ارسال کرد (بر خلاف ساختارهای معمولی که فقط به صورت passed by reference ارسال می شوند). برای توابع import شده از DLL، عدد مختلط باید فقط با passed by reference ارسال شود.
پسوند “i” برای توصیف ثابتهای عدد مختلط استفاده می شود.:
complex square(complex c) { return(c*c); } void OnStart() { Print(square(1+2i)); // A constant is passed as a parameter } // "(-3,4)" will be output, which is a string representation of the complex number
در حال حاضر فقط عملیات ساده برای اعداد مختلط امکان پذیر است:
+ | – | * | / | = | != |
+= | -= | *= | /= | == |
پشتیبانی از توابع ریاضی اضافی بعداً اضافه خواهد شد و امکان محاسبهی قدر مطلق، سینوس، کسینوس و موارد نظیر آن را فراهم خواهد کرد.
در مقالات بعدی آموزش ام کیو ال، مطالب آموزش انواع دادهها را پی گرفته و دیگر مباحث پایه را شرح خواهیم داد.
همچنین میتوانید از سسله مقالات آموزش Python سایت جهان بورس استفاده نمایید.
دیدگاهتان را بنویسید
برای نوشتن دیدگاه باید وارد بشوید.