fc2ブログ

中の人の徒然草434 何も改善されない日本の社会システムに思いを馳せた

どうやら民主党が解散するようですね。それだけで一大ニュースとなっていますが、システム屋の私としては、どうでもよいちっぽけなことだと感じてしまいます。何故ならば、日本の社会システムそのものは何も変わっていないし、変わる見込みもないからです。また選挙ごっこしてお終いになるのが目に見えています。
よく誤解されるのですが、私は政治家や官僚を嫌っているわけではありません。ただ単に、システム屋として分析すると、何も生み出していないと指摘しているだけなのです。政治家個人を見ると、安部元総理大臣は良い人だと思っています。また、小泉元総理大臣に至っては、明治維新の英雄並みの実力を持つ方だと考えています。他にも、橋下市長は実力者であることは明白ですし、他にも優秀そうな方はいます。しかしながら、システムとはそういうものではありません。個人云々というレベルではなく、どれだけ偉大な英雄が居てもどうにもならないのがシステムというものです。
日本の場合、国家システムそのものがMS-DOSレベルの代物なので、今までのように優秀な個人が頑張ってもどうにもなりません。なぜならば、MS-DOSレベルのOSに、どれだけ高度なソフトウェアをインストールしても、まともに作動しないのと同様だからです。
ニュースを見ていると、特定の人のせいにする傾向があると感じます。タクシー業界の人が困ったら、小泉元総理大臣が悪いなどとありえない理論の飛躍を吹聴します。あまりにも非理論的すぎてあきれます。もしかしたら、今バッシングされている、野田総理も優秀な方なのかもしれません。でも、非理論的で何でも茶化すマスメディアを通してみると、酷い悪人のように見えてしまいます。
日本の国家システムにおいて、まともな情報を得られない時点で終わっています。民主主義というシステムは、まともな情報がなければ成立しないものです。報道の自由を、報道の暴力をしてもよいと誤解している節がある現在のマスメディアでは、信頼できる情報を得られないと考えるのが妥当です。むろんこれも、マスメディアだけを非難したいわけではありません。下劣な情報を買う私たち消費者にも責任があります。
ではどうすればよいのかといいますと、一から仕様を考え、今あるシステムを破棄して、新しいシステムを作るのが最善です。OSレベルでシステムが壊れている場合、これしか方法がありません。しかしながら、日本の問題は根深く、何でもお上任せで自分では考えない傾向が見受けられます。このお上任せの精神構造を何とかしない限りどうにもなりません。国民主権とは、国民が考えるのを前提とするものであり、国民が考えないとどうにもならない代物なのです。
システム屋として考えたとき、日本崩壊を防ぐには次のプロセスをするしかないと思います。

  1. 日本とどうあるべきなのかを国民が考える(仕様策定)
  2. 1で作った仕様を満たすべく、各専門家が実現方法を考える。(設計&実装)
  3. 2がうまく働いているのかを常に監視する方法を考える。(テスト)
  4. 一刻も早く新システムを稼働させる。(運用)
  5. システムは稼働するのと同時に問題は発生します。改善するべく1の手順に戻る。(改善)
※わかりやすいようにものすごく大雑把なものにしています。

ちなみにシステムというものは、常に改善できなければ意味がありません。存在そのものが有害になります。問題が発覚したら即改善するのがシステムの常識なのです。物事は常に変化します。変化に対処できなければ滅ぶのみです。それが世の理であり、戦後60年以上の変化しない時点でシステムと呼べる代物ではありません。破綻して当然です。それにもかかわらず、日本の風潮は変わるのを良しとしません。これが日本の国家システムが破たんしている一番の理由かもしれません。
日本は危機的状況です。解散したらなんとなくよくなる気がするという、いつものお祭りをしている暇はないと思います。大局的に見れば解散なんてどうでもいい出来事です。一刻も早く現実を受け止め、旧システムを破棄して新システムを稼働させましょう。それしか日本が生き残るすべがないと思います。

テーマ : 日記
ジャンル : 日記

中の人の徒然草433

日記なので今日思ったことを書きます。
自然数を関数として捉えると、微分したら1の線形関数だと思います。従って、1~∞の要素を持つ集合として考えるのではなく、線形関数を持つ集合もしくは、線形関数そのものだと考えるといろいろな物事が見えてきます。
例えば、濃度を考える(数を数える)という行為は、接線となる線形関数を見出す行為に等しいと思います。そう考えると、無限集合において、部分集合が上位集合の濃度と同じに見えるという不可思議な現象が解明できます。部分集合から上位集合を数えると、その濃度が等しく見えます。ただし、実数と自然数のように、位相空間的に離れすぎていると濃度が計算できません。ただ、部分集合から濃度を考えるという行為も無駄ではありません。その考えから、上位集合と部分集合の対応(関数)が考えられます。この関数も必要だという意見は多くの人が賛同してくれると思います。
しかしながら、定量分析として考えれば、濃度が同じに見えたらだめです。合同することができるという点は重要ですが、それはどちらかというと定性分析であり、定量分析をしたいときにその考えを適用すると混乱します。無限はこういった錯覚を生み出す極めて難しいものです。おそらく、これは始まりです。無限の性質はまだまだあるでしょう。そのとき人間ができるのは、一杯の水から海を分析することだけです。それが人間の限界です。
しかし人間の限界を悲観する必要はありません。自分の無知さと無限なる自然を受け入れたとき、少しずつ真実が見えてきます。有限の能力でも、使い方次第で無限に太刀打ちできます。分をわきまえれば、人類という大きな尺度でうまく大いなる自然と共存できるのでしょう。
人間はちっぽけですが、そのちっぽけさを受け入れたとき、自然は微笑みかけてきます。人という存在はちっぽけですが、その事実を謙虚に受け入れ、その小ささをうまく活用すれば、決してちっぽけでない結果が得られます。私の基本的思想はここから生じていると思います。私は自分をちっぽけな存在だと認め、他者に敬意を持ち、毎日を無為に過ごしています。それが幸せなのではないでしょうか?
人間には足りないものがたくさんあります。不平や悪口を無限に言えるでしょう。しかしながらそんなことをしても幸せになりません。その行為そのものが不幸です。ただ、足りないものと残酷な現実を冷静に見つめ、子孫のために黙々と改善していくのが人類の営みそのものだと私は考えています。
その観点から見ると、日本は今地獄へと突入していると思えてなりません。個々の人は、優しく真面目で優秀です。それこそ、世界に一つだけの花です。しかし、その土壌が腐っています。私たち個人が持つ魅力や能力が生かされていません。子孫のために、その土壌をどう改善するのか、真面目に考えないといけないと思います。
かくいう私も、つい最近まで研究にしか興味がない人間でした。俗物に興味がなく、研究室にこもるタイプの人間です。友と遊び、研究に明け暮れ、お客様の「有難う」の一言のために仕事も頑張り、家族団欒し、餓死しなければそれだけで幸せだと思っていました。しかしながら、30歳を超え、色々な体験をすると、そうもいってられないとわかりました。ふと、人ではなく、社会システムを分析すると、バグだらけでひどい代物でした。
この土壌の汚染(システム崩壊)現象は、個人攻撃しても仕方がないと思います。一人々の人間が、ちょっと周りを見渡せば気付ける些細なバグだらけです。そのバグが積もりに積もって、どうにもならない状態になっていますが、目をそむけず、子孫のために冷静にシステムを見つめる必要があるかと思います。
日本今末期ですが、意外と簡単に解決できるような気がします。システムというと難しくて縁がないもののように感じますが、誰にでも考えられる普通のものです。難しい言葉で惑わされているだけです。個々の人が自分の幸せだけを考えず、ちょっとだけ本来の優しさを発揮したら、大半の問題は解決できるのではないでしょうか?
日本は不景気だとかデフレだといわれていますが、本当に足りないのはお金ではなく、心(思いやりや謙虚さ)の不足と、心の価値の下落(金額しか評価しない)にあると私は思えてなりません。

