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言語プログラムをコンパイルすると、どれだけ遅くなるのか・どれだけ早くなるのかを、色々な環境で確かめてみたい、と思っています。