スポンサーサイト

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

ネタつつき163 - 掛算と割り算の本質は同じ

 以前私は、抽象的に見れば、足し算と引き算は本質的に同じだと書きました。この話題から当然湧く疑問は、掛け算と割り算の共通性です。という事で、昨晩少し考えてみました。
 掛算と割り算の分析をしてみて感じたのは、この両演算は一次関数と似ているという事です。例えば、2 * 4 = 8、7 / 3 = 2 ..余り2です。これを一次関数に書き直すとy = 2x + b です。掛け算の余りを0と仮定すると、それぞれが 2x + 0と2x + 1 です。これを微分すれば両方とも2です。この事から、掛け算と割り算は超離散しているだけのグラフを描くように見えます。
 その考えを元に、今度は掛け算と割り算について、共通ルーチンを使う形で実装してみました。今度のサンプルは、ちょっと複雑になったので、オブジェクト指向の洗礼(プログラマージョーク)をしています。構造的にちょっと見やすくなっていると思います。

//Main
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;

static class Program
{
    static void Main()
    {
        CycleTableTest( );
        Console.WriteLine( );
        NumberTest( );
    }

    static void NumberTest()
    {
        char[ ] table = new char[ ] {
                '0', '1', '2', 
                '3', '4', '5', 
                '6', '7', '8',
                '9'
            };
        NumberUnit obj = new NumberUnit(
            new CycleTable( table ) );

        //インクリメントとデクリメントの共通表示処理
        Action<string, Func<char, string>> Print =
            ( string msg, Func<char, string> f ) => {
                Console.WriteLine( msg );
                foreach ( char value in table ) {
                    Console.WriteLine( "{0}を代入した結果は? : {1}",
                        value,
                        f( value ) );
                };
                Console.WriteLine( );
            };

        //インクリメント
        Print( "インクリメントします・・・",
            ( char x ) => obj.Increment( x ).ToString( ) );

        //デクリメント
        Print( "デクリメントします・・・",
            ( char x ) => obj.Decrement( x ).ToString( ) );

        //加算と減算の共通表示処理
        Action<char, char, char, Func<char, char, string> > show =
            ( char x, char ope, char y, Func<char, char, string> f ) => {
                Console.WriteLine( "{0} {1} {2} = {3} ",
                    x, ope, y, f( x, y ) );
            };
        Action<string, char, Func<char, char, string>> Print1 =
            ( string msg, char ope, Func<char, char, string> f ) => {
                Console.WriteLine( msg );
                show( '0', ope, '0', f );
                show( '2', ope, '3', f );
                show( '3', ope, '6', f );
                show( '4', ope, '2', f );
                show( '7', ope, '3', f );
                show( '9', ope, '9', f );
                Console.WriteLine( );
            };

        //足し算
        Print1(
            "加算演算子を試します・・・",
            '+',
            ( char v, char v1 ) => ( obj.Add( v, v1 ) ).ToString( ) );

        //引き算
        Print1( "減算演算子を試します・・・",
            '-',
            ( char v, char v1 ) => ( obj.Sub( v, v1 ) ).ToString( ) );

        //掛け算
        Print1(
            "乗算演算子を試します・・・",
            '×',
            ( char v, char v1 ) => ( obj.Mul( v, v1 ) ).ToString( ) );

        //掛け算
        Print1(
            "除算演算子を試します・・・",
            '÷',
            ( char v, char v1 ) => ( obj.Div( v, v1 ) ).ToString( ) );

        //比較
        Console.WriteLine( "値の比較を試します・・・" );
        Func<int, string> GetString = ( int v ) => {
                switch ( v ) {
                    case -1:
                        return "右の値の方が大きい";
                    case 0:
                        return "両方の値は同じ";
                    case 1:
                        return "左の値の方が大きい";
                }
                throw new ArgumentException( );
            };
        Console.WriteLine( "{0}と{1}どちらが大きい?{2}",
            '5' , '4',GetString( obj.CompareTo( '5', '4' ) ) );
        Console.WriteLine( "{0}と{1}どちらが大きい?{2}",
            '5', '5', GetString( obj.CompareTo( '5', '5' ) ) );
        Console.WriteLine( "{0}と{1}どちらが大きい?{2}",
            '5', '6', GetString( obj.CompareTo( '5', '6' )  ) );

        //終了
        Console.ReadLine( );
    }