テーマ : 日記
ジャンル : 日記

中の人の徒然草432 集合論をオブジェクト指向分析すると・・・

集合論をもっと抽象的に考えると、たった1言で全てを表現できます。

「集合は任意の集合を受け取り、任意の集合を返す対応である。」
※ハッカーが好みそうな再帰構造表現にしています。
※無限を扱う理論ですから、無限構造になるように記述しています。

実際にSetオブジェクトの実装を進めていたら、こうなりました。
それをさらにオブジェクト指向分析すると、この1言が出てきます。
ファジイ集合も考慮した場合、真偽を返すのではなく0~1.0の実数を返すことになります。
しかし、それでもまだオブジェクト指向としては終わりではありません。
もっと抽象化して考えると、何らかの集合を返すと定義したほうが思考ツールとして最高の状態になります。
集合論のパラドックスなんて解決できますし、もっと適用範囲も広がります。
カントールが見た世界は、こんな感じだと推測しています。
やはり、カントールは正しかった。数学の本質は自由なのですね。
彼自身、パラドックスは解決できる問題にしか過ぎないと考えていました。
全てが集合で記述できる世界。なんと天才なのでしょうか。
彼の抽象能力は高すぎます。100年前の人間だとは、とてもじゃないけど思えません。
天才の知的活動に時代なんて関係ないのでしょう。
これだから人間は素晴らしい。それに、世界はこんなに面白い。
この世界は面白いもので満ちています。
この考えを適用すれば、抽象度が高い集合プログラミングと高度な思考ができます。
ちょっと、集合プログラミングぽいものをしてみましたが、非常に面白いですね。
実装としては未完成だから今回は紹介しませんが、後日紹介するかもしれません。
雰囲気だけ書くと、論理型プログラミング+オブジェクト指向プログラミング+関数型プログラミングです。
それにLINQを加えると、非常にクールです。抽象度が非常に高いプログラミングとなります。
OSとかコンパイラの実装には向かないと思いますが(バイナリレベルで最適化した実装ができない)、もっと高い層のものを作るならば有効かもしれません。
趣味の一環としてぼちぼち研究を続けます。
ほかにも研究したいことが山ほどあるんだけど時間が足りない。1日100時間ほどほしいな。

テーマ : 日記
ジャンル : 日記

中の人の徒然草431 濃度計算と直観について思ったこと

昨日書ききれなかったのですが、濃度の計算は「無限集合の濃度Pは区間を与えて算出する」(※1)と定義するとよいと思います。
※1:有限集合に区間を与えても問題ありません。

例えば・・・
閉区間 a ≦ 0 ≦ b において、a = -10, b = 10 のときの濃度Pは、
自然数集合のP= 10 (自然数に0を含まない場合)
整数集合のP = 21
従って、整数集合の濃度と自然数集合の濃度の比は2x+1(xを自然数の濃度とする)

こう定義すれば、有限集合と無限集合のある領域における濃度を比較できたりします。

有限集合{ 2, 3, 5, 8, 10 } (謎の有限集合)の濃度は5
自然数集合の濃度は、区間 2 ≦ x ≦ 10 を与えると濃度は9。
従って、自然数集合のほうの濃度が高い。

私はこのほうが便利だと思います。
もともと濃度は、個数の概念を拡張したものですから、こういう風に個数との対応関係が必要だと考えています。
有限集合は無限集合の部分集合でしかありません。ならば、濃度と個数に対応関係がなければ不都合が生じます。
この濃度計算と、「属する」に関して1つのルールを付け加えれば、集合の矛盾も解けます。

「あらゆる集合は、濃度が高い集合を含むことができない。なぜならば、自分よりも濃度が高い集合は、部分集合となりえないからである。」

こうすれば、定性分析と定量分析を集合論で行えるようになります。
集合の集合Vの積集合P(V)は、V ∊ P(V)ということです。集合論は動的なものであり、静的に考え、集合の集合に濃度が高い積集合が定義できるから矛盾しているなとど考える必要はないと思います。集合は無限に増えるのだと考えたほうがしっくりきます。
ラッセルのパラドックスについては、これはただ単に全てにおいて偽を返す対応(関数)にしか過ぎないと思います。この自分自身を含まない集合は、自分以外のものを含む集合の動的表現とも言えます。P(x){x|x≠x}だから、何のxを渡しても偽を返します。こういったツールは、プログラミングで有効ですから別に不思議でもなんでもない、普通の道具にしかすぎません。
どういったときに使用するのかといいますと、2つ以上の条件を満たす性質を分析するときの論理演算において、ある特定の条件が絶対に満たさないとわかっている場合に、必ず偽を返す集合と、もう一つの条件を論理演算したいときに使用します。そうすれば、if文的に物事を考えず、論理演算できます。また、X以外というNOT演算にも使えます。結構便利な集合だといえます。
では、何の集合を渡しても偽を返す集合(対応)は何に属するのかといいますと、集合の集合に属します。なぜならば、集合とは何らかの対応を持つものであり、「すべてにおいて偽を返す」という対応があるので集合の集合に属するとみなせます。
後整列集合における矛盾については、濃度が高い集合は等価とみなせないので、そもそも矛盾になりません。カントールがしたことは、要するに順序数を要素として持つ順序数を定義しているだけですから、プログラミングでよく見られる入れ子構造(行列表現)にしかすぎません。この問題は、無限を無限個数えると、その識別子が人間には判断できないという性質を表わしていると思います。
でも、プログラミングで2次元配列の要素を1つの数と等しいとだれも思いません。つまり、濃度が違う集合はたとえ識別子が同じに見えても等価ではないのです。この件についてまとめると・・・

