/*	
 *	clipmati.c
 *
 *	ユーティリティ：数学関数(整数版)
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2017 Naoyuki Sawa
 *
 *	* Thu Aug 10 21:41:17 JST 2017 Naoyuki Sawa
 *	- 作成開始。
 *	- clipmath.cから、整数版の関数の実装を、clipmati.cへ分離しました。
 *	  実際のアプリケーションでは実数版か整数版の片方だけを使用する事が多く、もう片方も無駄にリンクされて容量が増える事を避けるためです。
 */
#include "clip.h"
//*****************************************************************************
//	線形補間(整数版)
//*****************************************************************************
//x～yを、n/dで補間します。
//[in]
//	x		開始値。		INT_MIN～INT_MAX
//	y		終了値。		INT_MIN～INT_MAX
//	n		補間係数の分子。	INT_MIN～INT_MAX
//	d		補間係数の分母。	1～INT_MAX,-1～INT_MIN	0のみ不可
//[out]
//	戻り値		x+(y-x)*(n/d)		結果がINT_MIN～INT_MAXの範囲に収まらない場合は、戻り値は不定となる。<例>{x=0,y=1<<30,n=5,d=1}を指定した場合など。
//[note]
//	- 当関数は、他の補完処理からも利用する基本処理になると思ったので、汎用性を重視して、引数の値の範囲の制限を設けないように作成しました。
//	  内部的には演算途中で64ビット演算を行っているので、(結果以外は)演算途中での桁あふれを心配する必要は有りません。
//	  実数版の'lerp()'と、ほぼ同じ感覚で使えると思います。
//	  詳細は、以下の通りです。
//	- xとyの大小は不問です。
//	  (x<y)でも(x=y)でも(x>y)でも構いません。
//	- xとyはそれぞれ、INT_MIN～INT_MAXの任意の値です。
//	  (|x-y|>INT_MAX)でも構いません。				一般的には(|x-y|≦INT_MAX)だとは思いますが、汎用性のために(|x-y|>INT_MAX)も対応しました。この対応のために、やや処理が多くなっています。
//	- nは一般的には、0以上d以下(d<0の場合は0以下d以上)の値です。
//	  ただし必須ではなく、上記の範囲外の値でも構いません。
//	- dは一般的には、1～INT_MAXの値です。
//	  ただし必須ではなく、-1～INT_MINの値でも構いません。		一般的には(1≦d≦INT_MAX)だとは思いますが、汎用性のために(-1≧d≧INT_MIN)も対応しました。この対応のために、やや処理が多くなっています。
#ifndef PIECE
int lerp_i(int x, int y, int n, int d) {
	if(d < 0) {
		n = -n;
		d = -d;
	}
	if(y < x) {
		y -= x;
		y = -y;
	    //{{共通処理
		if(n < 0) {
			n = -n;
			y = (uint64_t)(unsigned)y * (uint64_t)(unsigned)n / (uint64_t)(unsigned)d;
			y = -y;	//    ~~~~~~~~~~              ~~~~~~~~~~              ~~~~~~~~~~	元々の変数y,n,dは符号付きの値ですが、既に符号無しの値に補正済みなので、bit31をbit63～32へ符号拡張しないように、まず(unsigned)へのキャストが必要です。
		} else {
			y = (uint64_t)(unsigned)y * (uint64_t)(unsigned)n / (uint64_t)(unsigned)d;
		}		//    ~~~~~~~~~~              ~~~~~~~~~~              ~~~~~~~~~~	元々の変数y,n,dは符号付きの値ですが、既に符号無しの値に補正済みなので、bit31をbit63～32へ符号拡張しないように、まず(unsigned)へのキャストが必要です。
	    //}}共通処理
		y = -y;
	} else {
		y -= x;
	    //{{共通処理
		if(n < 0) {
			n = -n;
			y = (uint64_t)(unsigned)y * (uint64_t)(unsigned)n / (uint64_t)(unsigned)d;
			y = -y;	//    ~~~~~~~~~~              ~~~~~~~~~~              ~~~~~~~~~~	元々の変数y,n,dは符号付きの値ですが、既に符号無しの値に補正済みなので、bit31をbit63～32へ符号拡張しないように、まず(unsigned)へのキャストが必要です。
		} else {
			y = (uint64_t)(unsigned)y * (uint64_t)(unsigned)n / (uint64_t)(unsigned)d;
		}		//    ~~~~~~~~~~              ~~~~~~~~~~              ~~~~~~~~~~	元々の変数y,n,dは符号付きの値ですが、既に符号無しの値に補正済みなので、bit31をbit63～32へ符号拡張しないように、まず(unsigned)へのキャストが必要です。
	    //}}共通処理
	}
	return x + y;
}
#else //PIECE
//□アセンブラ版のlerp_i()が保存するレジスタについて:
//│アセンブラ版のlerp_i()は、%r9,%r10,%r11,%r13,%r14,%r15,%alr,%ahr,%psr だけを破壊します。
//│呼び出し規約によって保存が義務付けられている %r0～%r3,及び,%r8 に加えて、%r4～%r7,及び,%r12 も保存します。	←──────────────────────┬注目!!
//│呼び出し側の関数は、上記のレジスタが保存される事を前提として、上記のレジスタの退避を省略しても構いません。	←──────────────────────┘
//□アセンブラ版の性能について(2017/07/28現在)
//│C言語版よりもアセンブラ版の方が、64バイト小さく、約10倍も高速です。	←──────────────────────────────────────────┬注目!!
//│C言語版でframdi.oを高速RAMに置いた場合と比べても、約3倍も高速です。	←──────────────────────────────────────────┘
//│C言語版とアセンブラ版の速度が大きく違う理由は、C言語版では、必要無い部分までフル64ビット乗除算を行ってしまっていますが、
//│アセンブラ版では、必要最低限の32ビット×32ビット⇒64ビット乗算，及び，64ビット÷32ビット⇒32ビット除算に最適化したので、
//│C言語版と違って、ソフトウェアによる64ビット乗除算ルーチン(framdi.o)は呼び出さず、機械語命令だけで済ませられたからです。
//│速度計測の結果の詳細は、以下の通りです。
//│【速度計測に使用したテストプログラム】
//│#define N 10000
//│int data[N][4];
//│int app_main(int argc, char* argv[]) {
//│  int i, j, t;
//│  srand48(0);
//│  for(i = 0; i < N; i++) {
//│    double d;
//│         data[i][0] = mrand48();
//│         data[i][1] = mrand48();
//│         data[i][2] = mrand48();
//│    do { data[i][3] = mrand48(); } while(!data[i][3]);
//│    d = lerp(data[i][0], data[i][1], (double)data[i][2] / (double)data[i][3]);
//│    if((d < INT_MIN) || (d > INT_MAX)) { i--; }
//│  }
//│  t = pceTimerGetCount();
//│  for(j = 0; j < 10; j++) {
//│    for(i = 0; i < N; i++) {
//│      lerp_i(data[i][0], data[i][1], data[i][2], data[i][3]);
//│    }
//│  }
//│  t = pceTimerGetCount() - t;
//│  die("%d", t);
//│  return 0;
//│}
//│【速度計測の結果】TURBOモード、スタックは高速RAMに配置して実行しました。
//│・C言語版(framdi.oをSRAMに配置)     7555ミリ秒
//│・C言語版(framdi.oを高速RAMに配置)  2272ミリ秒
//│・アセンブラ版(framdi.oは関係無し)   767ミリ秒
int lerp_i(int x, int y, int n, int d);
asm("
		.code
		.align		1
		.global		lerp_i
lerp_i:
		;//%r12 := x
		;//%r13 := y
		;//%r14 := n
		;//%r15 := d
		cmp		%r15, 0			;//if(d < 0) {
		jrge.d		lerp_i_L10		;//  
		ld.w		%r9, 8-1		;//%r9       := i = 8-1		*delay*	─┐
		not		%r14, %r14		;//  %r14    := n = -n			　│
		add		%r14, 1			;//  					　│
		not		%r15, %r15		;//  %r15    := d = -d			　│
		add		%r15, 1			;//  					　│
lerp_i_L10:						;//}					　│
		sub		%r13, %r12		;//%r13      := y -= x			　│
		jrge.d		lerp_i_L20		;//if(変更前のy < x) {			　│
		ld.w		%r11, %psr		;//%psr保存①			*delay*	　│
		not		%r13, %r13		;//  %r13    := y = -y			　│
		add		%r13, 1			;//  					　│
lerp_i_L20:						;//}					　│
		cmp		%r14, -1		;//if(変更前のn <= -1) {		　│		(n>-1)ならば%psr(Z)=0で分岐する。(n<=-1)ならば%psr(Z)=1の可能性も有るが、この下の処理で%psr(Z)=0になる。
		jrgt.d		lerp_i_L30		;//  					　│
		ld.w		%r10, %psr		;//%psr保存②			*delay*	　│
		sub		%r14, 1			;//  %r14    := n = -n			　│		この処理で必ず%psr(Z)=0になる。-1して0になるのは(n=1)だった場合のみだが、(n=1)ならばここへは来ないから。
		not		%r14, %r14		;//					　│
lerp_i_L30:						;//}					　│	─┐	分岐した場合も分岐しなかった場合も、ここで必ず%psr(Z)=0になっている。この後のループの初回の%psr(Z)判定まで変化しないよう注意せよ。
		mltu.w		%r13, %r14		;//%ahr:%alr := (y * n)			　│	　│
		ld.w		%r14, %ahr		;//%r14      := (y * n)[63:32]		　│	　│
		div0u		%r15			;//%ahr      :=    0			　│	　│	%psr(DS,N)=0
		ld.w		%ahr, %r14		;//%ahr:%alr := (y * n)			　│	　│
	;//	ld.w		%r9, 8-1		;//%r9       := i = 8-1			←┘	　│
lerp_i_L40:						;//do {						　│
		div1		%r15			;//  1						　│	┐
		div1		%r15			;//  2						　│	├div1を実行する時は'%psr(DS,N)=0'を維持している必要がある事に注意せよ。
		div1		%r15			;//  3						　│	│
		div1		%r15			;//  4						　│	┘
		jrne.d		lerp_i_L40		;//} while(i != 0)				←┤	初回は%psr(Z)=0であるはずなので必ずループする。二回目以降はこの下で変化した%psr(Z)を参照してループする。
		sub		%r9, 1			;//  %r9     := i--		*delay*		─┘
		ld.w		%psr, %r10		;//%psr復元②
		jrgt.d		lerp_i_L50		;//if(変更前のn <= -1) {
		ld.w		%r10, %alr		;//%r10      := y = (y * n) / d	*delay*
		not		%r10, %r10		;//  %r10    := y = -y
		add		%r10, 1			;//  
lerp_i_L50:						;//}
		ld.w		%psr, %r11		;//%psr復元①
		jrge		lerp_i_L60		;//if(変更前のn < 0) {
		not		%r10, %r10		;//  %r10    := y = -y
		add		%r10, 1			;//  
lerp_i_L60:						;//}
		ret.d					;//return       x + y
		add		%r10, %r12		;//%r10      := x + y		*delay*
");
#endif//PIECE
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#if 0
//□lerp_i()のテストスイート
int app_main(int argc, char* argv[]) {
	int x, y, n, d, a;
	double b;
	for(;;) {
		     x = mrand48();
		     y = mrand48();
		     n = mrand48();
		do { d = mrand48(); } while(!d);
		a = lerp_i(x, y,         n,          d);
		b = lerp(  x, y, (double)n / (double)d);
	#ifndef PIECE
		       printf(                     "% 11d % 11d % 2d\n", a, lround(b), a - lround(b));
	#else //PIECE
		surface_clear(&surface, 0);
		render_printf(&render, 0, 0, 2, 3, "% 11d % 11d % 2d\n", a, lround(b), a - lround(b));
		update();
		if(pcePadGetDirect() & PAD_SELECT) { break; }
	#endif//PIECE
		if((b >= INT_MIN) && (b <= INT_MAX)) {	//結果がINT_MIN～INT_MAXの範囲に収まらない場合を除けば…
			if(abs(a - lround(b)) > 1) {	//小数部の切り捨て誤差の範囲で正しい結果が得られるはず。
				die("x = % 11d\n"
				    "y = % 11d\n"
				    "n = % 11d\n"
				    "d = % 11d\n"
				    "a = % 11d\n"
				    "b = % 11d\n", x, y, n, d, a, lround(b));
			}
		}
	}
	return 0;
}
#endif
//*****************************************************************************
//	イージング(整数版)
//*****************************************************************************
//ゆっくり動き出して加速する動作です。
//[in]
//	x		開始値。		INT_MIN～INT_MAX
//	y		終了値。		INT_MIN～INT_MAX
//	n		補間係数の分子。	0～d
//	d		補間係数の分母。	1～SHRT_MAX
//[out]
//	戻り値		補間結果。
//[note]
//	- lerp_i()は基本処理なので汎用性を重視して引数の値の範囲の制限を設けないようにしましたが、当関数(easeIn_i())は末端処理だと思うので汎用性は重視しませんでした。
//	  そのため、lerp_i()よりも引数d(ひいては引数nも)の値の範囲の制限が厳しいです。
//	  一般的な使い方では充分だと思いますが、引数の値が5桁(=?万)以上になるケースでは、注意して下さい。
#ifndef PIECE
int easeIn_i(int x, int y, int n, int d) {
	n *= n;	//調整可
	d *= d;	//調整可
	return lerp_i(x, y, n, d);
}
#else //PIECE
int easeIn_i(int x, int y, int n, int d);
asm("
		.code
		.align		1
		.global		easeIn_i
easeIn_i:
		mlt.h		%r14, %r14		;//%r14 := n *= n
		ld.w		%r14, %alr		;//
		mlt.h		%r15, %r15		;//%r15 := d *= d
		xjp.d		lerp_i			;//return lerp_i(x, y, n, d)
		ld.w		%r15, %alr		;//				*delay*
");
#endif//PIECE
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#if 0
//□easeIn_i()のテストスイート
int app_main(int argc, char* argv[]) {
	int x, y, n, d, a;
	double b;
	for(;;) {
		     x = mrand48();
		     y = mrand48();
		do { d = lrand48() % (SHRT_MAX + 1); } while(!d);
		     n = lrand48() % d;
		a = easeIn_i(x, y,         n,          d);
		b = easeIn(  x, y, (double)n / (double)d);
	#ifndef PIECE
		       printf(                     "% 11d % 11d % 2d\n", a, lround(b), a - lround(b));
	#else //PIECE
		surface_clear(&surface, 0);
		render_printf(&render, 0, 0, 2, 3, "% 11d % 11d % 2d\n", a, lround(b), a - lround(b));
		update();
		if(pcePadGetDirect() & PAD_SELECT) { break; }
	#endif//PIECE
		if((b >= INT_MIN) && (b <= INT_MAX)) {	//結果がINT_MIN～INT_MAXの範囲に収まらない場合を除けば…
			if(abs(a - lround(b)) > 1) {	//小数部の切り捨て誤差の範囲で正しい結果が得られるはず。
				die("x = % 11d\n"
				    "y = % 11d\n"
				    "n = % 11d\n"
				    "d = % 11d\n"
				    "a = % 11d\n"
				    "b = % 11d\n", x, y, n, d, a, lround(b));
			}
		}
	}
	return 0;
}
#endif
//-----------------------------------------------------------------------------
//高速で動き出して減速する動作です。
//[in]
//	x		開始値。		INT_MIN～INT_MAX
//	y		終了値。		INT_MIN～INT_MAX
//	n		補間係数の分子。	0～d
//	d		補間係数の分母。	1～SHRT_MAX
//[out]
//	戻り値		補間結果。
//[note]
//	- lerp_i()は基本処理なので汎用性を重視して引数の値の範囲の制限を設けないようにしましたが、当関数(easeOut_i())は末端処理だと思うので汎用性は重視しませんでした。
//	  そのため、lerp_i()よりも引数d(ひいては引数nも)の値の範囲の制限が厳しいです。
//	  一般的な使い方では充分だと思いますが、引数の値が5桁(=?万)以上になるケースでは、注意して下さい。
#ifndef PIECE
int easeOut_i(int x, int y, int n, int d) {
	n = -n;
	n += d;
	return easeIn_i(y, x, n, d);
}
#else //PIECE
int easeIn_i(int x, int y, int n, int d);
asm("
		.code
		.align		1
		.global		easeOut_i
easeOut_i:
		not		%r14, %r14		;//%r14 := n = -n
		add		%r14, 1			;//
		add		%r14, %r15		;//%r14 := n += d
		ld.w		%r9, %r12		;//%r9  :=            x
		ld.w		%r12, %r13		;//%r12 :=         y
		xjp.d		easeIn_i		;//return easeIn_i(y, x, n, d)
		ld.w		%r13, %r9		;//%r13 :=            x		*delay*
");
#endif//PIECE
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#if 0
//□easeOut_i()のテストスイート
int app_main(int argc, char* argv[]) {
	int x, y, n, d, a;
	double b;
	for(;;) {
		     x = mrand48();
		     y = mrand48();
		do { d = lrand48() % (SHRT_MAX + 1); } while(!d);
		     n = lrand48() % d;
		a = easeOut_i(x, y,         n,          d);
		b = easeOut(  x, y, (double)n / (double)d);
	#ifndef PIECE
		       printf(                     "% 11d % 11d % 2d\n", a, lround(b), a - lround(b));
	#else //PIECE
		surface_clear(&surface, 0);
		render_printf(&render, 0, 0, 2, 3, "% 11d % 11d % 2d\n", a, lround(b), a - lround(b));
		update();
		if(pcePadGetDirect() & PAD_SELECT) { break; }
	#endif//PIECE
		if((b >= INT_MIN) && (b <= INT_MAX)) {	//結果がINT_MIN～INT_MAXの範囲に収まらない場合を除けば…
			if(abs(a - lround(b)) > 1) {	//小数部の切り捨て誤差の範囲で正しい結果が得られるはず。
				die("x = % 11d\n"
				    "y = % 11d\n"
				    "n = % 11d\n"
				    "d = % 11d\n"
				    "a = % 11d\n"
				    "b = % 11d\n", x, y, n, d, a, lround(b));
			}
		}
	}
	return 0;
}
#endif
//-----------------------------------------------------------------------------
//ゆっくり動き出して加速し、また減速する動作です。
//[in]
//	x		開始値。		INT_MIN～INT_MAX	┬処理の都合上、演算途中で、(y + x)がINT_MIN～INT_MAXの範囲を超えた場合も、結果が不正になります。
//	y		終了値。		INT_MIN～INT_MAX	┘
//	n		補間係数の分子。	0～d
//	d		補間係数の分母。	1～SHRT_MAX
//[out]
//	戻り値		補間結果。
//[note]
//	- lerp_i()は基本処理なので汎用性を重視して引数の値の範囲の制限を設けないようにしましたが、当関数(easeInOut_i())は末端処理だと思うので汎用性は重視しませんでした。
//	  そのため、lerp_i()よりも引数d(ひいては引数nも)の値の範囲の制限が厳しいです。
//	  一般的な使い方では充分だと思いますが、引数の値が5桁(=?万)以上になるケースでは、注意して下さい。
//{{2017/08/08削除:easeInOut_i()とeaseOutIn_i()の処理を共通化して、コードサイズを削減しました。
//#ifndef PIECE
//int easeInOut_i(int x, int y, int n, int d) {
//	y += x;								//処理の都合上、演算途中で、(y + x)がINT_MIN～INT_MAXの範囲を超えた場合も、結果が不正になります。
//	n <<= 1;
//	if(n >= d) {
//		x = -x;
//		x += y;
//		n = -n;
//		n += d << 1;
//	}
//	y >>= 1;
//	return easeIn_i(x, y, n, d);										//easeInOut_i()とeaseOutIn_i()の違いは、この行だけです。
//}
//#else //PIECE
//int easeInOut_i(int x, int y, int n, int d);
//asm("
//		.code
//		.align		1
//		.global		easeInOut_i
//easeInOut_i:
//		sla		%r14, 1			;//%r14 := n <<= 1
//		cmp		%r14, %r15		;//if(n >= d) {
//		jrlt.d		easeInOut_i_L10		;//  
//		add		%r13, %r12		;//%r13 := y += x		*delay*
//		not		%r12, %r12		;//  %r12 := x = -x
//		add		%r12, 1			;//  
//		add		%r12, %r13		;//  %r12 := x += y
//		not		%r14, %r14		;//  %r14 := n = -n
//		add		%r14, 1			;//  
//		add		%r14, %r15		;//  %r14 := n += d << 1
//		add		%r14, %r15		;//  
//easeInOut_i_L10:					;//}
//		xjp.d		easeIn_i		;//return easeIn_i(x, y, n, d)				//easeInOut_i()とeaseOutIn_i()の違いは、この行だけです。
//		sra		%r13, 1			;//%r13 := y >>= 1		*delay*
//");
//#endif//PIECE
//}}2017/08/08削除:easeInOut_i()とeaseOutIn_i()の処理を共通化して、コードサイズを削減しました。
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#if 0
//□easeInOut_i()のテストスイート
int app_main(int argc, char* argv[]) {
	int x, y, n, d, a;
	double b;
	for(;;) {
		     x = mrand48();
		     y = mrand48();
		do { d = lrand48() % (SHRT_MAX + 1); } while(!d);
		     n = lrand48() % d;
		if((((double)x + (double)y) < (double)INT_MIN) || (((double)x + (double)y) > (double)INT_MAX)) { continue; }
		a = easeInOut_i(x, y,         n,          d);
		b = easeInOut(  x, y, (double)n / (double)d);
	#ifndef PIECE
		       printf(                     "% 11d % 11d % 2d\n", a, lround(b), a - lround(b));
	#else //PIECE
		surface_clear(&surface, 0);
		render_printf(&render, 0, 0, 2, 3, "% 11d % 11d % 2d\n", a, lround(b), a - lround(b));
		update();
		if(pcePadGetDirect() & PAD_SELECT) { break; }
	#endif//PIECE
		if((b >= INT_MIN) && (b <= INT_MAX)) {	//結果がINT_MIN～INT_MAXの範囲に収まらない場合を除けば…
			if(abs(a - lround(b)) > 1) {	//小数部の切り捨て誤差の範囲で正しい結果が得られるはず。
				die("x = % 11d\n"
				    "y = % 11d\n"
				    "n = % 11d\n"
				    "d = % 11d\n"
				    "a = % 11d\n"
				    "b = % 11d\n", x, y, n, d, a, lround(b));
			}
		}
	}
	return 0;
}
#endif
//-----------------------------------------------------------------------------
//高速で動き出して減速し、また加速する動作です。
//[in]
//	x		開始値。		INT_MIN～INT_MAX	┬処理の都合上、演算途中で、(y + x)がINT_MIN～INT_MAXの範囲を超えた場合も、結果が不正になります。
//	y		終了値。		INT_MIN～INT_MAX	┘
//	n		補間係数の分子。	0～d
//	d		補間係数の分母。	1～SHRT_MAX
//[out]
//	戻り値		補間結果。
//[note]
//	- lerp_i()は基本処理なので汎用性を重視して引数の値の範囲の制限を設けないようにしましたが、当関数(easeOutIn_i())は末端処理だと思うので汎用性は重視しませんでした。
//	  そのため、lerp_i()よりも引数d(ひいては引数nも)の値の範囲の制限が厳しいです。
//	  一般的な使い方では充分だと思いますが、引数の値が5桁(=?万)以上になるケースでは、注意して下さい。
//{{2017/08/08削除:easeInOut_i()とeaseOutIn_i()の処理を共通化して、コードサイズを削減しました。
//#ifndef PIECE
//int easeOutIn_i(int x, int y, int n, int d) {
//	y += x;								//処理の都合上、演算途中で、(y + x)がINT_MIN～INT_MAXの範囲を超えた場合も、結果が不正になります。
//	n <<= 1;
//	if(n >= d) {
//		x = -x;
//		x += y;
//		n = -n;
//		n += d << 1;
//	}
//	y >>= 1;
//	return easeOut_i(x, y, n, d);										//easeInOut_i()とeaseOutIn_i()の違いは、この行だけです。
//}
//#else //PIECE
//int easeOutIn_i(int x, int y, int n, int d);
//asm("
//		.code
//		.align		1
//		.global		easeOutIn_i
//easeOutIn_i:
//		sla		%r14, 1			;//%r14 := n <<= 1
//		cmp		%r14, %r15		;//if(n >= d) {
//		jrlt.d		easeOutIn_i_L10		;//  
//		add		%r13, %r12		;//%r13 := y += x		*delay*
//		not		%r12, %r12		;//  %r12 := x = -x
//		add		%r12, 1			;//  
//		add		%r12, %r13		;//  %r12 := x += y
//		not		%r14, %r14		;//  %r14 := n = -n
//		add		%r14, 1			;//  
//		add		%r14, %r15		;//  %r14 := n += d << 1
//		add		%r14, %r15		;//  
//easeOutIn_i_L10:					;//}
//		xjp.d		easeOut_i		;//return easeIn_i(x, y, n, d)				//easeInOut_i()とeaseOutIn_i()の違いは、この行だけです。
//		sra		%r13, 1			;//%r13 := y >>= 1		*delay*
//");
//#endif//PIECE
//}}2017/08/08削除:easeInOut_i()とeaseOutIn_i()の処理を共通化して、コードサイズを削減しました。
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#if 0
//□easeOutIn_i()のテストスイート
int app_main(int argc, char* argv[]) {
	int x, y, n, d, a;
	double b;
	for(;;) {
		     x = mrand48();
		     y = mrand48();
		do { d = lrand48() % (SHRT_MAX + 1); } while(!d);
		     n = lrand48() % d;
		if((((double)x + (double)y) < (double)INT_MIN) || (((double)x + (double)y) > (double)INT_MAX)) { continue; }
		a = easeOutIn_i(x, y,         n,          d);
		b = easeOutIn(  x, y, (double)n / (double)d);
	#ifndef PIECE
		       printf(                     "% 11d % 11d % 2d\n", a, lround(b), a - lround(b));
	#else //PIECE
		surface_clear(&surface, 0);
		render_printf(&render, 0, 0, 2, 3, "% 11d % 11d % 2d\n", a, lround(b), a - lround(b));
		update();
		if(pcePadGetDirect() & PAD_SELECT) { break; }
	#endif//PIECE
		if((b >= INT_MIN) && (b <= INT_MAX)) {	//結果がINT_MIN～INT_MAXの範囲に収まらない場合を除けば…
			if(abs(a - lround(b)) > 1) {	//小数部の切り捨て誤差の範囲で正しい結果が得られるはず。
				die("x = % 11d\n"
				    "y = % 11d\n"
				    "n = % 11d\n"
				    "d = % 11d\n"
				    "a = % 11d\n"
				    "b = % 11d\n", x, y, n, d, a, lround(b));
			}
		}
	}
	return 0;
}
#endif
//-----------------------------------------------------------------------------
//{{2017/08/08追加:easeInOut_i()とeaseOutIn_i()の処理を共通化して、コードサイズを削減しました。
#ifndef PIECE
static int easeInOut_easeOutIn_i(int x, int y, int n, int d, int (*fn)(int x, int y, int n, int d));		//前方参照
int easeInOut_i(int x, int y, int n, int d) { return easeInOut_easeOutIn_i(x, y, n, d, easeIn_i); }
int easeOutIn_i(int x, int y, int n, int d) { return easeInOut_easeOutIn_i(x, y, n, d, easeOut_i); }
static int easeInOut_easeOutIn_i(int x, int y, int n, int d, int (*fn)(int x, int y, int n, int d)) {
	y += x;								//処理の都合上、演算途中で、(y + x)がINT_MIN～INT_MAXの範囲を超えた場合も、結果が不正になります。
	n <<= 1;
	if(n >= d) {
		x = -x;
		x += y;
		n = -n;
		n += d << 1;
	}
	y >>= 1;
	return (*fn)(x, y, n, d);
}
#else //PIECE
int easeInOut_i(int x, int y, int n, int d);
int easeOutIn_i(int x, int y, int n, int d);
asm("
		.code
		.align		1
		.global		easeInOut_i
		.global		easeOutIn_i
easeInOut_i:
		xld.w		%r9, easeIn_i			;//%r9  := fn = easeIn_i
		jp		easeInOut_easeOutIn_i
easeOutIn_i:
		xld.w		%r9, easeOut_i			;//%r9  := fn = easeOut_i
easeInOut_easeOutIn_i:
		sla		%r14, 1				;//%r14 := n <<= 1
		cmp		%r14, %r15			;//if(n >= d) {
		jrlt.d		easeInOut_easeOutIn_i_L10	;//  
		add		%r13, %r12			;//%r13 := y += x		*delay*
		not		%r12, %r12			;//  %r12 := x = -x
		add		%r12, 1				;//  
		add		%r12, %r13			;//  %r12 := x += y
		not		%r14, %r14			;//  %r14 := n = -n
		add		%r14, 1				;//  
		add		%r14, %r15			;//  %r14 := n += d << 1
		add		%r14, %r15			;//  
easeInOut_easeOutIn_i_L10:					;//}
		sra		%r13, 1				;//%r13 := y >>= 1
		jp		%r9				;//return (*fn)(x, y, n, d)	(jp.d %rbは不可)
");
#endif//PIECE
//}}2017/08/08追加:easeInOut_i()とeaseOutIn_i()の処理を共通化して、コードサイズを削減しました。
