数値計算
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系のプログラム