/*	
 *	clipfp16.h
 *
 *	半精度浮動小数点数
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2016 Naoyuki Sawa
 *
 *	* Mon Jul 27 18:33:57 JST 2009 Naoyuki Sawa
 *	- 1st リリース。
 *	* Wed Nov 18 21:37:53 JST 2015 Naoyuki Sawa
 *	- 'extern "C" {'〜'}'で囲みました。.cppを含むWin32プロジェクトからもインクルード出来るようにするためです。
 *	* Sun Mar 20 21:22:35 JST 2016 Naoyuki Sawa
 *	- 当モジュールの名前を、'16bit浮動小数点形式'⇒'半精度浮動小数点数'に変更しました。
 *	  下記の資料によると、'半精度浮動小数点数'と呼ぶのが正式なようです。
 *	  □参照資料
 *	  │http://ja.wikipedia.org/wiki/半精度浮動小数点数
 *	- グローバル関数を全て変更しました。
 *	  具体的には、既存のfp16_read(),fp16_write()を廃止し、新規にtruncsfhf2(),truncdfhf2(),extendhfsf2(),extendhfdf2()を作成しました。
 *	  上記の変更をおこなった理由は、以下の通りです。
 *	  既存のfp16_read(),fp16_write()は、参照渡しでfp16⇔float変換を行う関数でした。
 *	  これまではfp16_read(),fp16_write()は用意していただけであまり利用していなかったのですが、頻繁に使うようになると参照渡しよりも値渡しの方が使い易い事が判りました。
 *	  そこで、参照渡しの関数を廃止し、値渡しに変更する事にしました。
 *	  また、fp16⇔float変換だけでなく、fp16⇔double変換も行いたいので、fp16⇔double変換を行う関数も追加する事にしました。
 *	- これまでは、fp16型を構造体として定義していたのですが、uint16_tへのtypedefに変更しました。
 *	  変更前のfp16型を構造体は、FP16_HALFに名前を変えて残してありますが、当モジュールの内部処理用であり、アプリケーションが直接FP16_HALF型を使用する事は推奨しません。
 *	  上記の変更をおこなった理由は、以下の通りです。
 *	  これまでfp16型を構造体として定義していた理由は、fp16の値を間違って普通の式に含めた時にエラーを検出出来るようにするためでした。
 *	  それは良いのですが、構造体を関数に値渡ししたり戻り値として受け取ると、P/ECEのコンパイラは効率の悪いコードを生成します。
 *	  それを避けるために、これまでは参照渡しで変換していました。
 *	  しかし、前述の理由で、今回、グローバル関数を全て値渡し・値返しに変更しました。
 *	  fp16型を構造体が構造体のままでは、効率の悪いコードが生成されてしまいます。
 *	  そこで、fp16型をuint16_tへのtypedefに変更する事にしました。
 *	- 今回の変更によるデメリットとして、fp16の値を間違って普通の式に含めた時にエラーが検出出来ず、見つけ辛いバグになる恐れが有ります。
 *	  このデメリットによる問題を避けるために、アプリケーションはなるべくデータのロード/セーブ時だけにfp16への変換を使用して下さい。
 *	  データのロード/セーブ時にすぐfloat,又は,doubleへ変換し、計算は全てflot,又は,doubleを使うようにして下さい。
 *	  要するに、fp16を使用する箇所を、データのロード/セーブの箇所だけに限定するのが安全です。
 *	- 関数名truncsfhf2(),truncdfhf2(),extendhfsf2(),extendhfdf2()は、GCCの組み込み関数名から取りました。
 *	  P/ECEのコンパイラではfp16はサポートされていませんが、最近のGCCではfp16がサポートされているアーキテクチャも有るそうです。
 *	  'truncdfhf2'等で検索してみると、GCCやLLVMにそれらの関数が実装されているらしき情報がヒットします。(詳細は未確認です。)
 *	- 以上、今回の変更は当モジュール全体の大幅な変更であり、変更前のコードはコメントアウトして残していません。
 *	  変更前のコードを参照する必要がある場合は、前回までのアーカイブを参照して下さい。
 *	* Mon Mar 21 21:34:20 JST 2016 Naoyuki Sawa
 *	- truncsfhf2(),truncdfhf2(),extendhfsf2(),extendhfdf2()をアセンブラ化しました。
 *	- truncdfhf2(),extendhfdf2()は、C言語版はtruncsfhf2(),extendhfsf2()を経由する単純な実装としています。
 *	  C言語版を最適化しなかった理由は、doubleにはFLT_INTに相当するビットフィールドを定義していないためと、
 *	  C言語版が使用される環境(Win32等)では、最適化しなくても性能上もコードサイズ上(下記参照)も問題無いと思ったからです。
 *	- truncdfhf2(),extendhfdf2()は、アセンブラ版ではtruncsfhf2(),extendhfsf2()を経由せずに、直接fp16⇔double変換を行うように最適化しました。
 *	  アセンブラ版は最適化した理由は、もしtruncsfhf2(),extendhfsf2()を経由すると、それ以外にfloat演算を使っていなくてもframflt1.sがリンクされてしまい、コードサイズが無駄に増える事と、
 *	  アセンブラ版を使用する環境(P/ECE)では、少しでも高速化するために直接fp16⇔double変換を行う方が良いと思ったからです。
 */
