# 固定小数点算術ネタ
###### tags: `java` `c#`
~~~java
/**
* 固定小数を用いた計算クラス。
*/
public class GameMath
{
/** 小数部分のビット数(={@value}) */
static public final int DECIMAL_POINT_BIT = 12;
/** 1.0 を示す固定小数(={@value}) */
static public final int FIXED = 1 << DECIMAL_POINT_BIT;
/** FIXED 倍されたπ */
static public final int PI = (int)( Math.PI * FIXED );
/** FIXED 倍された2π */
static public final int PI2 = (int)( Math.PI * FIXED * 2 );
/** sin テーブル */
static private final int[] SIN = new int[ FIXED ];
/** ラジアン(0~FIXED)を示すためのマスク */
static private final int RADIAN_MASK = FIXED - 1;
/**
* static initilizer
*/
static
{
final double per = 2 * Math.PI / FIXED;
for( int i = 0; i < SIN.length; i++ )
{
SIN[ i ] = ( int )( Math.sin( per * i ) * FIXED );
}
}
/**
*
*/
private GameMath(){}
/** cos テーブル変換への sin テーブルオフセット */
static public final int COS_TABLE_OFFSET = FIXED / 4;
/**
* 正弦の近似値を計算する。
* @param a 角度を FIXED 分円単位(2πラジアン = FIXED)で指定する。 任意の符号付き整数を指定できる。
* @return 指定された角度の正弦値の FIXED 倍の値を返す。
* @see FIXED
*/
static public int sin( int a )
{
return SIN[ a & RADIAN_MASK ];
}
/**
* 余弦の近似値を計算する。
* @param a 角度を FIXED 分円単位(2πラジアン = FIXED)で指定する。 任意の符号付き整数を指定できる。
* @return 指定された角度の余弦値の FIXED 倍の値を返す。
* @see FIXED
*/
static public int cos( int a )
{
return SIN[ ( a + COS_TABLE_OFFSET ) & RADIAN_MASK ];
}
static private final int ATAN90 = FIXED / 4;
static private final int ATAN180 = FIXED / 2;
static private final int ATAN270 = ( FIXED / 4 ) * 3;
static private final int ATAN_ALPHA = FIXED / 8;
static private final int ATAN_BETA = -FIXED / 8;
/**
* 逆正接の近似値を計算する。
* @return 逆正接値の FIXED 倍の値を返す。
* @see FIXED
*/
static public int atan2( int y, int x )
{
int atan = 0;
int r = 0;
int xx;
int yy;
int signed = 1;
if( x + y > 0 )
{
if( x > y )
{
xx = x;
yy = y;
}
else
{
xx = y;
yy = x;
r = ATAN90;
signed = -1;
}
}
else
{
if( x < y )
{
xx = -x;
yy = -y;
r = ATAN180;
}
else
{
xx = -y;
yy = -x;
r = ATAN270;
signed = -1;
}
}
if( xx != 0 )
{
int n;
int alpha = ATAN_ALPHA;
int beta = ATAN_BETA;
int i = 7;
do
{
n = ( alpha + beta ) / 2;
if( xx * sin( n ) >= yy * cos( n ) )
{
alpha = n;
}
else
{
beta = n;
}
}while( --i >= 0 );
atan = ( signed * alpha ) + r;
}
return atan & RADIAN_MASK;
}
/**
* 平方根の近似値を取得する。
* @exception ArithmeticException v < 0 の時
*/
static public int sqrt( int v )
{
if( v < 0 )
{
throw new ArithmeticException( "v = " + v );
}
if( v == 0 )
{
return 0;
}
int result = 0;
int i = 15;
int t;
for( i = 0; i < 16; i++ )
{
t = ( 0x8000 >> i ) | result;
if( t * t <= v && t <= 46340 ) // 46340 == √0x7fffffff
{
result = t;
}
}
return result;
}
}
~~~