# データの加工

- 概要
- 数値リテラル
- 定数
- 定数定義
- パラメータ
- 変数
- 配列
- ユーザ定義関数
- 演算子
- 関数
- 演算子の優先順位
- 数式変換の使用例

## 概要

描画は隣接平均, 数式変換などデータの加工を行った後に行われます。 グラフを作成する際その処理手順を意識することが重要な場合があります。 以下にデータの流れを示します。
データ
↓
数式変換
↓
マスクされたデータを削除
↓
移動されたデータを移動
↓
隣接平均
↓
[曲線の補間係数, 最小二乗フィットの係数を求める]
↓
出力(グラフ描画)
ロググラフを作成する場合, 曲線の補間はデータを対数変換した後に行われるので通常の線形グラフとロググラフでは結果が異なります。 最小二乗法に関してはロググラフでも通常の線形グラフと同じ係数を求めます。

## 数式変換で使用できる数値リテラル

1
1.0
1.0E3

  浮動小数点

0xffff

  16進整数

0b1011

  2進整数

0o377

  8進整数

数字が連続している部分は見やすくするため任意の箇所に空白を入れることが出来ます (例 123 456.789 E8) 。

## 数式変換で使用できる定数

PI | 円周率
E | 自然対数の底
EULER | オイラーの定数
NAN | 欠損データ エラー表示
UNDEF | 欠損データ エラー非表示
CONT | 欠損データ (データ線は結合)
BREAK | 欠損データ (データ線は分断)
NUM | データの個数
MINX | (X) column の生データの最小値
MAXX | (X) column の生データの最大値
MINY | (Y) column の生データの最小値
MAXY | (Y) column の生データの最大値
SUMX | (X) column の生データの和
SUMY | (Y) column の生データの和
SUMXX | (X) column の生データの二乗和
SUMYY | (Y) column の生データの二乗和
SUMXY | (X) column, (Y) column の生データの積和
AVX | (X) column の生データの平均
AVY | (Y) column の生データの平均
SGX | (X) column の生データの標準偏差
SGY | (Y) column の生データの標準偏差
FIRST | diagonal, errorbar など一行のデータで2回の変換が行われる場合、1回目の呼出しで真(=1)、2回目の呼出しで偽(=0)
MASK | マスクに設定された行数
MOVE | 移動に設定された行数
COLX | 「X カラム」に指定された数
COLY | 「Y カラム」に指定された数
AXISX | 「X 軸」に指定された axis オブジェクトの ID
AXISY | 「Y 軸」に指定された axis オブジェクトの ID
HSKIP | 「先頭スキップ行」に指定された行数
RSTEP | 「読込ステップ行」に指定された行数
FLINE | 「最終行」に指定された行数
FILE_OBJ | file オブジェクトのオブジェクト ID
PATH_OBJ | path オブジェクトのオブジェクト ID
RECT_OBJ | rectangle オブジェクトのオブジェクト ID
ARC_OBJ | arc オブジェクトのオブジェクト ID
MARK_OBJ | mark オブジェクトのオブジェクト ID
TEXT_OBJ | text オブジェクトのオブジェクト ID
%D | データの番号
%N | データの数

## 定数定義

const x:=exp

x は英字で始まり英数字または _ から構成される文字列、exp は任意の数式。

- 既存の定数は上書きできません。
- 数式 exp は数式変換実行時ではなく構文解析時に解釈されます。
- 数式 exp 中ではパラメータ、関数 sum(), dif() は使用できません。

## 数式変換で使用できるパラメータ

%0 | データを読み込んだ順番に1から番号をつけたときの値
%1〜%999 | 同一行中 1〜999 カラムの生データ
%Fxx1〜%Fxx999 | データ xx の同じ行の 1〜999 カラムの生データ

## 数式変換で使用できる変数

変数は X, Y の変換式で独立です。

E, X, Y 以外のアルファベット一文字 | ユーザが自由に使用できます (代入されていない変数は 0 に初期化されています) 。
X | (X)column の生のデータ (変数への代入は可能ですが、データ読込時に生データで上書きされます)
Y | (Y)column の生のデータ (変数への代入は可能ですが、データ読込時に生データで上書きされます)

## 配列

