演算子と式

演算子と式

文字や文字列には特に重要なものがいくつかあります。これらは俗に演算記号と言われるもので、例として下記があります。

+ – * / %     算術演算子
&& ||         論理演算子
= += *=       文字代入演算子

演算記号は式の中で使用され、適切なオペランドが与えられた時に意味を持ちます。句読点も同様に強調されています。これらは、括弧、中括弧、カンマ、コロン、及びセミコロンです。

操作記号、句読点、及びスペースは、独立した言語要素を分割するのに使用されます。

このセクションには以下のトピックの説明が含まれます。

  • 算術演算子
  • 代入演算子
  • 関係の演算子
  • ブール演算子
  • ビット演算子
  • その他の演算子
  • 優先順位と操作順序

式は 1 つ以上のオペランドと演算記号で構成されています。式は複数行で記述することが出来ます。

例:

a++; b = 10;         // 複数の式が 1 行に記述されている
//—  1 つの式がいくつかの行に分割されている
x = (y * z) /
(w + 2) + 127;

セミコロン( ; )で終了する式が演算子です。

算術演算子

算術演算には加法と乗法の演算が含まれます。

変数の加算                 i = j + 2;
変数の減算                 i = j – 3;
符号の反転                 x = – x;
変数の乗算                 z = 3 * x;
除算                      i = j / 5;
剰余                      minutes = time % 60;
変数に 1 を加算する          i++;
変数に 1 を加算する          ++i;
変数から 1 を減算する         k–;
変数から 1 を減算する         –k;

インクリメントとデクリメント演算は変数だけに適用され、定数に適用することは出来ません。プレインクリメント( ++i )とプレデクリメント( –k )は、この変数が式の中で使用される直前に適用されます。

ポストインクリメント( i++ )とポストデクリメント( k– )は、この変数が式の中で使用された直後に適用されます。

重要事項

int i=5;
int k = i++ + ++i;

上記の式を別のプログラミング環境に移動(例えば Borland C++ から MQL5)すると計算問題が発生することがあります。一般的に、計算の順序はコンパイラの実装に依存します。実際には、ポストデクリメント(ポストインクリメント)を実装する方法は 2 つあります。

  1. 式全体を計算した後、ポストデクリメント(ポストインクリメント)が変数に適用される
  2. 演算時すぐに、ポストデクリメント(ポストインクリメント)が変数に適用される

現在 MQL5 では、1 つ目の計算方法が実装されています。しかし、この知識があっても、その使用法と実験することは推奨されていません。

例:

int a=3;
a++;           // 有効な式
int b=(a++)*3; // 無効な式

代入演算子

与えられた演算を含む式の値が代入後の左のオペランドの値です。

y 変数に x 値を代入                                                             y = x;

以下の演算は、算術演算または論理演算と代入演算を団結します。

y 変数に x を加算                          y += x
y 変数から x を減算                         y -= x;
y 変数 に x を乗算                         y *= x;
y 変数を x で除算                          y /= x;
y 変数を x で除算した残り                     y %= x;
y の 2 進数表現を右に x ビットだけシフトする        y >>= x;
yの 2 進数表現を左に x ビットだけシフトする         y <<= x;
y とx の 2 進数表現の AND ビット演算           y &= x;
y とx の 2 進数表現の OR ビット演算            y |= x;
y とx の 2 進数表現の XOR ビット演算           y ^= x;

ビット演算は整数のみに適用することが出来ます。y 表現の左右への x ビット論理シフトが実行される際には、x 値の 2 進数表現の下 5 桁が使用され、残りは破棄されます。つまりシフトは 0〜31 ビットに行われます。

%= 演算(x のモジュールによっての Y 値)では結果の符号は分割数の符号と同じです。

代入演算子は式の中で複数回使用出来ます。この場合、式の処理は左から右に実行されます。

y=x=3;

まず、変数 x の値が 3 に割り当てられ、その後 y に変数 x の値(すなわち 3 )が割り当てられます。

関係の演算子

