コンピュータを楽しもう!!

今、自分が面白くていろいろやってみたことを書き綴りたいと思います。連絡先はtarosa.yでgmail.comです。

数値計算

OsoScriptは数値関数を自前で書いています。余り効率良くないのですが、趣味ということでお許しください。
使っているのは、pow()とexp()です。OsoScriptでは変数の数値をすべてテキストで持っているので、計算時に浮動小数値に変換しています。この変換にpow()とexp()を使うのですが、この2つの関数を内部で書いています。
例えば

1.234e4 = 1.234*pow(10,4)
として計算します。
pow(10,4)は10を4回掛ければ答えが出ます。
-4のように負の数だと、10で割ればいいだけです。

次に、1.23e6.7という場合どうなるかというと、

1.234e6.7 = 1.234*pow(10,6.7)
となります。これを解くのにexpを使います。

例えば、
Z=10のn乗とすると、
log(Z)=log(10のn乗)
log(Z)=n*log(10) となります。
ここで、
Y=log(X)は、X=exp(Y)なので、上の式に当てはめてZ=の式に直しますと、
Z=exp(n*log(10)) となります。
log(10)は、2.30258509299405これぐらいの数値に直します。

そうすると、pow(10,6.7)は、
exp( 6.7*2.30258509299405 )により答えが出ます。

expの計算は、exp(x)をマクローリン展開して求めています。
実際の関数は下記です。

//**********************************************
// exp( x )を計算する
//**********************************************
double	texp( double x )
{
double	k = 1.0;
double	y = 1.0;
double	n = 1.0;

	while( true ){
		k = k * ( x / n );
		if( -0.0000001<k && k<0.0000001 )	break;
		y += k;
		n++;
	}
	return( y );
}

10のn乗を求める関数は、tpow10()としています。

//**********************************************
// pow( 10, x )を計算する
//**********************************************
double	tpow10( double x )
{
double	y = 1.0;
double	i;

	if( x==0.0 ){	return( y );	}
	if( (double)((int)x)==x ){
		if( x>0 ){
			for( i=1; i<=x; i+=1.0 ){	y *= 10.0;	}
		}
		else{
			x = -x;
			for( i=1; i<=x; i+=1.0 ){	y /= 10.0;	}
		}
	}
	else{
		y = texp( x * 2.30258509299405 );
	}
	return( y );
}

ちなみに、これをOsoScriptで書くと、

OsoScriptで書いてみる

下記のようになるのですが、OsoScriptに致命的なバグがありました。

#--------------------------------
#10のn乗を求める
#--------------------------------
global White = 65535;
global Black = 32768;
global Red = 32799;
global Green = 33760;
global Blue = 64512;
global Main = 0;
global Sub = 1;
function main()
{
local x;
local y;

	cls( 0, rgb(0,0,0) );		#メイン画面を黒で塗りつぶします
	cls( 1, rgb(0,0,0) );		#サブ画面を黒で塗りつぶす

	print( Main, 0,0, "10のn乗を求めます", White );
	print( Main, 0,1*12, "数値を入力してください", White );
	while( true ){
		input( Sub, x, "", 5 );
		y = pow10( x );
		box( Main, 0,3*12, 35*6, 3*12+11, rgb(0,0,0), 1 );
		print( Main, 0, 3*12, "pow10( " x " ) = " y, White );
	}
}

function exp( x )
{
local	k = 1.0;
local	y = 1.0;
local	n = 1.0;
local	z;

	while( true ){
		k = k * ( x / n );
	if( (-0.0000001<k)*(k<0.0000001) ){break;}
		box(Main,0,5*12,35*6,5*12+11,rgb(0,0,0),1);
		print( Main, 0,5*12,"k=" k ",y=" y,White);
		z = y;
		y = y + k;
		n=n+1;
	}
	return( y );
}

function pow10( x )
{
local	y = 1.0;
local	i;
	if( x==0 ){return( y );}
	if( x-int(x)==0 ){
		if( x>0 ){
			for(i=1,i<=x,1){y=y*10;}
		}
		else{
			x=-x;
			for(i=1,i<=x,1){y=y/10.0;}
		}
	}
	else{
		y = exp( x*2.302585093 );
	}
	return( y );
}

OsoScriptの単項演算子として使っている'-'が正常に計算されないことがわかりました。(-0.0000001

 if( Amatch( "+", 0 ) ){
  value = p_factor();
 }
 else if( Amatch( "-", 0 ) ){
  value = - p_factor();
 }

としなければいけないところを、

 if( Amatch( "+", 0 ) ){
  value = p_expression();
 }
 else if( Amatch( "-", 0 ) ){
  value = - p_expression();
 }

としていたのが原因でした。
バージョン0.03では修正したいと思います。とりあえずの解決策は下記のように、

-(3)と、単項演算子の後ろはカッコで囲むことで、正常に計算されます。

以上、数値計算の話と、バグ報告でした。

本当にやりたいことリスト

(ブログの終わりにやりたいことを書いておきたいと思います)

  • 求職活動・・・このブログで興味を持った人一声かけてください。m(_ _)m
  • Androidプログラム
  • Web系のプログラム