x[n] | x は英字で始まり英数字または _ から構成される文字列、n は任意の数式。 未代入の配列要素は 0 に初期化されています。 配列の添字は整数に丸められます。 配列の添字の上限は 65535 です。 配列の添字に負の数値を使用した場合、配列の末尾からのインデックスとみなします。

## ユーザ定義関数

def func(a,b,...) {exp}

仮引数 a, b, ... の関数 func を定義します。
配列を渡すときは仮引数を @a の様に指定してください。配列は参照渡しとなります。
exp には任意の数式を指定できますが、以下の制限があります。

- パラメータ (%0, %F0001 など) は使用できません。
- 関数 dif(), sum() は使用できません。
- 関数定義はネストできません。

## 数式変換で使用できる演算子

-+ | 符号
+ - * / | 四則演算
\ | 浮動小数点剰余
^ | ベキ乗
! | 階乗(引数は 169 以下の正の整数)
:= | 代入
-= | 自己代入
+= | 自己代入
*= | 自己代入
/= | 自己代入
\= | 自己代入
^= | 自己代入
== | 比較
!= | 比較
<= | 比較
>= | 比較
< | 比較
> | 比較
&& | 論理積
|| | 論理和

exp1 && exp2 と AND(exp1, exp2) の違い。

  exp1 && exp2 は exp1 が偽の時 exp2 を評価しません。また exp1 が真の場合、exp2 を評価した値を返します。

exp1 || exp2 と OR(exp1, exp2) の違い。

  exp1 || exp2 は exp1 が真の時 exp2 を評価しません。また exp1 が真の場合は exp1、exp1 が偽の場合は exp2 を評価した値を返します。

;

  ; は式の終端を表します(省略可能)。; の後に別の式を後に続けることができます。

括弧 ()

  括弧 () の数に制限はありません。

## 数式変換で使用できる関数

- 引数は省略することが出来ます。引数が省略された場合 0 が渡されます。
- IF() 関数のネスト数、DIF(), SUM() 関数の数の制限はなくなりました。
- 引数は左から評価されます。

### 変換関数

ABS(x) | 絶対値
SIGN(x) | 正負の符号 (x < 0 で -1、x >= 0 で 1)
INT(x) | 0に向かって切捨てた整数部
GAUSS(x) | ガウスの記号[ ] ([n]はnを越えない最大の整数)
FRAC(x) | 小数部
ROUND(x) | 四捨五入した整数部
MIN(a,b,c,...) | 引数のうちもっとも小さな値
MAX(a,b,c,...) | 引数のうちもっとも大きな値

### 初等関数

SQR(x) | 二乗
SQRT(x) | 平方根
EXP(x) | 指数(x≦690)
LN(x) | 自然対数
LOG(x) | 常用対数
SIN(x) | サイン
COS(x) | コサイン
TAN(x) | タンジェント
ASIN(x) | 逆サイン
ACOS(x) | 逆コサイン
ATAN(x) | 逆タンジェント
SINH(x) | ハイパボリックサイン
COSH(x) | ハイパボリックコサイン
TANH(x) | ハイパボリックタンジェント
ASINH(x) | 逆ハイパボリックサイン
ACOSH(x) | 逆ハイパボリックコサイン
ATANH(x) | 逆ハイパボリックタンジェント
FMOD(x, y) | x を y で割った浮動小数点剰余

### 特殊関数

