2009-12-09[n年前へ]
■エクセルの計算ワークシートをRubyでC言語に変換してみよう
この記事のスクリプトや、(下記のエクセルファイルとは違いますが、より有用そうな)エクセルファイル例、そして、そのエクセルファイルを変換したC言語ソースを保存し、また、つらつら考えことなどを「続 エクセルの計算ワークシートをRubyでC言語に変換してみよう」 に書きましたので、下記記事を読んだ後には、上記記事(さらにその後に続く記事など)を引き続きご覧ください。
先日、「エクセルの計算ワークシートをRuby計算スクリプトに変換してみよう」でエクセルで作った離散化シミュレーション用.xlsシートをRuby Script(プログラム)に自動的に変換する、Rubyスクリプトを作ってみました。基本的には四則演算で(反復収束計算手法を用いることにより)「この世界を(エクセル上で)シミュレーションするスプレッドシート」を作ったなら、それを他のプログラミング言語に「変換する」アプリケーション例として、エクセルのシートをRuby言語に変換するソフトを作ってみたわけです。目標は「何だかすげー!、けど、役に立たねー!」です。
というわけで、引き続き、今日はエクセルのシートをC言語に変換するRubyスクリプトを書いてみました。もちろん、今回も、基本的には四則演算と数値だけで作られ、反復収束計算手法を用いることで最終的な計算結果を得るような「シート」を前提にしています。
というわけで、書いたコード"xls2c.rb"はこんな具合です。
require 'win32ole' def getAbsolutePath(filename) fso=WIN32OLE.new('Scripting.FileSystemObject') fso.GetAbsolutePathName(filename) end def getAlphabet(n) val=n.to_f/25.0 mod=n%25 result='' result+=('A'..'Z').to_a[(n-val)/25] if val>1 result+=('A'..'Z').to_a[mod] end def defFunc(state,book) src='' book.Worksheets.each do |sheet| y=1 sheet.UsedRange.Rows.each do |row| x=0 record=[] row.Columns.each do |cell| if state==:def &&cell.Value.to_s!='' record<<' float '+getAlphabet(x)+y.to_s+'=0.;' end if state==:init &&cell.Value!='' record<<' '+getAlphabet(x)+y.to_s+ '='+cell.Value.to_s+';' if cell.Value.to_s!='' end if state==:calc &&cell.Formula!='' t=cell.Formula.sub(/[=$]/,'') record<<' '+getAlphabet(x)+y.to_s+'='+t+';' end x+=1 end if record.join('').gsub("\n",'')!='' src+=record.join("\n")+"\n" end y+=1 end end return src end filename=getAbsolutePath(ARGV[0]) excel=WIN32OLE.new('Excel.Application') book=excel.Workbooks.Open(filename) defsrc=defFunc(:def,book) initsrc=defFunc(:init,book) calcsrc=defFunc(:calc,book) book.close excel.quit GC.start puts <<INIT // autocreated C source from excel file // jun hirabayashi jun@irax.net http://www.hirax.net #include "stdio.h" // gloval variables #{defsrc} void init(void){ #{initsrc}} void calc(void){ #{calcsrc}} int main(){ int i; init(); for(i=0;i<10;i++){ calc(); } printf("C2=%f",C2); return 0; } INITこのスクリプトを、
ruby xls2c.rb ex.xls > sample.cという具合に実行すると、下のようなC言語ソースができあがります。
// autocreated C source from excel file // jun hirabayashi jun@irax.net http://www.hirax.net #include "stdio.h" // gloval variables float A1=0.; float B1=0.; float C1=0.; float A2=0.; float B2=0.; float C2=0.; float A3=0.; float B3=0.; float C3=0.; void init(void){ A1=1.0; B1=2.0; C1=3.0; A2=1.0; B2=2.0; C2=5.0; A3=1.0; B3=2.0; C3=3.0; } void calc(void){ A1=1; B1=2; C1=3; A2=1; B2=2; C2=B2+C1; A3=1; B3=2; C3=3; } int main(){ int i; init(); for(i=0;i<10;i++){ calc(); } printf("C2=%f",C2); return 0; }もちろん、今回もスプレッドシートの「セル」はすべてグローバル変数として取り扱い、エクセルが最初に行う初期化ルーチンを"init"関数として定義(作成)し、次に行う反復計算を"calc"関数として定義(作成)し、それを(適当に決めた)for文で10回繰り返す(計算を収束させるためには、実際にはもっと多く繰り返し計算をさせることが必要でしょう)、というソースです。
さて、このC言語ソースは、(たとえば、Borland C++ Compilerを使うなら)
bcc32 sample.cという具合で、sample.exeというバイナリができあがります。
いつか、エクセルのシートを変換し・作成したC言語プログラムをコンパイルすると、どれだけ遅くなるのか・どれだけ早くなるのかを、色々な環境で確かめてみたい、と思っています。