集合を含む集合は、任意の数の集合を与えないと判別できない。

だと思います。もっと簡潔に言えば、「2次元配列のインデックスとして、1つの数値だけ指定してもどの要素の事を言っているのかかわからない。」です。もしくは「配列の配列において、配列そのものを指定した場合、1つの要素と等価ではない(配列オブジェクトとその中にあるオブジェクトは違う)」(こっちの表現のほうが良いと思う)です。
過程がないので今まで上手く表現できなかったのですが、私は集合論に関する専門書を読んだ時点でこの結論が出ていました。
答えがすぐに分かって、その過程が自分でもわからない(上手く説明できない)ということはありがちですね。
こういうのを直観というのでしょう。ちなみに、脳科学的に直観はある程度解明されているそうです。脳科学によると、脳内は無意識にかなりの計算をしており、その計算量が説明できる量を超えている場合、直観となって表れるそうです(うろ覚え)
私は開発においてもこういった直観は大事だと思います。私の場合、お客様に話しを聞いた時点で、脳内でシステムを運用している風景(最終結果)とプログラムが同時に浮かんだりしますから、直観を大事にしています。わかってもらえないかもしれませんが、仕様が危ないときはバグの香りがします。それはほぼ100%当たります。刑事の勘ならぬ技術者の勘です。
勘だけで仕事はしませんが、勘を無視してもろくな結果になりません。それは、脳科学的に証明されていると私は思います。

テーマ : 日記
ジャンル : 日記

中の人の徒然草430 集合論に対する自分の考え

ここ最近、集合論で遊んでいます。自分の考えをまとめるために、その中で考えたことを書きます。先ず最初に思ったことは、集合そのものの定義が厳密でないことです。集合論は集合とは何かについて語り切っていないと思います。集合論の矛盾はそこから発生していると感じます。
「属する」もしくは「含む」という言葉そのものが曖昧模糊としています。英語を調べると・・・
x ∈ E は x is an element of E
A ⊂ B は A is contained in B もしくは A is a subset of B
です。要素と部分集合の所属は違うということだと思いますが、ならば要素とは何かについて厳密に定まっていません。部分集合については、すべてのAの元(要素)がBに属するとき部分集合であると定義されています。ここで問題となるのは、やはり要素(元)の厳密な定義です。
それが要素なのか集合なのか、分からない場合もあり得ます。実際に、原子論が発表された当時は、物質の最小要素は原子でしたが、今では原子よりも小さい物質(原子核など)が見つかっています。そういった将来の拡張性まで考えたとき、要素と集合の差は何なのか疑問です。
普通に考えば、何らかの要素を持つものを集合、すなわち要素を持つ要素は部分集合だと思います。ですが、要素をもたないと厳密に分かっている集合は空集合だけです。最小単位が「空集合」なのですから、要素があるといっている反面、集合論の構成要素は集合しかない事を暗示しています。
試しに最小要素を空集合だとみなして色々実験してみました。すると不思議なことに、それでも、いやそのほうが集合論は美しくなります。カントールの考えは、そちらのほうにあったという気がします。改めて考えてみれば、カントールは、数値さえも集合である順序数を例にとり理論を組み立てています。その考えに従うと、すべての要素は集合(最小単位は空集合)だと考えたほうがしっくりします。
カントールが理論構築に使っている順序数は、数の概念に人間の感性に一致すると私は思います。なぜならば、多くの数値は素数からなる合成数です。しかも、すべての数は1の合成です。人間は対象を「1,2,3,4,5...」と自然数で数えます(ただしプログラマーは0から数える)この感覚でいうと、数そのものが何らかの集合を表わしています。それを考慮すると、カントールの集合論には集合しかないような気がします。
次に私が問題だと感じたのは濃度です。整数と自然数には1対1の対応があるから濃度は等しいと聞いたとき、一瞬納得しかけましたが、直ぐに違和感を覚えました。確かに整数集合の部分集合である自然数から見れば1対1でしょう。しかし、本当の意味で両方の立場になって物事を見ていません。また、順序数(整列集合)のときの理論構築と矛盾しています。
順序数をすべて数え終わったらωとして・・・と理論が繰り広げられています。同じ理屈から言えば、自然数と整数の対応を0,1,-1,2,-2 = 0,1,2,3,4,というふうにしていけば、自然数が数え終わったとしたらどうするのでしょうか?明らかに半分足りません。このロジックの欠点は、自然数集合が整数集合の部分集合であるのにも関わらず、自然集合の範囲内でのみ、対応(関数)を考えている点にあります。小さな窓から見たら、世界は窓の広さに見えます。しかし、実際の世界は窓よりも広いです。それと同じことが整数と自然数にも言えます。
それに加えて、濃度の定義は微分的な考えがかけています。無限に広がるものは自然界に溢れかえっていますが、人間は有限の範囲内で分析し、無限を分析します。つまり、1杯の水から海水の性質を分析するように、無限集合の範囲内から、その濃度を調べる演算が必要だと私は考えています。自然数は無限、だから無限に付番できるというのはちょっと乱暴すぎます。無限にある自然数の要素を個々に考えるのではなく、関数ひとつだと考えればよいと思います。P( x ) = x + 1(x >= 0)の関数を要素として持つ自然数集合だと考えたほうが良いと思います。
そう考えると、整数集合は、中点である0と、2つの関数を持つ集合だとなります。こう考えると、濃度は2ℵ0+1となります。むろん自然数の濃度はℵ0とします。こう考えたほうが、「無限に付番できるから同じ無限なんだよ」という乱暴さがなくなり、理論が美しくなります。それに何より、濃度を有限の個数と対応付けられて代数演算できるようになります。1杯の水から海水の性質を分析するのです。人間が無限を分析するならば、有限の範囲内を取り出し、そこから性質を分析するしかありません。濃度と個数に対応関係が足りません。
数学の美しさは対称性にあると私は思います。ならば、有限と無限の個数に対応関係がなければ美しくないです。無限は無限だと思考停止せず、自由に発想したいです。数学は自由なのですから。ということで、私は集合論の拡張という遊びをしています。無駄なようですが、こういった遊びが技術力を高めると思います。もしかして、集合プログラミングが思いつくかもしれません。