RAND(x) | 0≦RAND(x)＜x (x＞0のとき)の乱数
SRAND(x) | RAND() 関数で作られる疑似乱数系列の新しい種を設定する。
THETA(x) | 階段関数(x≧0 のとき 1, それ以外は 0 )
DELTA(x) | クロネッカーのδ(x=0 のとき 1, それ以外は 0)
GAMMA(x) | ガンマ関数 Γ(x)
ICGAM(m,x) | 不完全ガンマ関数 Γ(μ,x)
ERF(x) | 誤差関数 Erf(x)
ERFC(x) | 相補誤差関数 Erfc(x)
QINV(x) | 誤差関数 Erfc(x) の逆関数
EI(x) | 積分指数関数 Ei(x)
BETA(x,y) | ベータ関数 B(p,q)
ICBETA(x,y) | 不完全ベータ関数 I(a,b,x) (0 <= x <= 1)
JN(n,x) | 第1種n次ベッセル関数
YN(n,x) | 第2種n次ベッセル関数
IN(n,x) | 第1種n次変形ベッセル関数
KN(n,x) | 第2種n次変形ベッセル関数
JL(l,x) | 第1種l次球ベッセル関数
YL(l,x) | 第2種l次球ベッセル関数
JNU(nu,x) | 第1種nu次ベッセル関数 (nu は正の実数)
YNU(nu,x) | 第2種nu次ベッセル関数 (nu は正の実数)
INU(nu,x) | 第1種nu次変形ベッセル関数 (nu は正の実数)
KNU(nu,x) | 第2種nu次変形ベッセル関数 (nu は正の実数)
PN(n,x) | ルジャンドル多項式
LGN(n,a,x) | ラゲール倍多項式
HN(n,x) | エルミート多項式
TN(n,x) | チェビシフ多項式
ZETA(x) | リーマンゼータ関数 ζ(x)
ZETA_INT(x) | リーマンゼータ関数 ζ(x) (x は整数)
ZETAM1(x) | リーマンゼータ関数 ζ(x) - 1
ZETAM1_INT(x) | リーマンゼータ関数 ζ(x) - 1 (x は整数)
CHOOSE(n,m) | the combinatorial factor n choose m: n!/(m!(n-m)!)
MJD(year,month,day,hour,min,sec) | 修正ユリウス日(year, month, day はグレゴリオ暦、hour,min,sec は UTC 時刻、うるう秒は考慮されない)
UNIX2MJD(time) | 修正ユリウス日(time は 1970年1月1日00:00:00 UTC からの経過秒数、うるう秒は考慮されない)
MJD2UNIX(mjd) | 修正ユリウス日 mjd の1970年1月1日00:00:00 UTC からの経過秒数(うるう秒は考慮されない)
MJD2YEAR(mjd) | 修正ユリウス日に対応するグレゴリオ暦の年
MJD2MONTH(mjd) | 修正ユリウス日に対応するグレゴリオ暦の月
MJD2DAY(mjd) | 修正ユリウス日に対応するグレゴリオ暦の日
MJD2WDAY(mjd) | 修正ユリウス日に対応するグレゴリオ暦の曜日 (1:月曜日 から 7:日曜日)
MJD2YDAY(mjd) | 修正ユリウス日に対応するグレゴリオ暦の 1 月 1 日からの通算日数 (1 から 366)
TIME() | 紀元 (1970年1月1日00:00:00 UTC) からの経過時間を秒単位で返す。

### 論理関数

- 0 を偽, それ以外を真とする。

EQ(x,y,prec) | x＝y のとき真(=1)。prec で比較の桁数を指定できる (prec == 0 は完全一致) 。
NEQ(x,y,prec) | x≠y のとき真(=1)。prec で比較の桁数を指定できる (prec == 0 は完全一致) 。
GE(x,y,prec) | x≧y のとき真(=1)。prec で比較の桁数を指定できる (prec == 0 は桁数指定なし) 。
GT(x,y,prec) | x＞y のとき真(=1)。prec で比較の桁数を指定できる (prec == 0 は桁数指定なし) 。
LE(x,y,prec) | x≦y のとき真(=1)。prec で比較の桁数を指定できる (prec == 0 は桁数指定なし) 。
LT(x,y,prec) | x＜y のとき真(=1)。prec で比較の桁数を指定できる (prec == 0 は桁数指定なし) 。
NOT(x) | x＝0 のとき真(=1)
OR(x,y) | (x≠0) or (y≠0) のとき真(=1)
AND(x,y) | (x≠0) and (y≠0) のとき真(=1)
XOR(x,y) | (x≠0) xor (y≠0) のとき真(=1)

### 配列操作関数

SIZE(a) | 配列 a の要素数
SORT(a) | 配列 a を整列する
RSORT(a) | 配列 a を逆順に整列する
POP(a) | 配列 a から末尾の要素を取り除いてそれを返す
PUSH(a,x) | 配列 a の末尾に x を追加する (戻り値は x)
SHIFT(a) | 配列 a の先頭の要素を取り除いてそれを返す。残りの要素はひとつずつ前に詰められる
UNSHIFT(a,x) | 配列 a の先頭に x を挿入する (戻り値は x)

### メモリー操作関数

メモリーは全ての数式変換で共有されます。

M(n,x) | 引数を第nメモリーに代入する(n=0〜65535) (戻り値は x)
RM(n) | 現在の第nメモリーの値(n=0〜65535)
CM(x) | メモリー全体を x で初期化する (戻り値は x)