#ifndef __CLIP_FP16_H__
#define __CLIP_FP16_H__
#ifdef  __cplusplus
extern "C" {
#endif//__cplusplus
/****************************************************************************
 *	定数、マクロ、構造体
 ****************************************************************************/
typedef uint16_t	fp16;
/*--------------------------------------------------------------------------*/
//
//	seeeeemm mmmmmmmm
//	||||||++-++++++++- 仮数部 10bit + 暗黙の 1bit
//	|+++++------------ 指数部  5bit   バイアス 15
//	+----------------- 符号
//
//	表現可能な最小の絶対値 約 0.00006103515625 これよりも小さいと0になります
//	表現可能な最大の絶対値 約 131008           これよりも大きいとオーバーフローエラーになります
//
//	DirectXのFP16と同じビット構造です。
//	DirectXのFP16と、本ライブラリのfp16で、異なる点は、以下のとおりです。
//
//	・DirectXのFP16は、指数部が0、かつ、仮数部が0でないときに、非正規化数と見なします。
//	  本ライブラリのfp16は、指数部が0の場合は、仮数部の値にかかわらず、+0と見なします。
//
//	・DirectXのFP16は、指数部が31の場合に、NaN、または、無限大と見なします。
//	  本ライブラリのfp16は、指数部が31の場合も、指数部が1〜30の場合と同じ扱いとします。
//
//	本ライブラリのfp16は、メモリやファイル容量節約の目的で作成したものです。
//	fp16を直接演算する関数は、用意していません。
//	演算は、float,又は,double形式で行なってください。
//
//	<例>
//		fp16 data[1000];
//		fread(data, sizeof(fp16), 1000, fp); // ファイルからfp16形式でロード
//		for(i = 0; i < 1000; i++) {
//		  float tmp = extendhfsf2(data[i]);  // fp16形式 -> float形式に変換
//		  tmp = sqrtf(tmp);                  // float形式で演算
//		  data[i] = truncsfhf2(tmp);         // float形式 -> fp1形式に変換して格納
//		}
//
typedef union _FP16_HALF {
	struct {
		uint16_t	m	:10;	//mantissa
		uint16_t	e	: 5;	//exponent
		uint16_t	s	: 1;	//sign
	}	h;
	fp16	f;
} FP16_HALF;
/****************************************************************************
 *	グローバル関数
 ****************************************************************************/
//値渡しで、float⇒fp16変換を行います。
//[in]
//	x		変換元のfloat値。
//[out]
//	戻り値		変換後のfp16値。
fp16 truncsfhf2(float x);
//値渡しで、double⇒fp16変換を行います。
//[in]
//	x		変換元のdouble値。
//[out]
//	戻り値		変換後のfp16値。
fp16 truncdfhf2(double x);
//値渡しで、fp16⇒float変換を行います。
//[in]
//	x		変換元のfp16値。
//[out]
//	戻り値		変換後のfloat値。
float extendhfsf2(fp16 x);
//値渡しで、fp16⇒double変換を行います。
//[in]
//	x		変換元のfp16値。
//[out]
//	戻り値		変換後のdouble値。
double extendhfdf2(fp16 x);
#ifdef  __cplusplus
}//extern "C"
#endif//__cplusplus
#endif /*__CLIP_FP16_H__*/