テーマ : 日記
ジャンル : 日記

初心者のためのC#プログラミング本格入門101 - 詳細を意識しないで済む状態にしよう

 この記事は、初心者のためのC#プログラミング本格入門100の続きです。前回は、今後必要となるテストの技法を解説しました。今回は、テストとオブジェクト指向の関係について解説します。
 今度もテストから始めます。ある程度機能が整ってきたので、今度は耐久テストを行います。耐久テストというのは、ある程度無茶な使い方をしても正常に処理されるのかをチェックするテストです。オブジェクトを使う人は通常、オブジェクト内部を意識しませんから、想定外の使い方をされても大丈夫なようにプログラミングしておかねばなりません。それは、他人のためだけにする行為ではありません。
 詳細を知っておかないと使えないオブジェクトは、使い勝手が非常に悪いです。たとえ自分がプログラミングしたオブジェクトであっても、永遠に詳細まで覚えておくことなど不可能に近いです。従って、将来の自分のためにも詳細を知らないでもよい作り方をしておくのが賢明だといえます。
 具体例を挙げて解説します。まずは、テストプログラムを改良し、ちょっと無茶な使い方を試してみましょう。

class SimpleListTest : Test
{
    //他のプログラムは省略しています。
    public void AddElementCheck()
    {
        base.Execute();
        for ( int i = 0 ; i < 10000 ; ++i ) {
            this.target.Add( i );
            int result = this.target[ i ];
            if ( result != i ) {
                string message = "予期せぬ値が返されました。" +
                    "予想値:" + i +
                    " 返された値" + result;
                base.Error( message );
            }
        }
    }
}

きっと、1万個も追加するとは思っていないでしょう。しかし、そういった盲点にバグは生まれます。テストを実行すると案の定、プログラムが止まってしまいます。プログラムが止まったら、デバッガが表示する情報を見てみましょう。配列の範囲外にアクセスしていることが問題だと分かります。
 配列の要素数が10個になっているのが目に見える問題です。だったら、2万個ほど確保しておけばいいと、考える人がいるかもしれません。しかし、問題は数だけではありません。どれだけ確保しても、それ以上の要素を追加する人が居るかもしれません。もし前提があると、「このオブジェクトは2万個までしか追加できないぞ」などと注意せねばなりません。非常に面倒です。それに加えて、常に無数の要素を追加したいわけではありません。初めから何万個も確保しようとせず、少量だけ用意しておき、後で何個でも追加できるようにしておくほうが便利ではないでしょうか?
 何個でも追加できるように簡単に変更できます。

partial class SimpleList 
{
    //他のプログラムは省略しています。
    public void Add( int value )
    {
        ++this.insertIndex;
        if ( this.insertIndex == this.data.Length )
        {
            this.data = new int[ this.data.Length * 2 ];
        }
        this.data[ this.insertIndex ] = value;
    }
}

ただしこのプログラム、大きな問題があります。テストを改良して自分で発見してください。続く...

テーマ : プログラミング
ジャンル : コンピュータ

中の人の徒然草429

前回日記を書いた直後に思ったのですが、集合論の最小要素はやはり空集合が良いのかもしれません。人間の感覚でいうと、最小要素を集合として考えにくいのですが、将来の事も考えると集合のほうが都合がよいという気がします。例えば、原子を空集合で表現した後で、原子よりも小さな物質が発見されたら、原子集合の要素を増やせばよいのですから、ちょっと違和感がありますが拡張性から考えるとベストだと思うのです。これって、要するにすべてをオブジェクトで表現することと同じだと思います。
オブジェクト指向で考えると、整数も実数もオブジェクトですが、実装効率からバイナリで表現されることが多いです。その考えが根底にあるから、最小単位が集合という考えに違和感を覚えたと思うのですが、分析や設計するという観点から見た場合、すべてが集合=オブジェクトだと考えたほうがやりやすいです。集合理論って、要するにオブジェクト指向分析と設計の世界なのかもしれません。そう考えると、仕事で慣れているから、集合論をいくらでも拡張できます。ちょっとその方向で探ってみます。
集合論はさておき、相変わらず報道がいい加減だと感じました。大学不認可問題についてなのですが、マスメディアはいつものように、「かわいそうな個人」を取り上げてとかくバッシングしました。しかし、これが本当の報道と言えるのか甚だ疑問です。仮に補助金が出るとすると、何に関しても補助金が支給されないのは困るでしょうが、だからと言って何でも許可していれば、税金がいくらあっても足りません。もっと冷静に考えるべきことでしょう。それにもかかわらず、とかくバッシングします。しかもいつも通り、バッシングがうるさいから、不許可を取り下げるなんていい加減な話しになりました。感情的になって何でもバッシングするマスメディア、そして厄介ごとを嫌い、何でも妥協する政府。彼らにしてみたら、自分のお金でないから支給してもよいのでしょう。すべてがいい加減です。でも、中身がないからこの問題はまた闇の中です。結局何もわかりません。
こんなことしているから税金が無尽蔵に膨れあがり、何の問題も解決せず、日本が崩壊していくのでしょう。頭を使わず、何でも感情的に済ませるこの風潮をどうにかしたほうが良いかと思います。株がらみの事件で「どんな手段をしてでもお金儲けをしたいのですか」と食いついたマスメディアですが、売れれば何でもいいといい加減に情報を売っています。何でもワイドショー化しますが、ワイドショーなんて結局個人情報を売買しているのですから、法律的に言って少々問題あると思います。売れるからと言って、個人情報で儲けていいのでしょうか?公人だから、芸能人だから、などとレッテル貼りでごまかしていますが、彼らがいう「報道の自由」とは、自由に言葉の暴力をふるえるという意味なのかと勘繰りたくなります。
日本の崩壊が目に見えているのに、こんないい加減な情報機関しかないというのは問題です。ただ、この問題ある機関を作り上げたのは我々消費者です。人の個人情報を買うなんてこと、個人情報の流出に手を貸しているのと同じです。質の良い情報は買う、下卑た情報は買わない、そうしないと永遠にまともな情報機関は生まれないでしょう。やはり、個々の人が「考える」というのが重要だと思います。自分の頭で物事を考えず、空気だけで曖昧に判断しているからこうした末期的状況になったと思えてなりません。

