微分方程式難しいねぇ…そりゃそうですか。
未知関数の微分積分を含む方程式ということで、
基本的には関数当てゲームというわけで、そりゃ難しい。
式を変形して積分して解くんですけどね。
一階線形微分方程式の解の公式なんてのがあって、まぁ覚えればいいと思うのだが、
とんでもない式だし、うまく積分できないならその方程式は解けんぞと。
しかし、自然界のいろいろを表す式って微分方程式も多いそうだ。
例えばだけど、RLC直列回路に直流電圧をかけたら、正弦波交流電流が流れることとか。
L(di/dt)+Ri+(1/C)∫idt=E、という方程式を解けばわかるんだよね。
まぁいろいろあるんですよということです。
最近3つのソフトウエアを同時に設計・開発してる。
1つはほとんど完成してるのだが、残り2つが大変。
プロトタイプを作って、機能を実装して…ということを繰り返してる。
まぁ小規模なプログラムだからできることですよね。
それで、Rich Text Formatを取り扱おうかなとか思って調べてた。
RTFなんだが、これが非常に冗長。圧縮するとすごい容量が減る。
というわけで圧縮したものをBase64に変換しておこうと。
IronPythonで開発してるが、try~finallyだらけで読みにくいので、C#で書こう。
どうもPython 2.5からwith構文というのがあるそうだが、残念ながらIronPythonでは実装されてない。
まずファイルを開き、圧縮したものをBase64に変換してコンソールに出力する件。
using( System.IO.FileStream fst=new System.IO.FileStream(fname,System.IO.FileMode.Open) ){
byte[] buf=new byte[fst.Length];
fst.Read(buf,0,buf.Length);
using(System.IO.MemoryStream mst=new System.IO.MemoryStream()){
using(System.IO.Compression.GZipStream gzst=
new System.IO.Compression.GZipStream(mst,System.IO.Compression.CompressionMode.Compress)){
gzst.Write(buf,0,buf.Length);
}
byte[] gzbuf=mst.ToArray();
Console.WriteLine( System.Convert.ToBase64String(gzbuf) );
}
}
using構文でC#ですら目が痛いが、IronPythonでは全部try~finallyで書いてるのでさらに目が痛い。
System.IO.Compression.GZipStreamにおいては、
書き込まれたら圧縮処理して、コンストラクタで指定されたストリームに書き出すストリームを提供、
コンストラクタで指定されたストリームから展開処理したものを、読み込むことができるストリームを提供、
のどっちかをできる。
しかし使いにくい仕様なんですよ。
圧縮時、あらかじめ、System.IO.MemoryStreamで圧縮結果を受けるストリームを作っておく、
コンストラクタで、このストリームと、System.IO.Compression.CompressionMode.Compressで圧縮モードだとする。
それで、GZipStreamのに、Writeで書き込む。
そして、GZipStreamを閉じたら、圧縮処理完了。受けるストリームには完全な結果が入ってる。
展開処理だが、これは明らかにめんどくさい。
Base64をバイト列に変換して、MemoryStreamのストリームに書き込んでおく。
GZipStreamのこのストリームを展開するストリームを作る。
このストリームを直接使えればいいのだが、Seek不可なので困ることがある。
System.Windows.Forms.RichTextBoxのLoadFileメソッドでRTFのストリームを渡したかったのだが、
Seekできんみたいな例外を投げるので、無理なんだなと。
そうなるとMemoryStreamのストリームにGZipStreamのストリームからReadしたのをWriteすると…
こんな作業をしないといけない。これがかなりめんどくさい。
以上の処理をするもの。
byte[] gzbuf=System.Convert.FromBase64String(gzb64)
using(System.IO.MemoryStream rtfst=new System.IO.MemoryStream()){
using(System.IO.MemoryStream gzmst=new System.IO.MemoryStream()){
gzmst.Write(gzbuf,0,gzbuf.Length);
gzmst.Position=0;
using(System.IO.Compression.GZipStream gzst=
new System.IO.Compression.GZipStream(gzmst,System.IO.Compression.CompressionMode.Decompress)){
byte[] buf=new byte[1024];
while(true){
int readlen=gzst.Read(buf,0,buf.Length);
if(readlen==0) break;
rtfst.Write(buf,0,buf.Length);
}
}
}
rtfst.Position=0;
rtfboxLoadFile(rtfst,System.Windows.Forms.RichTextBoxStreamType.RichText);
}
これはひどい。上で説明したとおりのことが書いてあります。
gzmst.Position=0; rtfst.Position=0;
はいずれもMemoryStreamにWriteした後、改めてスタート地点に戻って、
ここからReadしていただくという意味です。
ToArrayで配列に変換する分にはあまり気にしないけど、Readで読むときは重要。
あと、GZipStreamを読み取るのに、1024Bytesのバッファを用意して、
ループ回して、読み取り成功分だけMemoryStreamに書いていく。
Readの返り値は読み取り成功のバイト数だが、読めなくなれば0になるのでこれで抜けてる。
さっきのFileStreamでは、Lengthプロパティがあったけど、GZipStreamでは使えない。
だからこういう、まぁ正攻法でやらんといかんと。
これの使い道だが、TCPとかで通信するときデータを圧縮すると。
そのとき、データをGZipStreamのにWriteして、受けるMemoryStreamの中身を送信すると。
受信してMemoryStreamに投げ込んだら、これをGZipStreamで受けてReadしてMemoryStreamにWrite、
最後にMemoryStreamの中身を確認すれば本当に送りたかったデータがあると。
まぁこういう使い道が多そうです。
ちなみに。System.IO.Compression.DeflateStreamという類似したクラスがあります。
DeflateはgzipやZIPの原理です。Deflateを使ってgzipを実現してるのね。
今回のは別にgzipでなくてもDeflateでもよかった気はするが、gzipの方がデバッグに便利だしいいや。
こんな手間をかけてやるかは知らんが、有用なライブラリなので使うといいと思う。