    static void CycleTableTest()
    {
        char[ ] table = new char[ ] {
                '0', '1', '2', 
                '3', '4', '5', 
                '6', '7', '8',
                '9'
            };
        CycleTable obj = new CycleTable( table );

        Console.WriteLine( "次の値を表示します・・・" );
        foreach ( char value in table ) {
            Console.WriteLine( "{0}を代入した結果は? : {1}, " +
                "1週回った?:{2}",
                value,
                obj.Next( value ),
                obj.IsLast );
        };
        Console.WriteLine( );

    }
}

//NumberUnit
using System;
using System.Text;
using System.Collections.Generic;

enum Sign
{
    Plus,
    Minus
}


//1桁の数字を抽象化したもの
class NumberUnit
{
    //記号表
    CycleTable _table;
    CycleTable _rTable;

    //記号表が必要となる
    public NumberUnit(
        CycleTable table )
    {
        this._table = table;
        this._rTable = table.Reverse( );
    }

    //インクリメント演算
    public Value Increment(
        char value )
    {
        char lowValue = this._table.Next( value );
        char highValue = this._table.First;
        if ( this._table.IsLast ) {
            highValue = this._table.Next( highValue );
            this._table.Reset( );
        }
        Sign sign = Sign.Plus;
        return new Value(
            sign,
            highValue,
            lowValue,
            this._table.First );
    }

    //デクリメント演算
    public Value Decrement(
       char value )
    {
        if ( value == this._table.First ) {
          return new Value(
            Sign.Minus,
            this._table.First,
            this._table.Begin,
            this._table.First );
        }
        char lowValue = this._rTable.Next( value );
        char highValue = this._table.First;
        Sign sign = Sign.Plus;
        if ( this._rTable.IsLast ) {
            sign = Sign.Minus;
            this._rTable.Reset( );
        }
        return new Value(
            sign,
            highValue,
            lowValue,
            this._table.First );
    }

    //2つの引数を受け取る演算
    //記号表と照らし合しながら値を導出
    private Tuple<bool, char> Operator(
        CycleTable usetTable,
        char value,
        char value1 )
    {
        CycleTable workTable = this._table.Copy( );
        char temp = workTable.First;
        char result = value;
        while ( value1 != temp ) {
            result = usetTable.Next( result );
            temp = workTable.Next( temp );
        }
        bool flag = usetTable.IsLast;
        usetTable.Reset( );
        return new Tuple<bool, char>(
            flag, result );
    }

    //加算演算
    public Value Add(
        char value,
        char value1 )
    {
        Tuple<bool, char> temp = this.Operator(
            this._table,
            value,
            value1 );
        Sign sign = Sign.Plus;
        char lowValue = temp.Item2;
        char highValue;
        if ( temp.Item1 ) {
            highValue = this._table.Begin;
        } else {
            highValue = this._table.First;
        }
        return new Value(
            sign, 
            highValue, 
            lowValue, 
            this._table.First);
    }

    //減算演算
    public Value Sub(
        char value,
        char value1 )
    {
        Tuple<bool, char> temp;
        char v = value;
        char v1 = value1;
        Sign sign;
        if ( this.CompareTo( value, value1 ) >= 0 ) {
            temp = this.Operator(
                this._rTable,
                value,
                value1 );
            sign = Sign.Plus;
        } else {
            temp = this.Operator(
                this._rTable,
                value1,
                value );
            sign = Sign.Minus;
        }
        char highValue = this._table.First;
        char lowValue = temp.Item2;
        return new Value(
            sign,
            highValue,
            lowValue,
            this._table.First );
    }

    //比較
    public int CompareTo( char v, char v1 )
    {
        //エラーチェック
        if ( !this._table.Contains( v ) ) {
            throw new ArgumentException(
                v + "は無効な記号です。" );
        }
        if ( !this._table.Contains( v1 ) ) {
            throw new ArgumentException(
                v1 + "は無効な記号です。" );
        }

        //どちらが先に到達するまでチェック
        char temp = this._table.First;
        bool vHit = false;
        bool vHit1 = false;
        char tmp1 = this._table.First;
        while ( true ) {
            if ( temp == v ) vHit = true;
            if ( tmp1 == v1 ) vHit1 = true;
            if ( vHit || vHit1 ) break;
            temp = this._table.Next( temp );
            tmp1 = this._table.Next( tmp1 );
        }

        //どちらが先に到達したのか
        if ( vHit ) {
            if ( vHit1 == false ) return -1;
            return 0;
        } else {
            if ( vHit1 ) return 1;
            return 0;
        }
    }