テーマ : 日記
ジャンル : 日記

実践的オブジェクト指向設計入門25

 この記事は、実践的オブジェクト指向設計入門24の続きです。前回は、オブジェクトの表現について解説しました。今回は、物理的なパッケージ化について解説します。
 今回解説するのは、いよいよ最後の1個手前の作業です。この段階まで設計が進むと、後考えるべきことは、どのようにオブジェクトをパッケージ化するかです。パッケージ化するにあたって、考えるべきことは、情報隠蔽実態の一貫性物理的なモジュールの構築の3点です。これから個々の要素を解説します。
 情報の隠蔽とは、オブジェクト指向のカプセル化の事です。つまり、余計な細部に悩まされることなく、オブジェクトを使用できるように、余計な情報を隠すことを指しています。しかし、何でも隠せばよいというものではありません。極論を言うと、1個の何でもできるオブジェクトがあれば隠蔽度は最大です。ですが、1個の何でもできるオブジェクトを定義してしまうと、分担作業ができなくなりますし、仕様変更や機能拡張に耐えられない設計になってしまいます。設計者は、何の情報を公開するのかをよく考えなくてはなりません。オブジェクト指向の基本は隠蔽であり、何の情報を公開するのかを考える事が肝要です。
 実態の一貫性は、クラス、操作、インタフェースなどといった要素を、設計思想にそって一貫させることです。個々の要素に一貫性があると、将来拡張するのも容易ですし、途中参加したプロジェクトのメンバーの仕事がやりやすくなります。具体的には、命名規則が挙げられます。命名規則がおろそかにされることが多いのですが、人間は名前で意味を理解しようとするので非常に重要です。名前とまったく違う動きをするオブジェクトを理解することは容易ではありません。
 最後のモジュールの構成は、簡単に言うとオブジェクトの分割の仕方です。オブジェクトの粒度をどれくらいにするのか、アセンブリやDLLといった物理的なファイルをどのようにするのか、インタフェースをどのようにするのかなどといったことを考えます。一見簡単そうに見えますが、非常に複雑なものです。参考文献をあげます。




ほかにも参考になる書籍と、必要となる書籍がありますが、ひとまずこの3冊を押さえておきましょう。設計の世界も奥深いものです。続く...

テーマ : ソフトウェア開発
ジャンル : コンピュータ

中の人の徒然草428

11月になってから急激に寒くなりました。そんな時は、外に出ずにプログラミングが一番です。ということで昨日は、集合理論を検証したプログラムをリファクタリングしてみました。

using System;
using System.Collections.Generic;

//可能性
enum Possibility
{
    Absolutely,
    Possible,
    Impossible,
}

//集合
class Set
{
    #region フィールドとプロパティ

    //集合の説明
    private string m_explanation;
    public string Explanation
    {
        get { return m_explanation; }
    }

    //対応
    private Func<object, Possibility> m_contained;
    internal Func<object, Possibility> ContainedFunction
    {
        get { return m_contained; }
    }

    //部分集合
    List<Set> m_subSet;

    //保持する元
    List<object> m_elements;

    //Not集合
    Set notSet;
    internal Set NotSet
    {
        get { return notSet; }
    }

    //普遍集合
    Set universal_set;
    internal Set UniversalSet
    {
        get { return universal_set; }
        set { universal_set = value; }
    }

    #endregion

    #region コンストラクタ

    //説明文および集合と元(要素)の対応を指定する
    public Set( string explanation, Func<object, Possibility> isFunc )
    {
        this.m_explanation = explanation;
        this.m_contained = isFunc;
        this.m_subSet = new List<Set>( );
        this.m_elements = new List<object>( );
    }

    #endregion

    #region 所属判定

    //指定した元が集合に属するか判定する
    public bool Contained( object element )
    {
        Func<object, Possibility>[ ] checkFuncs =
            new Func<object, Possibility>[ ] {
                SpecialSetCheck, //Not集合と普遍集合は属しない
                ContainedCheck, //対応規則
                SubSetCheck,  //部分集合
                SubSetElementCheck //部分集合の要素
            };
        foreach ( var f in checkFuncs ) {
            Possibility pos = f( element );
            switch ( pos ) {
                case Possibility.Absolutely:
                    if ( element is Set &&
                         !this.m_elements.Contains( element ) ) {
                        this.m_elements.Add( element );
                    } else {
                        if ( !this.m_elements.Contains( element ) )
                            this.m_elements.Add( element );
                    }
                    return true;
                case Possibility.Impossible:
                    return false;
                case Possibility.Possible:
                    break;
            }
        }
        return true;
    }

    //特別な集合かチェック
    //特別な集合はこの集合に属しない
    private Possibility SpecialSetCheck( object element )
    {
        if ( this.notSet == element ||
            this.universal_set == element )
            return Possibility.Impossible;
        return Possibility.Possible;
    }

    //集合の対応規則をチェック
    private Possibility ContainedCheck( object element )
    {
        Set parent = this.universal_set;
        while ( parent != null ) {
            Possibility result = parent.ContainedFunction( element );
            if ( result == Possibility.Impossible )
                return Possibility.Impossible;
            parent = parent.UniversalSet;
        }
        return this.m_contained( element );
    }

    //指定した要素が部分集合の元なのかをチェック
    private Possibility SubSetCheck( object element )
    {
        Set obj = element as Set;
        if ( obj != null ) {
            if ( this.m_subSet.Contains( obj ) ) {
                return Possibility.Absolutely;
            } else {
                Possibility subFlag = this.IsSubSet( obj );
                if ( subFlag == Possibility.Absolutely )
                    this.m_subSet.Add( obj );
                if ( subFlag == Possibility.Impossible )
                    return Possibility.Impossible;
            }
            return Possibility.Possible;
        }
        return Possibility.Possible;
    }

