来月中には出そうと思っているので、一応書いておく。
ってか、書いちゃえ。
予告ってやつですよ。
[PR] 古い通信アプリにも安心を。OverSslの継続公開についてはコメントをください。
Hobby::Excelの最近のブログ記事
円周率を追加したアドインの評価を完了。
あとはドキュメントだけ。
鋭意執筆中。
公開されるのは来週・・・かな。
んー、おまけにいくつか関数ぶち込んであるんで、ぜひレジストして全関数を使ってほしいのだけどなぁ。
というのはさておき、現在公開中の0.7.1にもある問題が解決できていない。
そして、アドインを登録しようとして、重大なエラーとやらが出る。
Heap blockなんとか~ってエラーだとわかり、解放時のエラーらしいというのは分かったのだが、デバッグモードでトラップするのは、非常に困難。
- Excelにあらかじめアドイン(ちゃんと登録できるやつ)を設定しておく
- デバッグビルド物件に置換
- VSデバッグモードでExcelを起動(アドインを引数にしない)
- 操作等を実施
- 例外ダイアログが出たら、デバッグでコードが出るところまで何度かボタンをクリック
これで、何とか原因を突き止めることができる。
今回の問題は、デバッグ実行時の引数にアドインを指定してると呼び出されない関数にあったので、はじめはわけが分からなかった。
#現在リリースされているものとは違うコードです。
こういう手法に気付くまでが大変だけど、コードや呼び出し履歴を掴めれば、どこの何が原因かを判別するのが容易になる。
ま、気にする人はいないだろうけど、メモがてら。
- 絶対値・・・実装。
- 円周率・・・実装。
- SQRTPI相当・・・実装延期。
- 桁指定・・・実装延期。
- SUM系・・・実装延期。
- 数値化・・・追加実装。
ま、こんなところか。
円周率は出せているし、絶対値も現状用意済みの内部関数を呼ぶだけ。
あとは数値化だが、これも何とかなったっぽいので、これで、出せる・・・と思うのだが、デバッグモードで実行すると、例外がボロボロ出るところがあるので、原因を調べてからにしたい。
数値化はとても便利かも知れない。
#現状、Excelには255文字以上の数値文字列を数値化する関数が無い。
64bit版もできるんだけど、これは要望か何かがあるなら考えるけど、メジャーバージョンアップまで非公開の予定。
と、声に出して言いたい。
パイと言っても円周率(π)ですが。
いや~、スタティックライブラリのリソースからロードするのって、結構難しいですね。
あと、ちょっとリソースファイルの編集について、インクルードを処理するのは、リソースビューで開いて、「リソースファイルのインクルード」でやると簡単だったことをメモしておく。
で、πですが、こんな感じ。
しかし、もし、仕様ならば、仕方ないし、そうじゃなくても、現状そうならばそうで対処するしかない。
#回避策があるのならば、それに頼る。
##回避策が無いのに、不具合を仕様と言っちゃう(再起動したところで、再現を繰り返すだけ)のは愚かなだけだが。
とりあえず、関数の説明は同梱のPDFにお任せしちゃうことで、無しにすることは不可能ではないので、それで対応してみる。
さて、円周率3万桁、ちゃんと出るかはこれから確認。
例のXLLSDKをやっと取り込んだんだけど、やはり引数なしでうまくいかない。
サンプルだと引数なし関数の登録がうまくいくのかと思っていたのだけれど、試しに関数の説明まで出そうとしたところ、引数ありになってしまうことが分かった。
関数の説明を端折ると、引数なしとして登録できる。
これは誰のせいなのか、全く分からないのだけれど、Excelのせい?なのか・・・よくわからん。
とりあえず、Excel2003でも2010でも挙動が同じだったこと、VS2008でもVS2010でも結果は変わらなかったことをメモとして残しておく。
いやはや、さて、困ったぞ。
本読んでもこのあたり書いてないんだよなぁ・・・
あと、文字列(関数の説明以降)の最後1文字が切れるのも俺のせいじゃないらしい。
そういえば、引数なし関数がうまく登録できないとき、関数の引数んとこに空白1文字入ってるっぽいんだよね。
余分な1文字と無くなる1文字で辻褄は合ってるのか・・・?
んー、英語版Excelで試してみるか・・・
超長文字列のリソース埋め込みができそうなので、Excelのアドインで円周率を3万桁ほど返してみようとしたところ、とんでもないところで躓くことになった。
#悩みまくりのお手上げ。
なんと、引数なし関数の登録ができないのだ。
なぜ、できないのかは、よくわかっていない。
SDKのサンプルではいとも簡単に登録できているし、引数ありなら問題ないのに、引数なしになった途端に破綻する。
#途端破綻、ドタンバタン。
ま、いい機会だから、気になってたところを直しつつ、VS2010に移行して、メモリ使用効率もあげちゃおうかと考え中。
#計算部分には手を入れないつもりなので、高速化はできないと思う。
かなり手間だけど。
同時に64bit対応化も。
昨日の記事で、発見したXLLSDKのヘルプドキュメントをちらっと見たところ、非同期関数を定義できるとか。
長時間掛処理でExcel無応答になることが、これで防げるのかどうか、どちらにしろ、Excel2010の新機能だと思われる。
長時間処理といえば、HyperLong系の処理なのだが、これ、非同期にしたら、実行時間は変わらなくても、処理的に軽くなるかも知れない。
やってみる価値はありそうだ。
過去記事の誤り。
「署名があるとか無いとか、そんなことはどうだっていいんです」という結論。
やってみることは大事だね。
ただ、まだ、「動いた」というレベルだけれども。
とりあえず、Excel4系関数を排除して、Excel12系関数(SDKだと、_WIN64定義時に呼べないようになってるのを解除)のみにして、x64ターゲットでコンパイル。
すると、登録もできるし、関数も呼べる。
手放しで喜ぶのは構造体のアラインメントを詳しく確認してからなのだが、とりあえず、Excel2007と同程度のことはできそう。
それ以上の何かを期待できるかも知れないのだが、まずは、そこから。
・・・と、少し満足してたら、こんなものが!!
出てるなら出てるって教えておくれよ!!!<いや、無理。
仕方ない、中身調べてみるか・・・
Addin for Excel 95-2007 Basic EditionのVer0.7.1を公開した。
せっかくコンピュータ使ってんだから、有効桁なんてケチなこと言わず、どーんと数百~数万桁使っちゃえ的に加減乗除+開根+比較までできるってことは、100円電卓レベルの操作を多桁で実現できちゃったってことだ。
開根には時間掛るけど、100円電卓では得られない精度。
互換関数使えば互換性と処理速度と精度のいいとこ取り。
是非使ってみて欲しい。
HyperLong系の加減乗除、開根、大小比較まで出来るようになっている0.7.1もまだ公開されてませんが、次回(0.7.2)の予告。
絶対値取得関数。
開根関数には必須。
実は、文字列として、たとえ負の数だろうが、- を先頭に付けるだけで、符号反転できたりする仕様なので、条件判定して、- を文字列連結しちゃえばいいんだけど、それだと32767文字超えちゃう可能性があるので、関数として用意しておいたほうがいい。
円周率定数関数。
定数なので、計算処理無しで返したいところ。
これまで、「そんなに長く円周率算出して実際使うのは10ケタも無いじゃん」って言われ続けてきた円周率をこれでもかというくらいに長く利用できるようになったので、なが~く出せるように。
ついでにSQRTPI関数っぽいものも。
あとは提供方法考え中なのが、返却の文字列長指定。
あると、結構便利な予感。
他には、SUM系の関数をと考えてるんだけど、今のところ未定。
ま、こんなところかな。
徐々に追加すれば良い。
Excelの多桁開根関数を追加したやつ、登録しました。
Addin for Excel 95-2007 Basic Edition
多分、来週には公開されるんじゃないかな。
サポートはこちら。
今回のバージョンは、0.7.1になりまする。
是非、ご利用くださいな。
多桁数比較関数として、HLCOMPを用意してみたものの、Excel95のIF関数内で条件に使うと、なぜか#NUM!エラーになる。
HLCOMPを別セルで計算して、その値を条件に使えば問題ないし、IF関数の真偽値としてエラーを返す可能性の無いリテラルを指定すれば、これもエラーにならない。
HLCOMPの仕様は、引数2つをとり、>なら1、=なら0、<なら-1を返すというもの。
確かに、#NUM!エラーを返すパスもあるんだけど・・・
同様に、#NUM!を返す可能性のあるSQRT関数を条件に使う場合、そんな問題発生しないんだよなぁ。
で、Excel2003だと、再現しない。
#95~2003のどのバージョンまで再現するかは未確認(やらなきゃまずいかなぁ)。
原因はExcel95にあると思うのだけど・・・
ExcelでSQRTに負数を与えると、#NUM!エラーとなるわけだが、多桁の現実装は絶対値に対して平方根を計算している。
互換関数もよさげにできたっぽい評価結果が得られてるんだけど、そろそろ公開をと考えているのだが、さて。
今回比較関数を用意したので、負数を事前に排除することもできるわけだし、#NUM!エラーを返すようにするかな。
追加で絶対値を返す関数を用意する意味も出てくるし。
Excelで多桁計算。
現在公開されているのは、四則演算まで。
開根実装の目途はついた(と思っている)。
遅いけど。
遅さをカバーする意味も含めて、全Excelで同じ桁数を返す互換関数を用意しようかと思っている。
255文字分で表現可能な値を返すってやつ。
返却を短くできる分、処理が軽くなるので、開根の遅さをある程度カバーできる。
入力(引数)文字数はExcelバージョン依存で出力(解)文字数は互換となる予定。
乗算の打ち切り方について、まだよくわかってないので、入力依存。
除算・開根の打ち切りはできる。
加算・減算の打ち切りはしない。
で、提供予定としておく。
ついでに、比較演算関数も加えたいなぁと考えている。
そして、あともう2つほど関数を考えているのだけど・・・
高速化ってのは、処理を軽量化する方向でやるのと、そうでない場合があると俺は思う。
前者はたとえば、条件分岐を減らしたり、計算回数を減らしたり、より簡易なコードにすることが多いと思う。
#Simple is Bestってやつ。
今回(今日)の大幅な高速化は後者。
1位にいくつか数を加えた場合の桁上がりを処理するのは、1位値が10を超える場合のみでいいという、いわゆる打ち切り条件を加えた。
#条件によっては効果が無いけれど、今回はやる前から処理分岐率50%で、その分の処理を打ち切れるという、かなの効果を見込んでいた。
桁上がり処理は、全桁を確実にループするため、条件によってやらなくていいというのは、メリットだろうと思ったわけだ。
おまけに、その処理は何度も通るため、結果、条件判断に掛るコストよりも大幅な処理速度改善につながったわけだ。
にしても、びっくりするのは、これで限界と思ってた60秒から30秒台まで高速化できたことよりも、処理のほぼ半分も無駄なことやってたこと。
さすがに俺もこれには笑うしかない。
#その後、もう少し手を入れて、30秒切るところまできました。
環境は、Core2Duo L7500(1.6GHz)のまま。
開根時に多用してる減算をどうにかしたら速くなるんじゃないかということで、加算減算を見直し。
今までは、加算では各桁加算ループと桁上がり処理ループに分けていたんだけど、ループを1回で済ませられるように変更。
減算も、桁下ろしループ、各桁減算ループ、桁上がりループの3ループを1ループ化。
これだけで、60秒を切りそうな勢いで高速化できた。
他にもいろいろと手を入れているものの、減算の変更は一番効いたと思う。
もう少し見直して、余裕で1分切りを目指したいと思う。
#でも、実用とは言い難いので、別の策を考え中。
開根筆算では2桁ずつ下ろしてくる処理がある。
これを省略してみたところ、少し速くなって2や3の開根で80秒を切れるようになった。
これが限界だと思っても、諦めなければ、その先がある。
でも、多分、今のままで1分切るのは難しい。