    //3つの引数を受け取る演算
    private Value Operator(
        char addValue,
        char subValue,
        char remainder )
    {
        if ( addValue == this._table.First ||
            subValue == this._table.First ) {
            return new Value( this._table.First );
        }
        Value temp = new Value(
           Sign.Plus,
           this._table.First,
           this._table.First,
           this._table.First,
           remainder );
        char highValue = this._table.First;
        char lowValue = this._table.First;
        while ( remainder >= subValue ) {
            Value v = this.Add( lowValue, addValue );
            lowValue = v.LowValue;
            if ( v.IsHighValue ) 
                highValue = this.Increment( highValue ).LowValue;
            remainder = this.Sub( remainder, subValue ).LowValue;
            temp = new Value(
                Sign.Plus,
                highValue,
                v.LowValue,
                this._table.First,
                remainder );
        }
        return temp;
    }

    //乗算演算
    public Value Mul(
        char value,
        char value1 )
    {
        return this.Operator(
            value,
            this._table.Begin,
            value1 );
    }

    //除算演算
    public Value Div(
        char value,
        char value1 )
    {
        return this.Operator(
            this._table.Begin,
            value1,
            value );
    }
}

using System;
using System.Collections.Generic;
using System.Linq;

//記号表を管理するオブジェクト
class CycleTable
{
    //記号列
    IEnumerable<char> table;

    //開始記号
    char _first;
    public char First
    {
        get { return this._first; }
    }

    //終了記号
    char _last;
    public char Last
    {
        get { return _last; }
    }

    //開始記号の次
    char _begin;
    public char Begin
    {
        get { return _begin; }
    }

    //テーブルの終了を過ぎたか?
    bool _lastFlag;
    public bool IsLast
    {
        get { return this._lastFlag; }
    }
    
    //記号列を指定してインスタンスを生成
    public CycleTable( IEnumerable<char> table )
    {
        this.table = table;
        this._first = this.table.First( );
        this._last = this.table.Last( );
        this._begin = this.Next( this._first );
    }

    //次の記号を返す
    public char Next( char value )
    {
        //エラーチェック
        if ( !table.Contains( value ) ) {
            throw new ArgumentException(
                value + "は無効な記号です。" );
        }

        //初期値設定
        IEnumerator<char> ie = this.table.GetEnumerator( );
        ie.MoveNext( );

        //検索
        while ( value != ie.Current ) ie.MoveNext( );
        if ( ie.Current == _last ) {
            //終了まで達したら開始記号を返す
            this._lastFlag = true;
            return _first;
        } else {
            ie.MoveNext( );
            return ie.Current;
        }
    }

    //オブジェクトの状態をリセットする
    public void Reset()
    {
        this._lastFlag = false;
    }

    //記号表を逆にしたオブジェクトを返す
    public CycleTable Reverse()
    {
        return new CycleTable( this.table.Reverse( ) );
    }

    //同じ記号表を持つオブジェクトを返す
    public CycleTable Copy()
    {
        return new CycleTable( this.table );
    }

    //記号表に存在するかチェック
    public bool Contains( char target )
    {
        return this.table.Contains( target );
    }
}

共通性を強くアピールするために、0除算のエラーチェックはしていませんが、両演算はほぼ同じだと分かると思います。違いはエラーチェックと、特殊な状況です。これは、加算と減算にも言えます。減算でマイナス値を算出するときに工夫するのと同じです。
 情報技術力?を鍛えると、情報技術を学ぶ前に見えなかったものが見えてきます。乗算と除算と言えば、表と裏のように両極端に感じる人が多いと思います。しかし、それらの物事も視点を変え抽象化してみれば、思わぬ共通性が見えてきます。これこそが、情報技術の魅力なのかもしれませんね。
スポンサーサイト

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

コメントの投稿

非公開コメント

プロフィール

インドリ

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