2012年3月2日金曜日

桁の小さい平方根の計算

とりあえず桁の小さい平方根の計算の処理は完成しました
次はBIGFloatを利用してもう少し大きい桁の平方根を計算したいです
完成まで長かったwて、やってないから長いんですけどw

後、HSPでグラフを描くモジュールも作成したいです
Perlでグラフを描くのは僕の技量では無理w

use strict;
use warnings;

my ($r,$ans);

($r,$ans)=&small_sqrt(20000.0,0);
print $r." ".$ans."\n";

($r,$ans)=&small_sqrt(0.0002,0);
print $r." ".$ans."\n";

($r,$ans)=&small_sqrt(20000.0,1);
print $r." ".$ans."\n";

($r,$ans)=&small_sqrt(0.0002,1);
print $r." ".$ans."\n";

# 平方根の計算。計算する桁が小さい
sub small_sqrt{

# 引数A:sqrtしたい値
my $value=$_[0];
# 引数B:これが1だとprint debug
my $on_debug=$_[1];

# 返り値用
# $r:error情報。-1:数値が大きすぎる:-2数値が小さすぎる
# $ans:解
my ($r,$ans);

if ($value>=1.0){
# sqrtしたい値が1.0より大きい場合
($r,$ans)=&small_sqrt_L_in($value,$on_debug);
}else{
# sqrtしたい値が1.0より小さい場合
($r,$ans)=&small_sqrt_S_in($value,$on_debug);
}

return ($r,$ans);
}

# 平方根の計算。計算したい値は1.0より大きい
sub small_sqrt_L_in{

# 計算したい値
my $p=$_[0];
# これが1だとdebug
my $on_debug=0;
$on_debug=$_[1];

if ($on_debug==1){
printf "sqrt(".$p.")"."\n";
}

# &some_divはsqrtしたい値が1以上の時呼び出す
# sqrtしたい値は10の何乗の2乗か?求める
my ($r,$r_A,$r_B)=&some_div($p);

# &in_calc_0p1to0p0000001は実際に計算する
my $ans=&in_calc_0p1to0p0000001($r_A);

if ($on_debug==1){
printf $r."\n";
printf $r_A."\n";
printf $r_B."\n";

printf $ans*$r_B."\n";
}

return ($r,$ans*$r_B);

}

# 平方根の計算。計算したい値は1.0より小さい
sub small_sqrt_S_in{

# 計算したい値
my $p2=$_[0];
# これが1だとdebug
my $on_debug=0;
$on_debug=$_[1];

if ($on_debug==1){
printf "sqrt(".$p2.")"."\n";
}

# &some_mulはsqrtしたい値が1より小さい時呼び出す
# sqrtしたい値は0.1の何乗の2乗か?求める
my ($r2,$r_A2,$r_B2)= &some_mul($p2);

# &in_calc_0p1to0p0000001は実際に計算する
my $ans2=&in_calc_0p1to0p0000001($r_A2);

if ($on_debug==1){
printf $r2."\n";
printf $r_A2."\n";
printf $r_B2."\n";

printf $ans2*$r_B2."\n";
}

return ($r2,$ans2*$r_B2);

}