※A3には =HLMLT(A2,A2) で検算。
多桁開根確認中、数バイトのnewでヒープ破壊の例外発生。
何が原因かは目下不明。
Free Heap block xxxxxxxx modified at yyyyyyyy after it was freed
と言われるので、yyyyyyyyアドレスを見ると、確かに周りと違う値。
参照変数は、別スコープに移動したし・・・飛び地を不用意に書き換える処理は入っていないはず。
OS再起動して再現するようなら調査続行か。
メモリ使用量を減らしたり、演算回数を減らしたりして、処理速度アップを狙ってはいるのだけれど、どうも、方法にも限界はあるし、そもそものクラスのメモリ使用方法自体にもボトルネックがあって、どうにも速くならん。
2の開根で32767桁(文字(整数部や小数点等を含む))、二乗誤差は最小位+1なのはいままで同様。
二乗検算まで含めると結果表示まで、約2分。
そう、何とか2分を切るくらいまでは高速化(とは言えないが)できた。
開根のみであれば、なんとか90秒を切れるようにはなった。
#非常にうれしいのだが、全く実用的ではない。
しかし、これ以上高速化しても、恐らく1分の壁すら到達できないだろう。
なんにしても、クラスの基本部分を弄るしかないだろうと思っている。
開根くらいでもたついていては、開立や三角関数なんてどんなに時間が掛ることか知れたもんじゃない。
公開されたようです。
Addin for Excel 95-2007 Basic Edition ダウンロードページ
Addin for Excel 95-2007 Free Edition ダウンロードページ
不具合修正されてますので、是非。
ずっと考えていたけど、無いんですよね、必要な場面って。
昨日からの続き。
そして、構造体にコンストラクタを用意したところ、構造体を取り込んだ共用体でコンパイルエラーが発生する罠。
曰く、「共用体メンバに既定のコンストラクタを持たせることはできません」だそうな。
じゃぁ、既存構造体から新たに継承したクラスを作って・・・とかやると大手術になってしまうので、仕方ないからそれは次期バージョンにて考慮。
今回は、newでサーチしてnewや変数宣言など、構造体メモリを確保している箇所で片っ端から初期化してやろうと思う次第。
#必要な個所だけ。
他に、実はnewしているのは決まってExcelに返すデータをエクスポートする箇所なので、それらを一か所に集約してやろうかと。
これで今回の原因は撲滅できるはず。
100%確実ではないけれども、再現させる方法だけは見つけたので。
Windows 7を起動して、評価に使用したExcel95ブックをExcel2007で開くだけ。
すると、再計算50%を過ぎたところあたりでExcelがエラー(動作を停止)を起こす。
ここら辺が微妙なんだけど、50%のときもあれば、そうでない場合もあり。
2回目には起こらないので、都度OS再起動が必要。
ところが、通常、プロセスの異常時には、「デバッグしますか?」のダイアログが出るのだけれど、このExcel2007は自動修復するのか、デバッガでアタッチするとプロセスが終了してしまう。
困ったことナリ。
デバッグモードでは再現したことがないので、あたりをつけようにも・・・
とりあえず全エクスポート関数の大部分をtry~catchで囲んでみたのだけれども、状況は好転せず。
なんだか変。
Windows7やVistaで動作確認しようと、アドインを設定して、気を良くしてHLDIV(10,3)とかやるとExcel停止・・・
なんでやねん!
デバッグしようとしても痕跡なし。
じゃぁとVS2008からデバッグ実行すると、全く落ちず。
そうこうしてるうちにExcel停止が再現しなくなる。
なんだこりゃ?
重要。
でも、検算するのがとても大変なのは多桁演算の宿命。
だから、大体正しければいい、というものでもない。
除算の評価結果を見ていて、変なことに気付いた。
検算をするとどうもおかしい。
筆算してみても、自分が間違えてる可能性もある。
Windows付属の電卓はかなりの桁数計算できるが、それと比較すると、やはりどうも多桁計算側がおかしいようだ。
使用メモリ量と演算回数を削減したんだけど、Excel95落ちるようになっちゃいました・・・
多分、どこかで例外発生しているってことなんだろうけど。
おっかしいなぁ・・・って、よく見たら凡ミス。
直したら動くようにはなったけど、やはり重い。
#加算・減算だけでなく、内部で加算処理をしている乗算も重い場合がある。
リソース絡みだと思いたい。
Excel95のリソース制約は一番厳しいので、Excel95で動けばExcel2003でも動く。
#Excel2007からは別物だけど。
なんか、すごく重い。
今のところ原因不明。
Excel95で桁数多い場合に発生中。
Excel2003では発生しないようだした。
Excel95では同じ計算でも発生するときと、しないときがあるようだ。
数としてはあってもいいんだけど、-0が返るパターンがあったので、符号補正を入れて修正。
別に、1文字2文字で困る文字数じゃないから放置してもいいんだけど、0と-0が違うかっていうと十進数演算の中では同じなので、だったら符号不要ということで。
多桁計算にも一応、四捨五入丸め処理を入れている。
というのは既出だが、Excelに文字数制限があるため。
つまり、表現上、数に制限が生まれるわけで、普通の有効桁と同じ扱いと思ってくれればいい。
除算した場合、循環小数なんかはその限界まで延びるのだけれど、そこで四捨五入が必要になる。
掛け算でも桁が多ければ丸める必要がある。
多分、浮動小数点絡みだと思うんだけど、微妙に異なるらしい。
それも、Excelのバージョンによって、微妙さも違うときた。
これにより、計算結果を評価するのがとても面倒なんですが・・・
どうやって評価しようかと、そんなところで躓く。
因みに、やってびっくりしたのが、=1.5*1.3-1.95って計算、Excel95でやると、2.22E-16になるんだぜ・・・。
どうしてやろうか。
多桁乗算を使って、=VALUE(HLMLT(1.5,1.3))-1.95を計算すると、Excel95でも、0が返るんだけどな。
乗算と除算、ずっと考えていた方法でできそうだったので、気合い入れて実装しちゃいました。
まだ評価していないけれど。
加算・減算・乗算・除算の4関数を軽く動作確認。
処理速度にはちょっと満足できないけれど、処理結果にはほぼ満足。
小数点以下数万桁の数に意味はあるのかと問われれば、あると答える根拠を持ち合わせているわけでは無い。
けれど、逆に本当に無視していい数なんてあってよいものかと考えたら、小数点以下数万桁でも無視するのは忍びない。
だから、できるだけ多くの桁を利用したい、そのための多桁計算関数。
そして、リソースを喰い尽くす罠。
さて、どのEditionに組み込んで、バージョンをいくつにするか、決めなきゃな。
とりあえず、今回はBasicEdition(有料版)かなぁ。
因みに、まだまだ追加予定の関数はありますよ。
E(10のn乗)も処理できるようになったので、なかなか使えそうなものになった。
A2セルには「=-1.23456789012345E-21+123」と、普通に計算してみた。
当たり前だが、有効桁(Excelの場合15桁らしい)丸めで無視される大きさなので、A2セルの結果は123。
A1セルのHLADD(自作関数)ではちゃんと計算できている。
HLADDなら、小数点や符号を含みながらも、3万桁超(Excel2003以前は255桁)まで対応している。
因みに、E±9999まで入力可能にしたので、本来は文字列で指定した方がよいのだが。
残念なのは、まだ加算と減算しかできないってところか。
Excel関数にすると気になっちゃうのがEの処理。
文字列引数を受け取る関数にしたんだけど、ある程度の桁数の数値を引数に指定すると、E付きの文字列になっちゃう。
できればEを有効に読み取ってあげたいところ。
もうちょっと時間を掛けよう。
ので、少しうれしい。
何でもそうだけど、実際にやろうとすると、意外に手間取るよね~。
一応、走査回数は標準2回(最悪n^2オーダーになる条件が含まれるけど)でパースできるようにした。
#本当は1回でやるべき。
符号は数値前のものだけ。
でも複数連続符号も認識できるように。
数値中のカンマや空白の読み飛ばし機能とか、数値前後の文字列を無視する機能とか、そういうのも実装。
そうでした。
いくら加算・減算ができるといっても、返却可能な桁数には制限があるのです。
桁数が足りないからエラーにしちゃうのは、まずいわけで、少なくとも、整数部が制限に収まっているのであれば、値を返すべきでしょう。
であれば、特定の桁位置の値で四捨五入しなければならないのですが・・・これがちょっと難しい。
四捨五入処理自体はそれほどのことはないのだけれども、返却文字列長を考えるとね。
Office2010βの32bit版を動かしてみた。
なんか変なこと起こるかなと期待半分だったけど、アドインは問題無く動作。
Excel2007からの文字列長(32767文字)制限もそのままらしいので、内部仕様も全く問題なし。
さて、64bitは、どうなのか。
32bit混在で動くわけがないから、Excel自体が32bitであると64bitの恩恵を受けられないってことは64bitネイティブって可能性が。
アドイン呼び出し部だけ32bit化されてる可能性はあるけど、それだとオーバーヘッドでかいだろうし。
件の構造体のアラインメントは64bitだと変わりそうな感じがしてて・・・
あぁ、恐ろしい。<すぐにやってみれよ、俺。
とりあえず内部処理だけだが、加算・減算ができるようになった。
処理速度はイマイチだけど、負数も小数も含めて、600桁計算しても大丈夫になった。
結果の一例を載せておこう
シェアウェア登録したのだけれど、使ってもらえてないのか、まだ売り上げが無いので、やはり追加関数で対応していきたい。
Excelで計算できる数値は10の309乗程度までの浮動小数点範囲なので、ここはひとつ、3万桁目指して計算できたら、何かうれしいことが起こることを期待しつつ実装中。
#3万桁使えるのはExcel2007以降だけど。