スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

ネタつつき166 - 四則演算の抽象化と抽象化技法

 ちょっと気になったので、四則演算をすべて抽象化と統合をしました。その結果、抽象化技法の見本のようなものが出来上がったので、今回はその件について書きます。
 突然ですが質問です。皆様は、足し算、引き算、掛け算、割り算の四則演算は、どれもちがう計算法だと思いますよね?ですが、情報技術により抽象化すると、四則演算共通の関数を導き出すことができます。各々の演算は、その抽象化した関数に渡すパラメーターが違うだけの計算法なのです。すなわち、四則演算の本質は全く同じなのです。
 四則演算を抽象化したものは実に簡単です。たった2つの演算を繰り返し行っているだけです。
//考え方を示した疑似コード
while ( IsLoop( param.YTable, v1 ) ) {
    v = f ( v, X, );
    v1 = f ( v1, y);
}
fが実行する関数です。この関数は一つ次元が下?の演算子が使われます。例えば、掛け算ならば足し算、足し算ならばインクリメント(1増加)するです。これはちょっと想像すると分かってもらえると思います。掛け算を分解すると足し算の繰り返し、足し算を分解すると1増やすことの繰り返しです。
 ここで重要なのは、値を1増加する演算と、値を1減らす操作は同じだという点です。この2つの演算は逆操作のように見えますが、使用する記号表内の記号の順番が違うだけなのです。どちらも、記号表を指さししているだけです。
 ここで問題なのは、各種演算ごとのエラー処理です。これがあるから、各々が違う演算子だと感じてしまいます。しかし、視点を変えると、全ての演算は同じことをしています。それは、パラメータ(渡される値)のチェックと、先ほど言った2つの演算を繰り返す行為です。
 割り算で0を指定すると致命的な結果を招くので、エラーとなります。一方、掛算は0であろうとも気にしないように思えます。しかしながら、実はチェックはしているのです。何故ならば、「0をかけたら0にしよう」とルールを定めているからです。もし、まったく気にしないのであれば、そもそも0に関する思考すらしないはずです。
 それは歴史が証明しています。0をかける行為を、昔の人は忌避していました。何故ならば、幾何学的に考えて、0を掛けるという行為は何の図形を生み出すかわからないからです。幾何学的には、掛け算は縦×横の図形の面積を表わしています。ならば、0を変えるという行為は一体何の意味があるのでしょうか?そう考え、昔の人は0を掛ける事すら忌避していました。足し算と引き算もほぼ同じです。
 パラメーターをチェックした結果、気にしないのと、チェックすらしないのとでは意味が愛が異なります。算術演算の場合、チェックはしています。従って、四則演算のチェック方法そのものは同様で、チェック結果に対する対処法だけが違うといえます。この対処もパラメーターにしてしまえば、ほぼ完全な抽象化された関数を導出できます。
 以上の四則演算の考えをC#で表現してみました。行数にすると約740行です。全てを掲載すると見づらいので、核となる部分を掲載します。

//四則演算を抽象化した関数
private Tuple<Sign, char, char> Operator( Parameter param )
{
    //右の値(Y)が異常値ならば例外をスローする
    if ( param.CompareTable.Contains( param.ErrorValueY ) && 
        param.CompareTable.CompareTo( param.Y, param.ErrorValueY ) 
            == CompareToResult.Equal ) {
        throw param.ThrowException;
    }

    //左の値(X)が異常値ならば設定された値を返す
    Sign sign = Sign.Plus;
    if ( param.CompareTable.Contains( param.ErrorValueX ) && 
        param.CompareTable.CompareTo( param.ErrorValueX, param.X ) 
                == CompareToResult.Equal) {
            return param.ReturnValueX;
    }

    //必要であれば左右の値を比較交換する
    if ( param.IsExchage &&
        param.CompareTable.CompareTo( param.X, param.Y ) 
            == CompareToResult.Right ) {
        char o = param.Y;
        param.Y = param.X;
        param.X = o;
        sign = param.ChangedSign;
        param.Max = param.ChangedMax;
        param.InitX = param.ChangedInitX;
        param.InitY = param.ChangedInitY;
    }

    //ループ判定
    //※最終記号を超えて演算することを考慮している
    Func<CycleTable, char, bool> IsLoop =
        ( CycleTable useTable, char value ) => {
            bool a = false;
            if ( useTable.CompareTo( useTable.Last, param.Max ) 
                    == CompareToResult.Equal ) {
                a = useTable.CompareTo( useTable.First, value ) 
                    != CompareToResult.Equal;
            } else {
                a = useTable.CompareTo( useTable.Last, value ) 
                    != CompareToResult.Equal;
            }
            bool b = useTable.CompareTo( param.Max, value ) 
                != CompareToResult.Right;
            bool flag = a && b;
            return flag;
        };

    //処理本体
    char v = param.InitX;
    char v1 = param.InitY;
    while ( IsLoop( param.YTable, v1 ) ) {
        v = param.F( param.XTable, v, param.X, false );
        v1 = param.F( param.YTable, v1, param.Y, false );
    }
    Tuple<Sign, char, char> result =
        new Tuple<Sign, char, char>( sign, v, v1 );
    return result;
}

//除算演算
public Value Div(
    char x,
    char y )
{
    CycleTable counter = this._table.Copy( );
    Parameter param = new Parameter( ) {
        XTable = counter,
        X = this._table.Begin,
        YTable = this._rTable,
        Y = y,
        Max = y,
        InitX = this._table.First,
        InitY = x,
        F = ( CycleTable table, char v, char v1, bool isReset ) =>
           this.Add( table, v, v1, isReset ).LowValue,
        CompareTable = this._table, 
        ErrorValueX = this._table.First, 
        ReturnValueX = 
            new Tuple<Sign, char, char>( Sign.Plus, this._table.First, this._table.First ), 
        IsErrorY = true, 
        ErrorValueY = this._table.First,
        ThrowException = 
            new DivideByZeroException( this._table.First + "で割れません。" )
    };
    Tuple<Sign, char, char> temp = this.Operator( param );
    Sign sign = temp.Item1;
    char lowValue = temp.Item2;
    char highValue = this._table.First;
    char remainder = temp.Item3;
    this._table.Reset( );
    Value result = new Value(
        sign,
        highValue,
        lowValue,
        this._table.First,
        remainder );
    return result;
}

見ての通り、四則演算(インクリメントとデクリメントと合わせると六則)は、パラメーターを変えて、ある関数を呼び出しているだけなのです。この視点から見れば、四則演算は皆同じです。このプログラムはちょっと長く、やろうと思えば短くできると思いますが、可読性を考えてしませんでした。
 四則演算の抽象化は、いくつかの抽象化技法を使用しています。これは教科書には載っていないと思いますが、情報技術者は自然としている事です。おそらく、数学者や科学者もしていると思います。使用している抽象化技法は、対象条件の拡大(仮名)です。
 先ほどのべたように、足し算は掛け算の一部というふうに考えると、統一して考える事が可能となります。つまり、足し算は掛け算よりも条件が緩いと考えるのです。その逆に、掛け算を分解して、新しい関数を考える事も可能です。この2つの考えを、数学でたとえるならば微分積分です。物事を細かく分解して考えるのと、細かいものを纏めて考えるのは、人間が持っている基本的かつ強力な抽象化技法です。
 抽象化技法を使用して、身の回りにある物事を分析してみましょう。そうすれば、楽しい時間を過ごせると思います。
スポンサーサイト

テーマ : 文明・文化&思想
ジャンル : 学問・文化・芸術

コメントの投稿

非公開コメント

プロフィール

インドリ

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カウンター
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。