メルマガ:あゆしゃのC言語プログラミング
タイトル:あゆしゃのC言語プログラミング(Vol.470) 10進変換の高速化3  2004/07/05


/*========================================================*/
    <<<あゆしゃのC言語プログラミング>>>
/*========================================================*/
 第470回 10進変換の高速化3
 発行    2004年7月5日(月曜日)
 発行数   約2800

{magclick}
/*========================================================*/
 はじめに ( 決り文句 )
/*========================================================*/
・このメールマガジンは、主にまぐまぐさんから発行しています。
・ジャンルは、マルチメディアのプログラム、C言語です。
・横60文字で作成し、インデントは大抵半角スペース4つです。
・ここで扱うプログラムは、C言語と半光年以内のものです。
・登録解除は、メルマガのホームページでお願いします。
・過去ログはバックナンバー(下欄参照)を活用して下さい。
・内容は私が感じたもので、最新の技術も、へたれもあります。
・わかりやすさを優先させる為、たまに嘘があるかもしれません。
・セキュリティ突破のため、暗号化された単語があります。

/*========================================================*/
 ご挨拶
/*========================================================*/

 こんにちは。あゆしゃです。

 先日、増勝選新の理論をページにまとめました。

http://ayusya.hp.infoseek.co.jp/
http://ayusya.hp.infoseek.co.jp/TetuIWCN.html

 ファイル名称に悩みましたが、

インクリーズド
ウィン
チョイス
ニュー

 の頭文字としました。

/*========================================================*/
 株日記
/*========================================================*/

野村のバーチャル株式投資倶楽部
http://www2.nomura.co.jp/vstock/VirtualServlet?
(ゲストでログインして Ayusya を探せば成績を参照できます)

★ここ一週間の Ayusya の成績
木曜日 1,008,535円
金曜日 1,007,509円
月曜日 1,005,648円
火曜日 1,008,945円
木曜日 1,022,928円 24,864番
金曜日 1,026,300円 24,810番

 そろそろ手入れをしようかなぁ、と思っただけ(笑)

{magclick}
/*========================================================*/
 今回のお題  << 10進変換の高速化3 >>
/*========================================================*/

 前回、だいぶ早くなりました。


結果
0.240s


 もう少し、速くできる気がします。


CString CXInt10::toString( void )
{
    char buff[ SIZE10 + 1 ];
    UCHAR* pch = m_buff + SIZE10 - 1;
    char* pb = &buff[ 0 ];
    // 最大の桁位置を求める
    for( ; pch > m_buff; pch-- ) {
        if( *pch ) break;
    }
    // '0'を足しながらコピー
    for( ; pch >= m_buff; pch--, pb++ ) {
        *pb = ( char )*pch + '0';
    }
    *pb = 0;
    return CString( buff );
}

 最大の桁位置を求めたときに、長さを求めておき、

    int len = pch - m_buff + 1;

 CString にするときに、それを指定すると、

    return CString( buff, len );

 CString が buff の長さを調べる必要がないだけ、strlen が
省略され、早くなるはずです。


結果
0.230s


 うーん、微妙?

 あとは。。。


CXInt10& CXInt10::mul( int b )
{
    UCHAR* pch = m_buff;
    UCHAR* pe = m_buff + min( SIZE10, GetLength() + 11 );
    int c = 0;
    for( ; pch < pe; pch++ ) {
        c = ( int )*pch * b + c;
        *pch = ( UCHAR )( c % 10 );
        c /= 10;
    }
    return *this;
}


 余りを求めているところ、割り算が2回発生しているのが
もったいないです。

    for( ; pch < pe; pch++ ) {
        c = ( int )*pch * b + c;
        int c2 = c / 10;
        *pch = ( UCHAR )( c - c2 * 10 );
        c = c2;
    }

 割り算が速いという前提で、余りの部分は割り算結果を10倍
したものを引くことでもとめましょう。


結果
0.200s


 うっ、予想以上に速くなりました!

 ・・・あれれ?


CXInt10& CXInt10::add( CXInt10& b )
{
...
    for( ; pch < pe; pch++, pch2++ ) {
        c = ( int )*pch + ( int )*pch2 + c;
        *pch = ( UCHAR )( c % 10 );
        if( c >= 10 ) c = 1;
        else c = 0;
    }
    return *this;
}


 この関数のキャリーのところ、if にしたのですよね。

 同じような方式に変えてみますか。