    //指定された集合が部分集合かチェックする
    private Possibility IsSubSet( Set target )
    {
        bool result = false;
        if ( this.Equals( target ) )
            return Possibility.Possible;
        if ( target.m_subSet.Count == 0 ) {
            result = this.IsElement( target );
            if ( result == false ) return Possibility.Impossible;
            else return Possibility.Possible;
        }
        if ( this.m_contained( target ) == Possibility.Impossible ) {
            return Possibility.Impossible;
        } else {
            foreach ( Set sub in target.m_subSet ) {
                if ( this.IsSubSet( sub ) == Possibility.Impossible )
                    return Possibility.Impossible;
            }
            return Possibility.Possible;
        }
    }

    //自身の要素かチェックする
    private bool IsElement( Set target )
    {
        if ( target.m_elements.Count != 0 ) {
            foreach ( object element in target.m_elements ) {
                if ( this.Contained( element ) == false )
                    return false;
            }
            return true;
        }
        return true;
    }

    //部分集合の要素かチェック
    private Possibility SubSetElementCheck( object target )
    {
        foreach ( Set subSet in this.m_subSet ) {
            if ( subSet.Contained( target ) == false )
                return Possibility.Impossible;
        }
        return Possibility.Possible;
    }
    #endregion

    #region 比較

    public override bool Equals( object obj )
    {
        if ( obj == null ) return false;
        Set s = obj as Set;
        if ( s == null ) return false;
        return base.Equals( s );
    }
    public bool Equals( Set obj )
    {
        return this.Explanation.Equals( obj.Explanation );
    }
    public override int GetHashCode()
    {
        return this.ToString().GetHashCode();
    }

    #endregion

    #region 論演算

    //Not演算
    public Set Not()
    {
        Func<object, Possibility> f = ( x ) => 
            this.m_contained( x ) == Possibility.Impossible ? 
                    Possibility.Absolutely : Possibility.Impossible;
        Set result = new Set( this.Explanation + "のNot集合", f );
        this.notSet = result;
        return result;
    }

    #endregion

    #region その他

    //集合の説明を返す
    public override string ToString()
    {
        return this.m_explanation;
    }

    #endregion
}

class Program
{
    //実験
    static void Main()
    {
        //メタ集合(集合の集合の普遍集合)
        Func<object, Possibility> metaF = ( x ) => {
            if ( x == null ) return Possibility.Impossible;
            bool hit = x.GetType( ) == typeof( Set );
            if ( hit ) return Possibility.Absolutely;
            return Possibility.Possible;
        };
        Set metaSet = new Set( "メタ集合", metaF );

        //全ての集合を元として持つ集合
        Func<object, Possibility> setF = ( x ) => {
            Set y = x as Set;
            if ( y == null ) return Possibility.Possible;
            return Possibility.Possible;
        };
        Set setSet = new Set( "集合の集合", setF );

        /*どの集合にも属しない元からなる集合
         (集合の集合のNOT集合)
          長いからNOT集合とする*/
        Set notSet = setSet.Not( );
        setSet.UniversalSet = metaSet;

        //メタ集合に属するか?
        Action<object, Set, bool> MessageShow = ( x, y, z ) => {
            bool result = y.Contained( x );
            Console.WriteLine( "{0}は{1}に属するか?:{2}",
                x, y, result );
            if ( result != z )
                throw new ArgumentException( );
        };
        MessageShow( setSet, metaSet, true );
        MessageShow( notSet, metaSet, true );
        Console.WriteLine( );

        //自然数の集合は集合の集合に属するか?
        Func<object, Possibility> nf = ( x ) => {
            if ( x is int == false ) {
                if ( x is Set ) return Possibility.Possible;
                else return Possibility.Impossible;
            }
            bool hit = ( ( int ) x ) > 0; //0も含まないとする
            if ( hit ) return Possibility.Absolutely;
            else return Possibility.Impossible;
        };
        Set N = new Set( "自然数の集合", nf );
        int a = -1;
        MessageShow( a, N, false );
        int b = 0;
        MessageShow( b, N, false );
        int c = 1;
        MessageShow( c, N, true );
        Console.WriteLine( );

        //自然数の集合はどこに属する?
        MessageShow( N, setSet, true );
        MessageShow( N, notSet, false );
        MessageShow( N, metaSet, true );
        Console.WriteLine( );

        //自然数の奇数の集合
        Func<object, Possibility> of = ( x ) => {
            int value = ( int ) x;
            bool result = ( value > -1 && value % 2 == 1 );
            if ( result ) return Possibility.Absolutely;
            else return Possibility.Impossible;
        };
        Set oddSet = new Set( "自然数の奇数の集合", of );
        oddSet.UniversalSet = N;
        int d = 0;
        MessageShow( d, oddSet, false );
        int e = 1;
        MessageShow( e, oddSet, true );
        int f = 2;
        MessageShow( f, oddSet, false );
        string g = "1"; //数値ではない
        MessageShow( g, oddSet, false );
        int h = -1; 
        MessageShow( h, oddSet, false );
        Console.WriteLine( );

        //奇数集合はどこに属する?
        MessageShow( oddSet, N, true );
        MessageShow( oddSet, setSet, true );
        MessageShow( oddSet, notSet, false );
        MessageShow( oddSet, metaSet, true );
        Console.WriteLine( );

        //集合の集合は2つの集合を含むか?
        MessageShow( notSet, setSet, false );
        MessageShow( metaSet, setSet, false );
        Console.WriteLine( );

        //終了
        Console.WriteLine( );
        Console.WriteLine( "終了しました。" );
        Console.WriteLine( "Enterキーを押して下さい。" );
        Console.ReadLine( );
    }
}