論理値の偽( FALSE )は整数のゼロで表されます。一方、論理値の真( TRUE )は任意のゼロ以外の値で表されます。

関係の演算子や論理演算を含む式の値は FALSE( 0)か TRUE(1)です。

a と b が等しければ True      a == b;
a と b が等しくなければ True    a != b;
a が b より小さければ True     a < b;
a が b より大きければ True     a > b;
a が b 以下であれば True      a <= b;
a が b 以上であれば True      a >= b;

2 つの実数 は比較出来ません。一般的に、一見同一である 2 つの数が小数第 15 位の値が異なるために不均等であることがあります。2 つの実数を正しく比較するためには、これらの数の正規化後の差をゼロと比較します。

例:

bool CompareDoubles(double number1,double number2)
{
if(NormalizeDouble(number1-number2,8)==0) return(true);
else return(false);
}
void OnStart()
{
double first=0.3;
double second=3.0;
double third=second-2.7;
if(first!=third)
{
if(CompareDoubles(first,third))
printf(“%.16f and %.16f are equal”,first,third);
}
}
// 結果: 0.3000000000000000  0.2999999999999998   are equal

ブール演算子

論理否定 NOT( ! )

論理否定( ! )の演算対象となる値は算術型でなければなりません。演算対象の値が FALSE( 0 )の場合、結果は TRUE( 1 )になり、演算対象の値が FALSE( 0 )でない場合、結果はFALSE( 0 )になります。