結果
0.220s


 あ、却下(笑) if の方がさすがに速いです。

 あとは。。。


CString CXInt10::toString( void )
{
...
// '0'を足しながらコピー
for( ; pch >= m_buff; pch--, pb++ ) {
*pb = ( char )*pch + '0';
}
...
}


 やっぱりこの関数が遅いわけで、

 このループを、4バイトにしましょうか。

 しかし pch の初期位置は4の倍数ではないため、例外処理を
書いて、

    int len = pch - m_buff + 1;
    int len2 = len;
    int i = len2 & 3;
    // 4の倍数になるまでコピー
    if( i ) {
        do {
            *pb++ = ( char )*pch-- + '0';
        } while( --i );
        len2 -= i;
    }
    // '0'を足しながらコピー
    i = len2 >> 2;
    if( i ) {
        do {
            ULONG c = ( *( ULONG* )(pch - 3)) + 0x30303030L;
            char* pb2 = pb + 3;
            *pb2-- = ( char )c; c >>= 8;
            *pb2-- = ( char )c; c >>= 8;
            *pb2-- = ( char )c; c >>= 8;
            *pb2 = ( char )c;
            pb += 4, pch -= 4;
        } while( --i );
        len2 &= 3;
    }
    if( len2 ) {
        do {
            *pb++ = ( char )*pch-- + '0';
        } while( --len2 );
    }

 pb と pch の方向が逆なので、スワップしなければいけません。

 うーん、馬鹿みたいに長いけど。。。


結果
0.200s


 駄目ですね。100害あって1利なしです。


 ま、こんなところですか。

{magclick}
/*========================================================*/
 さいごに
/*========================================================*/

 新C言語使いにおくるチョー基本講座 第16回。

 プログラムの左側に空白やタブを埋め込むことを、インデントと
いいますが、

 インデントは面倒ですか?

 通常のC言語対応エディタならば、自動インデントを搭載して
いるでしょうが、

 しかし、}でインデントを下げてくれるかというと、そうで
あったりなかったり、結構いい加減です。

 switch のインデント方法は、ツールによってばらばらですね。

 インデントを自動調整してくれるツールがあると、便利ですか?

 デベロッパスタジオには、デフォルトでその機能があります。

 インデントのないC言語のソースを選択して、

 Alt+F8 を押してみてください。

 インデントを自動調整してくれます。

 他人のプログラムで不可解なインデントを見たときや、

 インターネットから拾ってきたソースがべったりとしているとき
に、

 便利です。

{magclick}
/*========================================================*/
 次回予告
/*========================================================*/

 次回は7月5日(月曜日)に、第470回をお送りします。
 お題は「ベクターへユーザ登録」

 さて、大型計算機が大分としっかりしてきました。

 ところで、

 ・・・

 ・・・・・・シェアウェアって、どうやって登録するのですか?

 お楽しみに!

/*========================================================*/
 最後の決り文句
/*========================================================*/
 このメールマガジンは、まぐまぐさんから発行しています。
 このメールマガジンを解除したい場合は、まぐまぐさんをご利用
ください。このメルマガのまぐまぐアイディーは最後にあります。
 このメールマガジンには広告が挿入されていますか?
 このメールマガジンの内容に文面の引用はありませんか?
 めーらっくすの場合はめーらっくすの利用方に従ってください。
 このメールマガジンの内容の、転用、流用、宣伝、リンク、
金に走った(笑) なんて大歓迎です。

{magclick}
/*========================================================*/
 
/*========================================================*/

発行者 あゆしゃ

ホームページ::あゆしゃの世界
http://ayusya.hp.infoseek.co.jp/

ご意見・ご感想・ご質問メール
mailto:ayusya@flamenco.plala.or.jp

まぐまぐ::アイディー
0000020674

まぐまぐ::登録と解除
http://www.mag2.com/m/0000020674.htm

まぐまぐ::バックナンバー
http://jazz.tegami.com/backnumber/frame.cgi?id=0000020674

めーらっくす::アイディー
MM3E1AEE285AB4F

めーらっくす::登録と解除
http://www.mailux.com/mm_dsp.php?mm_id=MM3E1AEE285AB4F 

めーらっくす::バックナンバー★最近のものならこちらが便利★
http://www.mailux.com/mm_bno_list.php?mm_id=MM3E1AEE285AB4F

ブラウザの閉じるボタンで閉じてください。