今後機能拡張するためにちょっとコードが長くなっています。他の論理演算を追加して、演算しも定義して、より集合理論の検証をしやすくしようと思っています。
リファクタリングしていてちょっと思ったのですが、集合理論の部分集合の定義には、ちょっと曖昧さがあります。集合の集合ということは、すべての数字の集合も含まれるわけですが、数値は集合なのでしょうか?集合でないと集合の集合に属せないと仮定すれば変になりますから、このプログラムのようにそれでも良いとみなすのか、それとも、集合とみなすかによって集合論が変わってくると思います。
個々の数値を集合とみなす場合、数値1の扱いが気になります。他の数値ならば、容易に集合とみなせますが、この数値1は集合とするのは苦しいです。付番した集合1とみなすこともできますが、その集合1の元が集合でないならば同じことです。つまり、どこかで集合でない元が入り込みます。そう考えると、やっぱり元が何らかの集合に属するならば、集合の集合に属すると考えてもいいのかな?ということは、集合の集合の正体は、集合もしくは何らかの集合に属する元から成る集合なのでしょう。この集合オブジェクトは原子論を連想させます。
すべての物質は原子からなっているとするならば、ほとんどの要素は集合とみなせます。それを応用すれば、すべての事柄が集合で表現できます。現在原子よりも小さいものが見つかっていますが、それでも内容としては同じです。ようするに、小さいものの集合が物質なのですから、どれだけ小さなものが発見されても、集合論的には何も変わりません。原理的にはすべてが集合と対応で表現できることになります。
ただ気になることがあります。最小の要素/元をどのように扱うのか、その点について集合論は何も語ってくれません。その点を補充しないと、集合論は完璧だといえません。といっても、「集合」なのに集合でないものを定義するのは、集合論の守備範囲外という気もします。要は公理の問題なのでしょう。

テーマ : プログラミング
ジャンル : コンピュータ

VBオブジェクト指向プログラミング講座 第11回 手続きも関数もオブジェクト

 この記事は、第10回 小さなオブジェクトを合成して作ろうの続きです。前回は、オブジェクトの大きさと、オブジェクト指向プログラミングの基本ついて解説しました。今回は、手続きも関数のオブジェクトである、オブジェクト指向プログラミングの醍醐味を解説します。
 突然ですが、オブジェクト指向プログラミングというだけあって、VBでは手続きも関数もオブジェクトとして扱えます。さっそく確認してみましょう。

Imports System
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Input
Imports System.Windows.Media
Imports System.Windows.Shapes

Friend Interface IIdentifier
    ReadOnly Property Number() As Integer
End Interface

Friend Class MessageWindow
    Inherits Window
    Implements IIdentifier

    'このウィンドウの名前
    Private m_id As String
    Public ReadOnly Property Number As Integer _
        Implements IIdentifier.Number
        Get
            Return Me.m_id
        End Get
    End Property

    'インスタンスを識別するための定義
    Private Shared NextID As Integer

    'Windowのサイズを指定するための定義
    Private Shared random As Random =
        New Random(DateTime.Now.Ticks Mod Integer.MaxValue)

    '使用するメッセージ
    Private m_message As String
    Private Function CheckMessage(ByVal value As String) As Boolean
        If value Is Nothing OrElse value.Length = 0 Then
            Return False
        Else
            Return True
        End If
    End Function
    Public Property Message() As String
        Get
            Return Me.m_message
        End Get
        Private Set(value As String)
            If Me.CheckMessage(value) = False Then
                Throw New ArgumentException(
                    "1文字以上の文字列を指定して下さい。")
            End If
            Me.m_message = value
        End Set
    End Property

    '各種コントロール
    Dim input As TextBlock
    Dim text As TextBox

    'メッセージを指定してインスタンスを生成する
    Public Sub New(Optional ByVal msg As String = "Hello World")

        'Windowの設定
        Me.Height = random.Next(100, 1000)
        Me.Width = random.Next(100, 1000)
        Me.Message = msg

        '-------------------- ボタン上のコントロール --------------------

        Me.input = New TextBlock()
        text = New TextBox()
        Dim panel As New StackPanel()

        '作成ボタン
        Dim createBtn As New Button()
        createBtn.Content = "作成"
        Dim createBtnAction =
            Sub(sender As Object, e As KeyEventArgs)
                If e.Key = Key.Enter Then
                    createBtn.Focus()
                    e.Handled = True
                End If
            End Sub
        AddHandler text.KeyDown, createBtnAction
        createBtn.ToolTip = createBtnAction.GetType().Name &
            "型のオブジェクトが関連付けられています。"

        '検索ボタン
        Dim searchBtn = New Button()
        searchBtn.Content = "番号検索"
        AddHandler searchBtn.Click, AddressOf SearchWindow

        '名前表示ボタン
        Dim nameBtn As New Button()
        nameBtn.Content = "番号は?"
        Dim nameBtnAction =
            Sub(sender As Object, e As RoutedEventArgs)
                MessageBox.Show(
                "私は" & Me.Number & "号",
                "識別子",
                MessageBoxButton.OK,
                MessageBoxImage.Information)
                e.Handled = True
            End Sub
        AddHandler nameBtn.Click, nameBtnAction
        nameBtn.ToolTip = nameBtnAction.GetType().Name &
            "型のオブジェクトが関連付けられています。"

        Dim endBtn As New Button()
        endBtn.Content = "終了"
        Dim endBtnAction = Sub() Application.Current.Shutdown()
        AddHandler endBtn.Click, endBtnAction
        endBtn.ToolTip = endBtnAction.GetType().Name &
            "型のオブジェクトが関連付けられています。"

        '------------------------------------------------------------------

        panel.Children.Add(input)
        panel.Children.Add(text)
        panel.Children.Add(createBtn)
        panel.Children.Add(searchBtn)
        panel.Children.Add(nameBtn)
        panel.Children.Add(endBtn)

        'ボタン
        Dim btn = CreateEllipseButton()
        btn.Content = panel
        Me.Content = btn
        AddHandler btn.Click, Sub() Me.CreateWindow()
        AddHandler btn.KeyDown, Sub() text.Focus()

        'その他の処理
        Me.SetMessages()
        Me.m_id = MessageWindow.NextID
        MessageWindow.NextID += 1
    End Sub

    '指定した番号を持つウィンドウを検索
    Private Sub SearchWindow(sender As Object, e As RoutedEventArgs)
        Dim value As Integer
        If Integer.TryParse(text.Text, value) = True Then
            For Each win In Application.Current.Windows
                Dim w As MessageWindow = CType(win, MessageWindow)
                If w.Number = value Then
                    MessageBox.Show(
                        "見つかりました♪",
                        "検索結果",
                        MessageBoxButton.OK,
                        MessageBoxImage.Information)
                    e.Handled = True
                    w.Activate()
                    Exit Sub
                End If
            Next
        End If
        MessageBox.Show(
            "指定のウィンドウはありません。",
            "検索結果",
            MessageBoxButton.OK,
            MessageBoxImage.Exclamation)
        e.Handled = True
    End Sub

    '新しいウインドウを作成する
    Private Sub CreateWindow()
        Dim win As MessageWindow
        If Me.CheckMessage(Me.text.Text) = False Then
            win = New MessageWindow()
        Else
            win = New MessageWindow(Me.text.Text)
        End If
        win.Show()
        Dim btn As Button = CType(win.Content, Button)
        btn.Focus()
    End Sub

    '指定されたメッセージを各種要素に反映する
    Private Sub SetMessages()
        Dim str As String = Me.Message
        Me.Title = str
        input.Text = str
    End Sub

    '楕円ボタンを作成
    Private Function CreateEllipseButton() As Button
        '原型となるボタン
        Dim btn As Button = New Button()

        'ファクトリーオブジェクトを用意
        Dim mainFact As FrameworkElementFactory =
            New FrameworkElementFactory(GetType(Grid))

        '楕円を用意
        Dim brush As LinearGradientBrush = New LinearGradientBrush()
        brush.EndPoint = New Point(0, 1)
        brush.GradientStops.Add(
            New GradientStop(Color.FromArgb(100, 255, 255, 0), 0))
        brush.GradientStops.Add(
            New GradientStop(Color.FromArgb(255, 0, 255, 0), 1))

        Dim ellipseFact As FrameworkElementFactory =
            New FrameworkElementFactory(GetType(Ellipse))
        ellipseFact.SetValue(
            Ellipse.StrokeThicknessProperty, 5.0)
        ellipseFact.SetValue(
            Ellipse.FillProperty, brush)
        mainFact.AppendChild(ellipseFact)

        '楕円の位置
        Dim position As FrameworkElementFactory =
            New FrameworkElementFactory(GetType(ContentPresenter))
        position.SetValue(
            ContentPresenter.HorizontalAlignmentProperty,
            HorizontalAlignment.Center)
        position.SetValue(
            ContentPresenter.VerticalAlignmentProperty,
            VerticalAlignment.Center)
        mainFact.AppendChild(position)

        'ボタンにテンプレートを適用
        Dim tmp As ControlTemplate =
            New ControlTemplate(GetType(Button))
        tmp.VisualTree = mainFact
        btn.Template = tmp
        Return btn
    End Function