### その他の関数

FIT_PRM(id,x) | ID が id の file オブジェクトのプロットタイプが fit のとき、対応す る fit object のフィールド "%0x" の値。
FIT_CALC(id,x) | ID が id の file オブジェクトのプロットタイプが fit のとき、対応する fit 結果 f(x) を計算する。
ISNORMAL(x) | x が通常の数値の場合真
ISBREAK(x) | x が BREAK の場合真
ISCONT(x) | x が CONT の場合真
ISNAN(x) | x が NAN の場合真
ISUNDEF(x) | x が UNDEF の場合真
SUM(x) | 積算
DIF(x) | 差分
F(x,y,z) | ユーザ定義関数
G(x,y,z) | ユーザ定義関数
H(x,y,z) | ユーザ定義関数
COLOR(0,x) | R値を x (0≦x＜256)に設定
COLOR(1,x) | G値を x (0≦x＜256)に設定
COLOR(2,x) | B値を x (0≦x＜256)に設定
COLOR(3,x) | RGB値を x (0≦x＜256)に設定
COLOR(4,x) | R2値を x (0≦x＜256)に設定
COLOR(5,x) | G2値を x (0≦x＜256)に設定
COLOR(6,x) | B2値を x (0≦x＜256)に設定
COLOR(7,x) | R2, G2, B2 値を x (0≦x＜256)に設定
COLOR(8,x) | x を 6 桁の 16 進数として、 2 桁ずつ R, G, B 値に設定
COLOR(9,x) | x を 6 桁の 16 進数として、 2 桁ずつ R2, G2, B2 値に設定
OBJ_COLOR(id, FILE_OBJ), OBJ_COLOR(id) | R, G, B, R2, G2, B2 値を ID が id の file オブジェクトと同じ値にする。
OBJ_COLOR(id, PATH_OBJ) | R, G, B, R2, G2, B2 値を ID が id の path オブジェクトの stroke_R, stroke_G, stroke_B, fill_R, fill_G, fill_B と同じ値にする。
OBJ_COLOR(id, RECT_OBJ) | R, G, B, R2, G2, B2 値を ID が id の rectangle オブジェクトの stroke_R, stroke_G, stroke_B, fill_R, fill_G, fill_B と同じ値にする。
OBJ_COLOR(id, ARC_OBJ) | R, G, B, R2, G2, B2 値を ID が id の arc オブジェクトの stroke_R, stroke_G, stroke_B, fill_R, fill_G, fill_B と同じ値にする。
OBJ_COLOR(id, MARK_OBJ) | R, G, B, R2, G2, B2 値を ID が id の mark オブジェクトと同じ値にする。
OBJ_COLOR(id, TEXT_OBJ) | R, G, B 値を ID が id の text オブジェクトと同じ値にする。
ALPHA(x) | A, A2 値を x (0≦x＜256)に設定
ALPHA(x,1) | A 値を x (0≦x＜256)に設定
ALPHA(x,2) | A2 値を x (0≦x＜256)に設定
OBJ_ALPHA(id, FILE_OBJ), OBJ_ALPHA(id) | A, A2 値を ID が id の file オブジェクトと同じ値にする。
OBJ_ALPHA(id, PATH_OBJ) | A, A2 値を ID が id の path オブジェクトの stroke_A, fill_A と同じ値にする。
OBJ_ALPHA(id, RECT_OBJ) | A, A2 値を ID が id の rectangle オブジェクトの stroke_A, fill_A と同じ値にする。
OBJ_ALPHA(id, ARC_OBJ) | A, A2 値を ID が id の arc オブジェクトの stroke_A, fill_A と同じ値にする。
OBJ_ALPHA(id, MARK_OBJ) | A, A2 値を ID が id の mark オブジェクトと同じ値にする。
OBJ_ALPHA(id, TEXT_OBJ) | A 値を ID が id の text オブジェクトと同じ値にする。
RGB(r,g,b) | 色のRGB値をそれぞれ r, g, b (0≦r,g,b≦1)に設定
RGB2(r,g,b) | R2, G2, B2, の値を r, g, b (0≦r,g,b≦1)から設定
HSB(h,s,b) | 色のHSB値をそれぞれ h, s, b (0≦h,s,b≦1)に設定
HSB2(h,s,b) | R2, G2, B2, の値を、HSB値からそれぞれ h, s, b (0≦h,s,b≦1)に設定
MARKSIZE(x) | マークのサイズをXに設定
MARKTYPE(x) | マークの種類をXに設定
IF(x,ex1,ex2) | x ≠ 0 のとき ex1, x = 0 のとき ex2
UNLESS(x,ex1,ex2) | x ≠ 0 のとき ex2, x = 0 のとき ex1
FOR(m,begin,end,step,ex) | 第mメモリーの値に begin から end まで step で 値を設定し、ex を繰り返す。 m が負の時はメモリーへの設定は行われない。 最後に評価された ex の値を返す。
PROG1(arg1,arg2,...) | 引数を評価し、最初の引数の値を返す
PROG2(arg1,arg2,...) | 引数を評価し、2 番目の引数の値を返す
PROGN(arg1,arg2,...) | 引数を評価し、最後の引数の値を返す