# sqrtしたい値が1以上の時呼び出す
# sqrtしたい値は10の何乗の2乗か?求める
sub some_div{
# $r:error通知用。普通は1。10の301以上だとerror
# $r_A:繰り返しで/100.0づつしていく
# $r_b:10のX乗の2乗か?のXの値を入れる
my ($r,$r_A,$r_B)=(1,$_[0],1.0);
# $r_A=&mul_10_X_count(301);
if ($r_A>&mul_10_300_count()){
$r=-1;
}
while ($r_A >= 100.0) {
$r_A/=100.0;
$r_B*=10.0;
}
return ($r,$r_A,$r_B);
}
# sqrtしたい値が1より小さい時呼び出す
# sqrtしたい値は0.1の何乗の2乗か?求める
sub some_mul{
# $r:error通知用。普通は1。10の301以上だとerror
# $r_A:繰り返しで*100.0づつしていく
# $r_b:0.1のX乗の2乗か?のXの値を入れる
my ($r,$r_A,$r_B)=(1,$_[0],1.0);
# $r_A=&mul_0p1_X_count(285);
if ($r_A<&mul_0p1_285_count()){
$r=-2;
}
while ($r_A <= 1.0) {
$r_A*=100.0;
$r_B/=10.0;
}
return ($r,$r_A,$r_B);
}
# 計算の処理。in_calcを8回呼び出す
sub in_calc_0p1to0p0000001{
# $p:この数値以下で最も大きい数値を導きたい。等しくてもいい
# $ret0~$ret8:計算結果が入る。少しづつ小さな単位を計算して代入
# &in_calcの3つめの引数:計算する単位
my $p=$_[0];
my $ret01=&in_calc($p,0,1);
my $ret02=&in_calc($p,$ret01,0.1);
my $ret03=&in_calc($p,$ret02,0.01);
my $ret04=&in_calc($p,$ret03,0.001);
my $ret05=&in_calc($p,$ret04,0.0001);
my $ret06=&in_calc($p,$ret05,0.00001);
my $ret07=&in_calc($p,$ret06,0.000001);
my $ret08=&in_calc($p,$ret07,0.0000001);
return $ret08;
}
# 計算の処理。一桁だけ計算
sub in_calc{
# この数値以下で最も大きい数値を導きたい。等しくてもいい
my $expression=$_[0];
# 計算結果を入れる
my $exp01=$_[1];
# 計算の単位
my $unit01=$_[2];
# 返り値用
my $ans01=0;
# 乗算の基
my @for_mul;
for (0..9){
$for_mul[$_]=$exp01+($_*$unit01);
}
# 乗算の基を2乗
my @of_mul;
for (0..9){
$of_mul[$_]=$for_mul[$_]*$for_mul[$_];
# print "i:$for_mul[$_]:i*i:$of_mul[$_]\n";
}
# X以下で大きい数値を求める
for (0..9){
if ($of_mul[$_]<=$expression){
$ans01=$for_mul[$_];
}
}
# print "解の候補:$ans01\n";
$ans01;
}
#printf &mul_10_X_count(0)."\n";
#printf &mul_10_X_count(3)."\n";
#printf &mul_10_300_count()."\n";
#printf &mul_10_300_count()*&mul_0p1_300_count()."\n";
#printf &mul_0p1_X_count(0)."\n";
#printf &mul_0p1_X_count(3)."\n";
#printf &mul_0p1_300_count()."\n";
#printf &mul_0p1_300_count()*&mul_10_300_count()."\n";

# 10の引数A乗の数を返す
sub mul_10_X_count{
my $x=1.0;
my $i=$_[0];
$i--;
for(0..$i){
$x*=10;
}
return $x;
}
# 10の300乗の数を返す
sub mul_10_300_count{
return &mul_10_X_count(300);
}

# 0.1の引数A乗の数を返す
sub mul_0p1_X_count{
my $x=1.0;
my $i=$_[0];
$i--;
for(0..$i){
$x/=10;
}
return $x;
}
# 0.1の285乗の数を返す
sub mul_0p1_285_count{
return &mul_0p1_X_count(285);
}

2012年2月22日水曜日

裏テーマ

僕が今書いている自費出版用の書籍の裏テーマは
問題をプログラミングで解く。と
数式の解の近似値を得る。です

人には様々な問題がある
社会にも様々な問題がある
それをプログラミングを利用して解こう
そういうテーマです
今書いているやつには
人の問題、社会の問題を解くようなプログラミング例は
思いついていないので書けませんが
プログラミングで解けることは
数学的な問題や
物理的な問題だけじゃないと思うんです
それを書籍を書くことを通して
道筋をつけたい
そういうテーマです
なので今やってるルートの計算なんて
(それが終われば2乗である数になる近似値だけじゃなく
 X乗(まずはXは整数)すればある数になる近似値を解くプログラムを書きたいです)
ググれば出てきそうですが
あえて自力で解こうと思っています

数式の近似値を得る。というテーマは
数式の解を解くって難しいんですよ
3次式の解を求める解の公式とか
やたらややこしいんですよ
でもそれは近似値ならば少数として
より把握しやすい値になるかもしれない
正確な解ってややこしいし
解き方も難しいし
なのでコンピューターの力で
強引に近似値を得てしまおう
書籍に載っているやり方を応用して
式の解を強引に得て欲しい
そういう道の道筋をつけたい
そういうテーマです

2012年2月17日金曜日

とりあえず

とりあえず、ルートを求める処理は出来てます
少々の改良と
(改良ってかスクリプトのサブルーチン化で呼び出せるように。です)
コメント書くのとサブルーチンの名前のリファクタリングが
TODOとして残ってるんですが
中途半端でも載せれば、眺めながらやる気出るかもしれないので
載せときますw

追記:一応、スクリプト完成したので削除w

2012年2月16日木曜日

自費出版を目指すブログ

TACKは数学っぽい経済学っぽいプログラミングっぽい書籍を自費出版するのが夢です
数学と経済学とプログラムを足して3で割ったような書籍です
あんまり言ってないんですが(笑)僕の夢は作家になることです
作家は何冊も書かなければ作家とは言えなく
文章を書くことは好きですが、作家になれるほど大量に書いている訳でもなく(笑)

インタプリタ/コンパイラの作成を目指すブログ で
このネタ書籍で使えるかも?と思ったネタを書いたので
それを機にGOOGLEのブログに投稿しながら執筆していこうかな?
と、考えるに至りました