End Class

ボタンのイベントを指定する部分(AddHandler)に注目してください。今までは直接指定していましたが、変数を宣言して手続きと関数を割り当てることもできます。この変数の型が手続きの型です。サンプルをビルド後実行すると、手続きの型を見られます。
 手続きの型を見ると、Delegateとなっている点に注目してください。手続きと関数と同様の働きをする不思議なオブジェクトの正体はデリゲートです。デリゲートオブジェクトが、手続きと関数をオブジェクトして扱うことを可能としています。続く...

テーマ : プログラミング
ジャンル : コンピュータ

プロフィール

インドリ

Author:インドリ
みなさん、はじめまして、
コンニチハ。

ボクは、無限の夢(infinity dream)を持つネタ好きな虹色の鳥インドリ(in dre)です。
色々な情報処理技術を啄ばむから楽しみにしてね。

http://twitter.com/indori
は別人による嫌がらせ行為です。
私とは関係ないので注意して下さい。
次はなりすましブログなどをするかもしれませんが、ここ以外でブログをするつもりがないので、ここ以外にインドリのブログがあったとしても無視してください。


何度言っても分からない人がいるので、ここにコメント欄へ書き込むときの注意事項を書きます。


一、社会人としてのマナーをわきまえましょう。
一、妄想に基づく書き込みを止めてください。
一、暴言の類は書かないで下さい。
一、某誹謗中傷サイトの書き込みは彼らの妄想に基づく書き込みですから無視して、ここへ書き込まないで下さい。
一、コメント書く前に他のコメントよく読んでから行って下さい。
一、言いがかかり等の行為を禁止します。
一、その他常識的に考えて迷惑なコメントはしないで下さい。


以上のルールを守れない人のコメントは削除します。



利用上の注意
ここに紹介してある文章およびプログラムコードは正確であるように心がけておりますが、内容を保証するものではありません。当サイトの内容によって生じた損害については、一切の責任を負いませんので御了承ください。


執筆したCodeZineの記事


【VB.NETで仮想CPUを作ろう】

  1. VB.NETで仮想CPUを作ろう
  2. レジスタの実装
  3. 仮想CPUのGUI化
  4. テストドライバの改良
  5. CPUの基礎動作の実装
  6. MOV命令の実装
  7. ADD命令実装
  8. SUB命令実装
  9. INC命令&DEC命令の実装と命令長
  10. MLU命令の実装とModR/Mについて
  11. DIV命令の実装とイベント設計について
  12. 機械語駆動式 関数電卓を作ろう!
  13. 機械語駆動式 関数電卓を作ろう! 解答編(前半)
  14. 機械語駆動式 関数電卓を作ろう! 解答編(後半)


【仮想ネットワーク実装でTCP/IPを学ぼう】
  1. TCP/IPの基礎と勘所
  2. ネットワークアクセス層の勘所
  3. インターネット層の勘所
  4. トランスポート層の勘所
  5. アプリケーション層の勘所
  6. セキュリティの基礎と仮想ネットワークの仕様
  7. GDI+と独自プロトコルの定義



【並列化】
インテル Parallel Studioを使って並列化プログラミングを試してみた
並列プログラミングの効率的なデバッグを実現する「Parallel Inspector」


【TBBシリーズ】
  1. インテル スレッディング・ビルディング・ブロックの概要
  2. インテルTBBから学ぶループの並列化
  3. スレッドセーフとインテルTBBのコンテナ
  4. インテルTBBのスレッドクラス


【OpenMPシリーズ】
  1. OpenMPの基礎構文
  2. OpenMPの実行時ライブラリと並列ループ
  3. OpenMPのメモリモデルとfork- joinモデル

最近の記事
最近のコメント
月別アーカイブ
カテゴリ
Ada (9)
COBOL (5)
C (9)
C++ (11)
C# (370)
D (25)
Java (8)
Perl (1)
Ruby (14)
PHP (2)
Boo (2)
Cobra (2)
LISP (6)
F# (33)
HTML (0)
XHTML (0)
CSS (0)
XML (0)
XSLT (0)
Scala (4)
WPF (0)
WF (2)
WCF (0)
LINQ (4)
MONO (5)
Linux (0)
MySQL (0)
ブログ内検索
リンク
最近のトラックバック
RSSフィード
ブロとも申請フォーム

この人とブロともになる

QRコード
FC2カウンター