if(!a) Print(“not ‘a'”);

OR( || )の論理演算

x と y の値の OR( || )論理演算。x か y の値が TRUE( null でない)の場合、式の値は TRUE( 1 )になります。その他の場合は FALSE( 0 )になります。

if(x<0 || x>=max_bars) Print(“out of range”);

AND( && )の論理演算

x と y の値の AND( && )論理演算。x と y の値が TRUE( null でない)の場合、式の値は TRUE( 1 )になります。その他の場合は FALSE( 0 )になります。

ブール演算の短判断

いわゆる「短判断」のスキームはブール演算に適用されます。式の結果を正確に推定することが出来る時に式の計算が終了されます。

//+——————————————————————+
//| スクリプトプログラムを開始する関数                                          |
//+——————————————————————+
void OnStart()
{
//— 短判断の 1 つ目の例
if(func_false() && func_true())
{
Print(“Operation &&: You will never see this expression”);
}
else
{
Print(“Operation &&: Result of the first expression is false, so the second wasn’t calculated”);
}
//— 短判断の 2 つ目の例
if(!func_false() || !func_true())
{
Print(“Operation ||: Result of the first expression is true, so the second wasn’t calculated”);
}
else
{
Print(“Operation ||: You will never see this expression”);
}
}
//+——————————————————————+
//| この関数は常に false を返す                                           |
//+——————————————————————+
bool func_false()
{
Print(“Function func_false()”);
return(false);
}
//+——————————————————————+
//| この関数は常に true を返す                                            |
//+——————————————————————+
bool func_true()
{
Print(“Function func_true()”);
return(true);
}

ビット演算子

1 の補数

変数値の1の補数。式の値は、2 進数での各桁で、変数の桁の値が 1 の場合には 0、0 の場合には 1 となります。

b = ~n;

例:

  char a=’a’,b;
b=~a;
Print(“a = “,a, ”  b = “,b);
// 結果:
// a = 97   b = -98

右シフト

x の 2 進数表現が y 桁だけ右にシフトされます。シフトする値が符号なしの型の場合には論理右シフトが行われ、解放された左側のビットはゼロで満たされます。

シフトする値が符号付きの型の場合には算術右シフトが行われ、解放された左側のビットは符号ビットの値で満たされます(数が正であれば符号ビットの値は 0 で数が負であれば符号ビットの値は 1 )。

x = x >> y;

例:

  char a=’a’,b=’b’;
Print(“Before:  a = “,a, ”  b = “,b);
//— 右にシフトする
b=a>>1;
Print(“After:   a = “,a, ”  b = “,b);
// 結果:
// Before:  a = 97   b = 98
// After:   a = 97   b = 48

左シフト

xの 2 進数表現が y 桁だけ左にシフトされ、解放された右側のビットはゼロで満たされます。

x = x << y;

例:

  char a=’a’,b=’b’;
Print(“Before:  a = “,a, ”  b = “,b);
//— 左へシフトする
b=a<<1;
Print(“After:   a = “,a, ”  b = “,b);
// 結果:
// Before:  a = 97   b = 98
// After:   a = 97   b = -62

その他の演算子

インデックス作成 ( [] )

配列の i 番目の要素にアドレス指定された場合、式の値は、i の通し番号を持つ変数の値になります。

例:

array[i] = 3; // 配列の i 番目の要素に 3 を割り当てる

整数のみが配列のインデックスになれます。4 次元以下の配列が使用可能です。それぞれの次元のインデックスは 0 から 次元のサイズ-1 です。例えば、50 の要素からなる1次元配列がある場合には、最初の要素は array[0] と参照され、最後の要素は array[49] となります。

配列の範囲以外のアドレスが指定された場合、実行サブシステムは重大エラーを発生し、プログラムが停止されます。

x1, x2 ,…, xn 引数での関数の呼び出し

各引数は、定数、変数、または対応する型式を表すことが出来ます。渡された引数をコンマで区切って指定し、呼び出された関数名の後ろの丸括弧の中に書く必要があります。

式の値とは、関数によって返される値です。もし、返される値の型が void の場合、関数呼び出しは、代入演算子の右側に配置出来ません。x1,…, xnの表現の実行順は保証されることにご注意ください。

例:

  int length=1000000;
  string a=“a”,b=“b”,c;
//—その他の演算子
int start=GetTickCount(),stop;
long i;
for(i=0;i<length;i++)
{
c=a+b;
}
stop=GetTickCount();
Print(“time for ‘c = a + b’ = “,(stop-start),” milliseconds, i = “,i);

コンマ演算子( , )

コンマで区切られた式は、左から右に実行されます。左式計算の副作用は右側の式を計算する前に現れることがあります。結果の型と値は右の式のものと一致します。受け渡されるパラメータのリスト(上記参照)は例として考えることが出来ます。

例:

for(i=0,j=99; i<100; i++,j–) Print(array[i][j]);

ドット演算子( . ) #

ドット演算子は構造体とクラスの public メンバへのアクセス を直接行うのに使用されます。構文:

構造体型の変数名 . メンバ名

例:

  struct SessionTime
{
string sessionName;
int    startHour;
int    startMinutes;
int    endHour;
int    endMinutes;
} st;
st.sessionName=“Asian”;
st.startHour=0;
st.startMinutes=0;
st.endHour=9;
st.endMinutes=0;

スコープ定義演算子 ( :: ) #

MQL5 プログラムの各関数には独自の実行スコープがあります。例えば、Print() システム関数はグローバルスコープで実行されます。Imported 関数は対応するインポートの範囲で呼び出されます。クラスのメソッド関数は対応するクラスのスコープを持ちます。スコープ解決演算の構文は次の通りです。

[スコープ名]::関数名(パラメータ)

スコープ名の不在は、グローバルスコープを使用する明示的な指示です。スコープ解決演算子がない場合、関数は最も近い範囲で求められます。ローカルスコープ内に関数がない場合、検索はグローバルスコープで行われます。

スコープ解決演算子はクラスメンバの 関数定義にも使用されます。

型 クラス名::関数名(パラメータ)
{
// 関数の本体
}

同名の関数をプログラム内の複数の実行コンテキストから使用すると、曖昧さを引き起こす可能性があります。明示的なスコープを指定せずに呼び出される時の関数の優先順位は次の通りです。

  1. クラスメソッド。指定された名称の関数がクラスに存在しない場合は、次のレベルに移動します。
  2. MQL5関数。MQL5 言語にそのような関数がない場合、次のレベルに移動します。
  3. ユーザ定義のグローバル関数。指定された名称の関数が見つからない場合は、次のレベルに移動します。
  4. インポートされた関数。指定された名称の関数が見つからない場合、コンパイラがエラーを返します。

関数呼び出しのあいまいさを避けるために、常に明示的なスコープ解決演算を使用して関数スコープを指定するべきです。

 

例:

#property script_show_inputs
#import “kernel32.dll”
int GetLastError(void);
#import

class CCheckContext
{
int         m_id;
public:
CCheckContext() { m_id=1234; }
protected:
int         GetLastError() { return(m_id); }
};
class CCheckContext2 : public CCheckContext
{
int         m_id2;
public:
CCheckContext2() { m_id2=5678; }
void       Print();
protected:
int         GetLastError() { return(m_id2); }
};
void CCheckContext2::Print()
{
::Print(“Terminal GetLastError”,::GetLastError());
::Print(“kernel32 GetLastError”,kernel32::GetLastError());
::Print(“parent GetLastError”,CCheckContext::GetLastError());
::Print(“our GetLastError”,GetLastError());
}
//+——————————————————————+
//| スクリプトプログラムを開始する関数                        |
//+——————————————————————+
void OnStart()
{
//—
CCheckContext2 test;
test.Print();
}
//+——————————————————————+

データ型のサイズまたは任意のデータ型オブジェクトのサイズ取得の操作( sizeof ) #

sizeof 演算子を使用すると、識別子または型に対応するメモリのサイズを定義することが出来ます。sizeof 演算の形式は次の通りです。

例:

sizeof(式)

括弧で囲まれた識別子または型名は式として使用することが出来ます。void 型の名称は使用出来ないことにご注意ください。また、識別子は、ビットフィールドに属したり関数名であることは出来ません。

式が静的配列(つまり、最初の次元が指定されている)の名称である場合、結果は配列全体のサイズ(要素数と型の長さの積)です。式が動的配列(つまり、最初の次元が指定されていない)の名称である場合、結果は 動的配列のオブジェクトサイズです。

sizeof が構造体またはクラス型や構造またはクラス型の識別子に適用された場合、結果は構造体またはクラスの実際のサイズです。

例:

  struct myStruct
{
char   h;
int    b;
double f;
} str;
Print(“sizeof(str) = “,sizeof(str));
Print(“sizeof(myStruct) = “,sizeof(myStruct));

サイズは、コンパイル段階で計算されます。

優先順位のルール

以下の表は演算子を同じ優先順位ごとにまとめます。グループは優先順位が高い順に示されています。優先順位のルールは演算子と演算する値の集まりによって決定します。

注意事項: MQL5 言語での演算の優先順位は C ++ で採用されている優先度に対応するため、MQL4 言語での優先順位とは異なります。

演算子

記述

実行順序

()

[]

にて。

関数の呼び出し

配列要素への参照

構造体要素への参照

左から右

!

~

++

(type)

sizeof

論理否定

ビット否定(補数)

符号変換

1 でインクリメント

1 でデクリメント

型キャスト

バイトサイズの決定

右から左

*

/

%

乗算

除算

剰余

左から右

+

加算

減算 

左から右

<<

>>

左シフト

右シフト

左から右

<

<=

>

>=

より小さい

以下

より大きい

以上

左から右

==

!=

等しい

等しくない

左から右

&

AND ビット演算

左から右

^

XOR ビット演算

左から右

|

OR ビット演算

左から右

&&

論理積演算

左から右

||

論理和演算

左から右

?:

条件演算

右から左

=

*=

/=

%=

+=

-=

<<=

>>=

&=

^=

|=

代入

乗算代入

除算代入

剰余代入

加算代入

減算代入

左シフト代入

右シフト代入

ビット論理積代入

ビット排他的論理和代入

ビット論理和代入

右から左

,

コンマ

左から右

演算の実行順序を変更するには、より高い優先順位を持つものに括弧を使用します。

Originally posted 2019-07-27 10:03:30.

Leave a Reply

Your email address will not be published. Required fields are marked *

CAPTCHA


You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">