はてなの方が見てくれそうですが
GOOGLEのブログはアフィリエイト?が使えるみたいなんで
収入になるかもしれないし
こっちで書くことにしました

幾つか寝かせてあるネタもあるので
ブログに投稿しながら
それをマイルストーンとして
ある程度の分量になるまで執筆して
そしたら自費出版しようと思いました

大学でゼミの頃、空想していた概念をまとめて自費出版する!というのは作家を目指す上での最初の僕の夢です!
最初は卒論にしようと思いましたがまだ構想があやふやで、実行するのに踏み切れませんでした
あれから10年経つんだなぁ
大分形になって来ましたが
手を伸ばせば、遠ざかり
手を離そうとすると、近づいて来るようで
難しいですね
そろそろ概念をきちんと文章にすることを決意しようかな?と考えているところです
なんか理想の人みたいな概念みたい
手を伸ばせば、遠ざかり
手を離そうとすると、近づいて来るようで

自費出版したら絶版になるまで
書いた記事は削除する予定です

文章をよりよくするためのコメントもお待ちしています

2012年2月6日月曜日

BIGFloat

先日ルートを計算するPerlスクリプトを書いていて
Perlのdoubleの有効桁数は何桁だったかな?と思ってググったら
PerlにはBIGFloatがあるみたいですw
ルートの計算の後で桁の大きい少数を扱うスクリプトを書こうと思ってましたw

あろうがなかろうが自力で処理を書いてもいいんですけど
めんどくさいしwバグが怖いので
素直にBIGFloat使う予定です

ルートの計算は大筋完成していて
後は整理してコメント書いて完成です

#最近、コメント書くのめんどくさいw

2012年2月3日金曜日

上限と下限の条件分岐

rootの計算はdoubleを使ってるので
ものすごい大きい数から
ものすごい小さい数まで計算できるので
いらないかもしれませんが
一応、考え方として
どれくらい大きい数から
どれくらい小さい数まで計算できるか
決めておいた方がいいですよね

とりあえず、最大1e+300
最小1e-300まで計算できるように決めました
決めるったら決めるw

でそんなのを求めるスクリプトです

追記:doubleの下限は300桁ちょいくらいなので
doubleの桁数も考え最小1e-285に変更しました
use strict;
use warnings;

printf &mul_10_X_count(0)."\n";
printf &mul_10_X_count(3)."\n";
printf &mul_10_300_count()."\n";
printf &mul_10_300_count()*&mul_0p1_X_count(300)."\n";
printf &mul_0p1_X_count(0)."\n";
printf &mul_0p1_X_count(3)."\n";
printf &mul_0p1_285_count()."\n";
printf &mul_0p1_285_count()*&mul_10_X_count(285)."\n";

# 10の引数A乗の数を返す
sub mul_10_X_count{
my $x=1.0;
my $i=$_[0];
$i--;
for(0..$i){
$x*=10;
}
return $x;
}
# 10の300乗の数を返す
sub mul_10_300_count{
return &mul_10_X_count(300);
}

# 0.1の引数A乗の数を返す
sub mul_0p1_X_count{
my $x=1.0;
my $i=$_[0];
$i--;
for(0..$i){
$x/=10;
}
return $x;
}
# 0.1の285乗の数を返す
sub mul_0p1_285_count{
return &mul_0p1_X_count(285);
}

2012年1月23日月曜日

いきなりサブルーチンを書く

現在やっていることは
ルートの計算なんですけど
ちょっと行き詰ってました

現時点で100以下の数値のルートは求めれるんですけど
(1以下の数値は有効な桁が少なくなりますが、たぶん求められる)
100以上の数のルートをどうやって計算しようかと

1e+3以上1e+5以下なら求める数字を1e+5で割って解を1e+3で割って
ちなみに1e+xとは10のx乗のことです
1e+3は100。1e+5は10000です
ちょうど1e+(2n+1)以上1e+(2n+3)未満になるように
再帰的な解決の仕方をしようと考えていたんです

でも、再帰で解こうとしたのが誤りで
結局繰り返しで解くことにしました
解を求める数字が100以上なら100で割り返り値Bにする変数に10掛けます(初期値1.0)
更に100以上なら同じ計算を続けます
何回か100で割った数値を返り値A
何回か10で割った数値を返り値Bとします
返り値Aのルートを求めて返り値Bをかけると、計算の出来上がり
1.0より小さい数も似たような計算で処理します

やっぱ僕は再帰苦手やわー
処理の全貌がつかみ難いのが苦手です
後、処理を書いてからサブルーチンに分割しようとしたのも敗因です
いきなりサブルーチンを書いてくっつけるのも良い手段ですね
ちなみにこの処理はまだメモを書いただけで
これから処理を書く予定です