## 演算子の優先順位

演算子 + - (正負の符号) の優先順位が Version 6.03 以前と異なっています。

高 | !
↑ | ^
| + - (正負の符号)
| * / \
| + -
| < <= > >=
| == !=
| &&
↓ | ||
低 | :=(+=, -= ... )

## 数式変換の使用例

- ; 使用例

  ; は式の終端を示しますが、さらに続けて別の式を書くことができます。 式の値は一番最後の式の値になります。 例えば、長い式が何度も現れるとき変数への代入と組み合わせて

            a:=...式...; ... a ....;

  のようにすれば同じ式は１度書くだけですみます。また式最後の ; は省略できます。

  (従来は式の終端として "=" が使われていましたが version 6.06.10 以降 は ";" を推奨とします。)

- メモリー関数 M(), RM() 使用例

  M() はメモリーへの代入、RM() は読みだしです。全ての数式変換でメモリーは 共有されるため、データ間での値の受け渡しに利用できます。メ モリーは 65536 個 (0〜65535) まで利用できます。また、未使用のメモリーは 0 に初期化されています。

- 比較関数 EQ(), NEQ(), LT(), GT(), LE(), GE() 使用例

  数値の比較を行う関数ですが、下記の例のように浮動小数点誤差により 思った通りの結果が得られない場合があります。

            Ngraph$ iexpr 'EQ(0.5 - 0.4, 0.1)'
            0

  このような場合に、３番目の引数で比較の桁数を指定すると期待する結果 が得られることが多くなります。

            Ngraph$ iexpr 'EQ(0.5 - 0.4, 0.1, 14)'
            1

  計算によっては浮動小数点誤差の影響が大きくなる場合もありますので注 意が必要です。

- 関数 DIF() 使用例
  関数 DIF() は微分でなく差分を返す関数です。 現在のデータがデータ中 n 番目としそれを Y(n) で表すとすると

  DIF(Y)=Y(n) - Y(n-1)

  です。これを用い簡単に微分近似値を求めるには

  DIF(Y)/DIF(X)

  とします。

  DIF(Y)/DIF(X)は {Y(n)-Y(n-1)} / {X(n)-X(n-1)} になります。

  この時、Xの変換数式を

  X-DIF(X)*0.5

  としてXを"現在のデータと一つ前のデータの中間値"としておいた方がより真に近いグラフが得られると思われます。

  X変換式: X-DIF(X)*0.5 (これは { X(n-1)+X(n) }*0.5 になります)
  Y変換式: DIF(Y)/DIF(X) (これは { Y(n)-Y(n-1) } / { X(n)-X(n-1) } になります)

  DIF() は現在のデータと一つ前のデータとの差分を返しますから、Y-DIF(Y) とすることで一つ前のデータを取り出すことができます。 同様に Y-DIF(Y)-DIF(Y-DIF(Y)) で2つ前のデータを取り出すことができます。 Y-DIF(Y)-DIF(Y-DIF(Y))-DIF(Y-DIF(Y)-DIF(Y-DIF(Y)))は3つ前のデータです．

  一番初めの DIF() の戻り値は"不定"です．このため，式全体の値も"不定"となり、結果としてデータの個数は1つ減ります(一番初めのデータに差分は存在しない)。 また DIF() をいくつも含む式では、全ての DIF() が初期化されるまで式全体の値は"不定"です。 例えば DIF() をネストして DIF(DIF()) のように使った場合、一番初めのデータでは内側の DIF() が初期化されその戻り値は不定の為、外側の DIF() の初期化は行われません。 外側の DIF() が初期化されるのは 2番目のデータの時です。 従ってデータの個数は2つ減ることになります。

