# 固定小数点算術ネタ ###### 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 &lt; 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; } } ~~~