- 関数 SUM() 使用例
  関数 SUM() は積算を返す関数です。 現在のデータが n 番目としそれを Y(n) で表すとすると

  SUM(Y)=Σ Y(n) (n=1..n)

  これを用い簡単に積分近似値を求めるには

  SUM(Y*DIF(X))

  とします。

  SUM(Y*DIF(X)) は Σ Y(n)*{ X(n)-X(n-1) } (n=1..n) になります。

  また、台形公式を用いて積分近似値を評価したい場合

  SUM(0.5*(2*Y-DIF(Y))*DIF(X))

  とします。

  SUM(0.5*(2*Y-DIF(Y))*DIF(X)) は Σ(Y(n-1)+Y(n))/2*{X(n)-X(n-1)} (n=1..n) になります。

  さらに積分の上限(b)、下限(a)を指定したい場合は階段関数 THETA() を用い

  SUM(0.5*(2*Y-DIF(Y))*DIF(X)*THETA(X-a)*THETA(b-X))

  とします。IF() を使って

  IF(AND(GE(x,a),LE(x,b)),INTEG(0.5*(2*Y-DIF(Y))*DIF(X)),0)

  としても可能です。
- 関数 IF() 使用例
  IF(x,ex1,ex2) は x が真(<>0)のとき ex1 を，偽(=0)のとき ex2 を返す関数です。例えば次の式

  IF( x < 0, 0, SQRT(x) )

  は x<0 のとき 0、x>=0 のとき√x を返す関数になります。また必ず ex1, ex2 どちらか一方しか評価されません。
- 関数 MARKSIZE(), COLOR() 使用例
  MARKSIZE()、COLOR()関数は数学関数では無く、それぞれプロットされたマークのサイズ、色を指定する関数です。 例えば、(x,y,z) の 3 カラムから成るデータがあり、マークのサイズを z の値で変更したいような場合には

  MARKSIZE(%03)

  とします。ただこれですと、プロットされるデータも %03 となりますので、前述の ; を使って

  MARKSIZE(%03);Y

  とするのが正しい使い方です。 COLOR()関数も同様で

  COLOR(3,%03);Y

  のように使います。
- 関数 OBJ_COLOR() 使用例

  file, path, rectangle, arc, mark, text の各オブジェクトの設定色を描 画色にします。例えばいくつかのフィッティング結果をもとにフィッティ ングパラメータをグラフにするような場合、

            OBJ_COLOR(X);FIT_PRM(X,1)

  のようにして、フィッティングとプロットの色を揃えることができます。 この時 X はフィッティングプロットにした file オブジェクトのインスタ ンス ID です。
- 関数 FIT_PRM(), FIT_CALC() 使用例

  フィッティングの結果からそのパラメータや、フィッティング式の計算を 行う関数です。

  例えば、いくつかの１次フィットからその傾きをプロットしたい場合、

            FIT_PRM(X,1)

  のようにします。この時 X はフィッティングプロットにした file オブジェ クトのインスタンス ID です。

  また、１次ドリフトのあるデータからドリフト成分を引いてプロットし たい場合 (id が 0 の file オブジェクトでフィッティングを行ってい るとして)、

            Y-FIT_CALC(0,X)

  のようにします。

  これらの関数はフィッティングの結果が確定していないと計算に失敗しま す。データの描画順に注意してください。また、初回のプロットでオー トスケールに反映されないことがあります。

- 関数 PROG1(), PROG2(), PROGN() 使用例

  関数 PROG1(), PROG1(), PROGN() は複数の引数を評価して、最初、2番 目または最後の引数の値を返す関数です。IF(), UNLESS(), FOR() 関数 の引数に使用して複数の式を評価するために利用できます。下記の例で は X の値が 1 以上変化する毎に Y の平均値を計算しています (X は 1 よりも大きいことを仮定) 。

  IF(X - A < 1, PROGN(B += Y, N += 1, CONT), PROG1(IF(N, B / N, CONT), B := Y, N := 1, A := X))