<?xml version="1.0" encoding="UTF-8" ?><rdf:RDF 
  xmlns="http://purl.org/rss/1.0/"
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xml:lang="ja">
  <channel rdf:about="http://www7.atwiki.jp/bogard/">
    <title>雑記</title>
    <link>http://www7.atwiki.jp/bogard/</link>
    <description>雑記</description>

    <dc:language>ja</dc:language>
    <dc:date>2006-03-11T00:33:09+09:00</dc:date>

    <items>
      <rdf:Seq>
                <rdf:li rdf:resource="http://www7.atwiki.jp/bogard/pages/5.html" />
                <rdf:li rdf:resource="http://www7.atwiki.jp/bogard/pages/81.html" />
                <rdf:li rdf:resource="http://www7.atwiki.jp/bogard/pages/80.html" />
                <rdf:li rdf:resource="http://www7.atwiki.jp/bogard/pages/79.html" />
                <rdf:li rdf:resource="http://www7.atwiki.jp/bogard/pages/39.html" />
                <rdf:li rdf:resource="http://www7.atwiki.jp/bogard/pages/78.html" />
                <rdf:li rdf:resource="http://www7.atwiki.jp/bogard/pages/77.html" />
                <rdf:li rdf:resource="http://www7.atwiki.jp/bogard/pages/76.html" />
                <rdf:li rdf:resource="http://www7.atwiki.jp/bogard/pages/75.html" />
                <rdf:li rdf:resource="http://www7.atwiki.jp/bogard/pages/74.html" />
              </rdf:Seq>
    </items>
	
		
    
  </channel>
    <item rdf:about="http://www7.atwiki.jp/bogard/pages/5.html">
    <title>メニュー</title>
    <link>http://www7.atwiki.jp/bogard/pages/5.html</link>
    <description>
      [[トップページ]]

[[本棚&gt;http://booklog.jp/tana.php?ac=Bogard]]

----
[[両手で1000まで数えられますか？：2進法の話&gt;2進法の話]]
[[数値 - 危険物取り扱い注意]]
[[100 × 200 =32？：変数のオーバーフローの話]]
[[パリティビット]]
[[小数の扱いについて]]
[[ぽいんた]]
[[ぽいんた2]]
[[ぽいんた3]]
[[ジ･オリジン]]
[[ジ・オリジン：補足]]
[[かっこつける話]]
[[かっこつける話２]]
[[文字列のこと&gt;リテラル]]
[[タイミングの話]]
[[拡張性の話&gt;拡張性]]
[[取り込む話]]
[[staticな話]]

[[コンパイルの話1&gt;コンパイルの話]]
[[コンパイルの話2：止まらぬビルド&gt;コンパイルの話：止まらないビルド]]
[[コンパイルの話3：マシン語に落ちるということ1：メモリの話&gt;コンパイルの話：マシン語に落ちるということ]]
[[コンパイルの話4：マシン語に落ちるということ2：最適化]]
[[コンパイルの話5：マシン語に落ちるということ3：変数とスタック]]
[[コンパイルの話6：コンパイラはそもそも何をやってくれるのか？？&gt;コンパイラはそもそも何をやってくれるのか？？]]
[[リンクの話]]
[[プリプロセッサの話]]

[[OS、というもの]]

[[オブジェクト指向1]]
[[オブジェクト指向：2]]
[[オブジェクト指向：3]]

[[オブジェクト指向：番外 C言語のソースファイルの話&gt;ソースファイルの話]]
[[オブジェクト指向：番外 C言語での「再利用性」と「カプセル化」データ構造とアルゴリズム&gt;データ構造とアルゴリズム]]


[[抽象的な話]]
----
[[寝込んで布団の中で考えたこと]]
[[こんなの、常識？？]]
[[お仕事プログラミング]]
[[ソフトでハードなプログラム&gt;エレガントなプログラム]]
[[プログラムするということ&gt;プログラムを書くということ]]
[[お勉強]]
[[プログラムを学ぶということの補足]]
[[C言語：「学問」と「実務」]]
[[統合開発環境&gt;プログラミングする、ということ3:統合開発環境]]
[[C言語ってポータブルですか？&gt;Cという言語]]
[[C言語ってポータブルですか？：2&gt;Cという言語：2]]
[[あなたは、どう読みますか？]]
[[ああ勘違い]]
[[試してガッテン]]
[[低級品]]
[[質問をするということ]]
[[ポカ]]
[[「何もしない」 != 「無駄」]]
[[エディタの話]]
[[もっと手を抜こう]]

[[いまどきの、アセンブラ&gt;アセンブラのこと]]

[[VisualStudio2005]]
[[VisualStudio2005:2]]
----
[[戦争の防ぎ方、に対する私の考え&gt;戦争の防ぎ方に対する一考察]]
[[身近な差別]]
[[改革]]
[[地球に優しいなんて大嘘]]
[[統計で嘘をつく方法]]

[[言葉について]]
[[言葉について:2]]

[[神が死んだということ]]
[[善悪の彼岸から、力への意思を目覚めさせるということ]]

[[本を読むということ]]
[[本を読むということ：2]]

[[絵を描く話]]
[[地図]]
[[地球儀]]

[[オカルトのお話]]
[[がんだむさん&gt;ガンダムのお話]]
[[RPGソフトウェア]]
[[記紀神話の不思議]]

----

[[メニュー]]    </description>
    <dc:date>2006-03-11T00:33:09+09:00</dc:date>
  </item>
    <item rdf:about="http://www7.atwiki.jp/bogard/pages/81.html">
    <title>もっと手を抜こう</title>
    <link>http://www7.atwiki.jp/bogard/pages/81.html</link>
    <description>
      作業対象のソースコードの解析を行っていたわけですが。

とりあえず、一通りの処理の流れは把握できたように思います。

doxygenのおかげでクラスの継承関係は把握できたので、流れは追いやすかったです。あとは、制御対象機器周りの細かい機器依存部のみ。

週明け月曜日にはなんとか、実務レベルの把握ができると思います。
･･･正直、かなりほっとしているわけですが(笑)


C++についてもだいぶ慣れてきました。

長らくC言語しかやってなかったから、それが一番しんどかったかも(笑)
ソースの書き方もそうだけど、ソースの解析手法もC言語とC++では、効率のいいやり方はだいぶ違うと思います。


C言語の場合は関数単位で見ていけばいいので、特に気をつけるべきことはあまりないように思います。関数名もプロジェクト内でユニークなものなので、grepかけたら終わりです(笑)

ですがC++にはクラスの継承、関数のオーバーライド・オーバーロードがあります。したがって、単純にgrepかけてみても求めるものが求める場所（ソースファイル）になかったり、逆にいっぱい同じ名前で検索に引っかかったりするわけです。


なので方法としては、次のようになると思います。

（グローバル関数でないかぎり）スコープが限定されているのでどのクラスのメンバかはすぐにわかるので、それをもとにヘッダファイルを見てみると、そこで宣言されているか、されていないにしてもそのクラスがどのクラスから派生しているのかがわかるわけで。

あとはそれを順にたどっていくことで目的の関数にたどり着くはずです。

･･･ただし、そんな馬鹿正直なことをやっていると継承が深い場合や多重継承（javaとちがって、C++はこれができてしまうから）の場合などは時間も手間もかかってしまいますが(笑)

特に、インターフェースを統一するためにあるクラスを基底においてある場合などは結構よくあるパターンな上に継承の階層が激しく深かったりします。


こういうときは、前述のdoxygenのようなツールに頼るのが一番だと思います（ドキュメントがすでにしっかりしているのなら、それに越したことはありませんが･･･）。

オブジェクト指向言語のソース解析は、UMLなり何なり、とにかくクラス図。話はそれからだと思います。まだ解析初めて二日目だから、あんまり偉そうに言ってしまうと怒られちゃうかもしれませんが(笑)


「ツールに頼ると実力がつかないから、自力でやったほうがいい」という方もいらっしゃるかもしれません。

ですが「実力を付ける」だのというのは、仕事でそれができるのならそれがベストですけれど、その過程で作業的に無駄が入るのであればそれは間違っています。
それならば、作業としては効率優先で行い、自分の時間（週末や帰宅後など）を利用してやるべきです。


私はC++についてだいぶ忘れかけていた状態から、3日ほどで18MBのソースを把握することができるところまで来ているわけです。まじめに自力だけでやったとしたら、（ドキュメントもほとんどないため）おそらくは1週間ほどはかかってしまったことでしょう。

かつ、その過程においてツールを使ったからといってC++を使えないわけでもありませんし。ソースをまったく見ていないわけではないし、ツールに頼っているのは階層関係の把握と定数定義を探すのに時間がかかるのを避けたかったわけで。

それ以上の解析については結局人間が（というより自分が）やるしかないんだし、そもそもソースを解析するというのはソースを把握、理解するためにあるわけです。


ソースを理解していくということは、そのソースがC++で書かれている以上、C++を身に付けざるを得ません（でないと、いかにツールを使ったとしても「理解」はできないはずです）。


私の持論として「結果が同じとなるなら、それにかける手間はできるだけなくす」のがいいことだと思っています。
それは単にらくだから、ではなく時間的な意味でも、作業的な意味でも余裕を作ることができるということです。

もちろん、手間をかけたときよりも結果の品質が下がるなどということがあってはいけません。それは大前提ですが。



結果の品質には注意が必要ですが、極力手を抜くこと。

「高品質かつ低コスト」これがベストだと思います。    </description>
    <dc:date>2006-03-11T00:31:43+09:00</dc:date>
  </item>
    <item rdf:about="http://www7.atwiki.jp/bogard/pages/80.html">
    <title>統計で嘘をつく方法</title>
    <link>http://www7.atwiki.jp/bogard/pages/80.html</link>
    <description>
      現在、報道・書籍・ネットなどメディアの充実により、情報だけは豊富に仕入れることができる時代となりました。

しかしながら、その情報も玉石混合といった感じなのは否めません。

転んでも泣かないためには、嘘を嘘と見抜ける能力が必要なわけです。

敵を知り己を知れば百戦して危うきなし。
そんなわけで、嘘をつかずに相手をだます方法をいくつか。


・統計データで嘘をつく

アンケートなどの統計結果の場合

該当アンケートの結果などを利用して嘘をつくのは常套手段です。
そのアンケート結果が信頼に値するかどうかは、ある程度以下で判断できます。

 a.アンケート回答者が対象の事柄について十分な理解がある
 b.実施人数、有効回答数などが統計データとして十分である

a.については、たとえば報道番組などで政治的なアンケートをとった場合、その対象となる政策について、その辺を歩いている一般的な人（自分自身も含めて）が十分な理解をできていそうかどうか。偏見ありきのアンケート結果は、当然ながら信頼に値しません。
b.については、統計というのは最低でも1000以上はないと信頼に値するデータは得られないとされています。実際、よく見るとテレビなどでのアンケートは100人程度であったりと、回答者たちに十分なばらつきがあるとは思えない場合が多いです。
また、ある一定の地域のみ限定でのアンケートであったり、実施人数は多くてもあまりにも有効回答率が低かったりするアンケートも同様の理由で信頼には値しません。大体アンケートの実施者などは「こういう結果が欲しい」を前提に実施していることがほとんどなわけで、自分の求める結果が得られやすい地域・対象年齢・対象性別で行っている可能性も否定できません。


また、統計データにはアンケート以外にも平均値などもあります。
これもまた、データを元に嘘をつくには格好の材料となることが多いです。

たとえば、昼夜で非常に寒暖の差の激しい砂漠のような場所でも、「夏季の昼は40度、冬季の夜はマイナス10度」と書かずに「平均気温は20度前後！」などとうたえば、まるですごしやすい快適な場所のように受け取られてしまいます。どちらも、嘘はついていないわけですが。


・誤解しやすい表現で嘘をつく

これも、言葉の上で嘘はついていないのですが。

たとえば、私が「私は東大の入試試験で落ちませんでした」というと、さも私が東大に合格したかのようです。しかし、事実はそもそも受験していないだけです。くだらないと言われればくだらないのですが、この論法は相手をだますのには有効です。

たとえばマルチ商法などの場合。「これで損をしたやつはいない」などという言い方をされる場合があります（「絶対に儲かる」は逆に使いません）。マルチ商法の多くは、販売代理店として在庫を抱える代わりに子の代理店契約を行ってそいつにまた在庫を抱えさせることで自分が儲かる、といったネズミ講まがいのシステムが多いわけです。
たとえ借金をして在庫を抱えて、それなのに自分の子になってくれる代理店の契約ができなかったとしても、それは「損はしていない」わけです。だって、親の代理店に払ったお金は「権利と在庫分の代金」であるので、価値は減じてない、と解釈できるからです。

このように、言葉の上で嘘をつかずに、うまく相手の考えを誘導するには、一般的な言い回しだが一般的ではない使い方をして「相手がそう思いたがっている」ということを利用すれば比較的容易に相手を騙すことができてしまいます。


・相手の考えを固定する

上に似ていますが･･･

判断材料をあえて少なくすることで相手の選択肢を狭めて正常な判断ができない状況にしてしまう、というのも常套手段として存在します。

よくあるパターンとしては、たとえば原発推進などで、
 「あなたは電気を使いますね？」
 →「じゃあ発電所は必要ですね？」
 →「じゃあ原発に賛成ですよね？」
と、どんどん相手の視野を狭めて選択の余地をなくしてしまうというわけです。心理学用語では「ロックオン」というそうですね。
この論法の特徴は、まったく逆の結論でも同じような論法を行うことができることです。先の原発の例で言うなら、
 「核は危ないですよね？」
 →「じゃあ原発も危ないですね？」
 →「じゃあ原発に反対ですね？」

また、プレゼンテーションなどで有効な手段として、「最初に結論を言う」というのがあります。
結論から入って、その説明を行うことでわかりやすくする効果もあるのですが、相手の考えを最初に傾けておくというのは相手を誘導する上でも有効な手段であるからです。これもある種の「ロックオン」であるといえるでしょう。


・論理をすりかえる

これもまたよくあるパターンですが、注意していないとなかなか厄介です。

たとえば、昨今話題の「女系天皇」問題などでも、「過去に推古天皇、持統天皇など女性の天皇がいたんだから」という言い方をする人がいますが、「女性天皇」と「女系天皇」は直交する概念です。「女性天皇」がいたということがイコールとして「女系」で天皇位を継承していく制度の根拠とはなりえません。



実際には、上で述べたようなことが複合的に使用されることが多いです。たとえば日本とアメリカの関係について、
「日本の安全保障のためにアメリカとは仲良くしなくてはいけないから、牛肉輸入問題などを早期かつ円満に解決すべき」
などといった場合、「ロックオン」と「論理のすり替え」が行われているわけです（どこがそうかは、わかりますよね？）。


これらの「騙しのテクニック」に騙されないためには、まさに上の逆を行けばいいわけです。
 ・結論を急がない
 ・今何を対象として論じているかを把握する
 ・単純な統計を信用しない
最低限、このくらいに気をつければ、手に入れた情報の精度が格段に向上します。    </description>
    <dc:date>2006-03-05T11:23:44+09:00</dc:date>
  </item>
    <item rdf:about="http://www7.atwiki.jp/bogard/pages/79.html">
    <title>地球に優しいなんて大嘘</title>
    <link>http://www7.atwiki.jp/bogard/pages/79.html</link>
    <description>
      「地球に優しい」という言葉があります。

私は、実に欺瞞に満ちた言葉だと思うのです。

無論、言いたいことは分かります。言っていることも大事なことだとも思います。


現在の地球環境というのはこれまでの奇跡的といってもいい偶然によって生まれました。またさらなる偶然によって、現在われわれ人類にとって実に最適な環境となっているわけです。

その環境を大切にしよう、という考えそのものは、正しいと思います。ですが、同時に「現在の地球環境」を維持しようとすることはあくまで人間の立場からのエゴであることも同時に知っておくべきだと思うのです。


地球は誕生したときはただの石ころでした。
その後数億年かけて周囲の隕石との衝突・融合を繰り返し、マグマに包まれた火の玉といっていい状態がありました。

さらに数億年たって地球がある程度冷えたとき、大気中の水蒸気が冷やされて雨となって海ができました。
このころの大気は二酸化炭素が現在の20倍、酸素はほとんど皆無という割合でした。
生物は、そのような環境で生まれたのです。


最初の生物は、酸素を必要としない生物でした。
そのうち、光合成によって酸素を作る生物が生まれたとき、地球環境は激変します。

海中に溶けていた膨大な鉄分が酸素と結合して酸化（さび）て、海は真っ赤に染まりました。また、酸素はそれ以前の生物にとって有毒なものであったため、当時の生物のほとんどが死に絶えてしまいました。

つまり、「酸素を出す」ということがこの時点の地球においては強烈な環境破壊であったわけです。


前置きが長くなってしまいましたが、このように現在われわれにとって必要な酸素を作り出すということが過去の地球においては環境破壊であったことがあったということです。
また、酸素を作り出す過程において大気中の二酸化炭素濃度が減り、地球の気温も徐々に現在の気温まで下がってきたわけです。

地球はこれまでこうした環境の激変を何度も繰り返し体験してきています。
そのたびに、古い生物が絶滅に追いやられるとしても、その激変を乗り切った新しい生物によって進化はとどまることなく続いてきました。


その意味で、今われわれが声高に叫ぶ「地球に優しく」という言葉は、あくまで人間にとって優しい地球を維持しようとするということに他なりません。

私は、それを悪いことだとは言いません。人類が生きていくうえで必要なことであるのですから、生物として自分（の種族）の維持を尊重することは当然のことだと思います。

ただ、それを「地球に優しい」という言葉で「絶対的」かつ「普遍的」な善のように言う言い方に、疑問を感じるのです。


この言葉は、「人間にとって都合がいい地球」が地球にとっていいこと、見たいなニュアンスを含んでいます。

そうではなく、本当は地球によって人間が生かされているのだ、ということをもっと自覚すべきだと思うのです。

現在の地球の奇跡とも言える環境に対する、感謝の念ではなく、人間の都合を地球に押し付けているように、思うのです。


われわれ人類は、地球上で他の生物と「共存」して暮らしているのであって、決して「地球の主」ではありません。
もっと、適切かつ謙虚な言葉があるように思えてならないのです。    </description>
    <dc:date>2006-02-28T00:53:13+09:00</dc:date>
  </item>
    <item rdf:about="http://www7.atwiki.jp/bogard/pages/39.html">
    <title>右側</title>
    <link>http://www7.atwiki.jp/bogard/pages/39.html</link>
    <description>
      つらつらと、日々考えたことを書いていこうと思います。 
blogでなくてwikiなのは、なんとなくです。 
将来的に、他の方にも編集をしてもらえたら、楽かな、と。 

さまざまなガラクタな話しかありませんが。。まさに雑記。

----

#showrss(http://www.rssnavi.jp/rss/?k=srch_feed&amp;c=3&amp;t=1&amp;kw=C++&amp;n=20,recent,0,1,1,,20)    </description>
    <dc:date>2006-02-24T00:34:08+09:00</dc:date>
  </item>
    <item rdf:about="http://www7.atwiki.jp/bogard/pages/78.html">
    <title>プリプロセッサの話</title>
    <link>http://www7.atwiki.jp/bogard/pages/78.html</link>
    <description>
      コンパイラ、リンカと並んで実行ファイルの生成に重要なのが、プリプロセッサです。



C言語の場合、プログラムをビルドするときに、コンパイラに先立ってソースファイル内の
 #
で始まる「プリプロセッサ命令」を解釈、実行します。

おなじみなのは、やはり
 #include
 #define
あたりでしょうか。

ほかにも、#defineなどの定数定義に従って
 #ifdef
 #elif
 #else
 #if
 #ifndef
などを使って同じソースファイルでデバッグルーチンをオンにしたりなどできます。

また、コメントをコンパイラに渡す前に削除しているのもプリプロセッサです。



これらの命令や制御はコンパイラとは関係なく、プリプロセッサによって行われるので、使い方によっては面白いことができます。
たとえば、gccなどではテキストファイルや他の言語のソースファイルでもプリプロセッサを適用することができます。
コマンドラインから
 cpp &lt;ファイル名&gt;
で、プリプロセスだけを適用することができるわけです。


ということは、アセンブラなどにC/C++の書式の定数定義やコメントを使うことができるということです。これは結構便利です。

また、テキストファイルなどでも#defineの値を変えてやることで擬似差込印刷のようなこともできなくはありません。

 #define NAME 山田
 
 NAME 様
 お元気でしょうか。･･･
などという書き方ができるわけです。

このテキストをプリプロセッサを通すことで、あて先などを簡単に変えてテキストファイルを出力することができます。


また、#if～#else～#endifなどのネストが深くなるとエディタでのソースが見づらくなってしまいます。

そういうときにプリプロセッサを通すことで実際に殺されている処理はどこなのかが簡単に把握できます。
（そのかわり、#includeなども展開されるので、標準ライブラリなどを#includeしているときはかなり大きなファイルが出力されますが）


プリプロセッサが行う処理は、比較的単純な文字列の編集です。

ですが、プリプロセッサがこのような準備をしてくれなければ、小さなプログラムを作るだけでも山のような関数宣言やexternを書かなくてはいけなくなってしまいます。

プリプロセッサのおかげで、作成・編集したい部位だけを意識することができるわけです。
簡単な機構ですが、ありがたいことだと思います。    </description>
    <dc:date>2006-02-22T21:49:32+09:00</dc:date>
  </item>
    <item rdf:about="http://www7.atwiki.jp/bogard/pages/77.html">
    <title>リンクの話</title>
    <link>http://www7.atwiki.jp/bogard/pages/77.html</link>
    <description>
      プログラムの入門書などを見ても、コンパイラについては結構皆さん意識してるんだけど、リンカについてはあんまり記述がない気がします。 

実際、ソースファイルを実行ファイルにするには、「コンパイル」+「リンク」というあわせ技は必須なわけですが、どうにもリンカは影が薄い気がしてしまうのです(笑)。 


単体のソースファイルのみでプログラムを書いているときはあまり気になりませんが、複数のソースファイルに分割して書いているならば、多少は意識があると思います。 

リンカの役割は、（主にソースファイルごとに作られる）オブジェクトファイルの結合です。 
･･･といってしまうと、ソースファイルから機械語のオブジェクトファイルを作るコンパイラの方が主でリンカは従であるようなイメージを受けてしまうかもしれません。 



しかし、そうではないのです。 



ソースファイル内にない関数、たとえばprintfなどのような標準ライブラリ関数などは、ユーザのオブジェクトファイル内には機械語コードとしては存在しません。これらはC処理系の用意したライブラリとリンクすることで初めて使えるわけです。 

また、グローバル変数やユーザ定義の関数などもソースファイルが違えばそれは個々のオブジェクトファイル内には存在しないわけです。 

それらは、オブジェクトファイルをリンクして実効ファイルにした段階で、初めて同一の舞台にそろうことができるわけです。 


このようなことを実現するために、各オブジェクトファイル内では識別子などの情報（アドレス）が相対参照になっていることが多いです。 

そうすることで、オブジェクトのリンク順が変わったり、リンクするオブジェクトに増減があってもリンケージ（リンク作業）の時に調節することができます。 
これも、リンカの役割のひとつです。 



また、一般にプログラムが実行されるときにはmain()から入るわけですが、このプログラムが実行されるまでにはいろいろと準備があるわけです。 


まずプログラムをメモリに展開・グローバル変数領域の確保、コマンドラインオプションをargc、argvとして準備、main()を呼び出す、という前準備があって初めてmain()の処理が呼び出されます。 

こうした前準備を行うのは一部はOSの役目ですが、ほとんどは「ローダオブジェクト」と呼ばれるモジュールによって行われます。 

この「ローダオブジェクト」が前準備をして、かつ我々が普段C言語でエントリポイントだと思っているmain()をコールしてくれることによってプログラムを実行させることができるわけです。 

この「ローダオブジェクト」もまた、リンケージの時に実行ファイルにリンクされます。 



また、オブジェクトファイルは（処理系にもよりますが）機械語の「実行ファイル一歩手前」ですので、当然他の言語でも作ることができます。 

たとえば、基本的な処理はC言語で書いて、クリティカルな処理や速度が必要な処理のみアセンブラで書く、などということができるわけです（無論、C言語でインラインアセンブラ使ってもいいわけですけど(笑)）。 

このときアセンブラソース側ではC言語の関数呼び出し規約に準じたサブルーチンとして記述してやれば、あとはオブジェクトファイルをリンクすることで実行ファイルを得ることができます。 
実際、C処理系についている標準ライブラリなどは実装はアセンブラで行われている処理系も多いです。 



というわけで、リンカは「縁の下の力持ち」と言ったところでしょうか。 
コンパイラほど派手な（？）仕事ではありませんが、実にイイ仕事をするリンカを応援してあげましょう(笑)    </description>
    <dc:date>2006-02-22T01:03:06+09:00</dc:date>
  </item>
    <item rdf:about="http://www7.atwiki.jp/bogard/pages/76.html">
    <title>小数の扱いについて</title>
    <link>http://www7.atwiki.jp/bogard/pages/76.html</link>
    <description>
      さて、コンピュータでの数値の取り扱いと計算についての注意点をいくつか書いてきたわけですが。

これまでに述べてきた以外にもいくつか、注意しなくてはいけない問題があります。

C言語における変数の型として、まだ述べていないものに
 [float][double]
があります。

これらは【実数型】などと呼ばれ、浮動小数点数を格納できます。

これらの不動小数点数を扱う上で注意しなくてはいけないのは、浮動小数点演算には誤差がつき物である、ということです。


不動小数点数についての詳しい説明は省きますが、
例えば、浮動小数点では「0.1」を正確に表現できません。


コンピュータの内部ではこれまで書いてきたように2進数で数値を表現しています。それは、たとえ浮動少数点数であろうと例外ではありません。

したがって、内部的にはbitの並びでしかないものを「浮動小数点数」として処理するために規格が存在します。
一般的な処理系であれば、この規格はIEEE754でしょう。

この規格においては、基数が「2」となります。したがって、2の乗数（2^n：小数を表すならnはマイナスとなる）で表現されるのです。


そして、困ったことに0.1は2の乗数で表現できないのです。


したがって、
 double d;
 d = 1/10;
としたとき、dには0.1は入っていません（！）

浮動小数点数はその表現方法から、極端に大きな値や逆に極端に小さな値を少ないbyte数で表現できるのですが、このような誤差が混入されることを念頭に入れて使用しなくてはいけません。

例えば、グラフィックアプリのサイズ指定やゲームプログラミングでの3D座標などを扱う場合であれば、ある程度値域を絞り込めると思うので、固定小数点を使用したほうが無難だと思います。

C言語で固定小数点を使うなら、単純に桁をそろえてやればいいだけです。

例えばすべて100倍して扱うと決めてしまえば、
 1　→　100
 0.1→　10
とするだけ。整数型で表すことができます。

こうすれば、浮動小数点固有の誤差は生じることがありません。

API関数などに渡す時に浮動小数点を使用しなくてはいけない時だけ、適宜内部で持っている固定小数点数から変換してやればいいでしょう。C言語は「暗黙の型変換」を行ってくれるので、この変換は特に難しくはありません。


これで、とりあえず誤差なしで小数点を扱うことができるようになりました。

しかし、まだ注意しなくてはいけない点があります。
それは、整数か有限小数しか扱えない、という点です。

例えば1/3などは0.3333333･････と無限に続きます。
したがって、コンピュータで1/3を正確に表すことはできません（1 / 3 * 3 は１にはなりません）。

同様に、pi（円周率）や平方根なども正確に表せません。

なので、特に3Dゲームなどで座標変換に三角関数を使用しますが、当然ながら誤差が出てしまいます。

これらの誤差は、浮動小数点か固定小数点かにかかわりません。


したがって、より誤差の少ない計算結果を得ようと思うなら、できるだけ途中の計算に無駄をなくすようにしなくてはいけません。上の 1 / 3 * 3 なら、/ 3 * 3は無駄なのでなくしてしまう、といった処理が必要になります。

3Dの座標変換などであれば、右に30度か移転後左に15度回転、などという処理があるならば変換用の行列（マトリクス）生成の時に右に15度回転を一度だけ行うようにすれば、誤差が少なくなるわけです。
（※この辺は詳しく説明すると長くなってしまいますが･･･。
　最初のワールド座標を保持しておいて、回転等の変換を
　「今の座標からの相対変換」ではなく
　「最初の座標からの絶対変換」にすれば誤差が減ると
　思います）


コンピュータでの数値の扱いは、非常に多くの制限事項が存在します。実際、浮動小数点演算における誤差などはプログラミングなどしなくてもEXCELでも確認できます。

小数の扱いには、特に非常に注意が必要です。    </description>
    <dc:date>2006-02-19T22:32:05+09:00</dc:date>
  </item>
    <item rdf:about="http://www7.atwiki.jp/bogard/pages/75.html">
    <title>パリティビット</title>
    <link>http://www7.atwiki.jp/bogard/pages/75.html</link>
    <description>
      チェックサムを書いたので、似たようなロジックとしてパリティビットの話も。 

bitの話も、もうしてあるので、準備も整ったことだし。 


チェックサムは、1byteに入りきらない値が切り捨てられることを利用してデータの整合性を（ある程度）保障するというものでした。 

これと似たようなテクニックとして、ビットを使うテクニックがあります。 

1byteは8bitですが、通信などにおいては送信側と受信側で正常にエンコード/デコードできれば、問題はありませんね。 

そこで、例えば送信する時には7bitずつ送って、最後の1bitをパリティビットとして使うことでデータの整合性を保障するということができます。 

どういう風にするかというと、例えば0x5a5a5a5aという4byteのデータを通信で送受信するとすると、bitで表すと 
 【0101 1010 0101 1010 0101 1010 0101 1010】 
となるわけです。 

これを7bitごとに送るとすると、【0101 101】ですね。 

このbitを 0 + 1 + 0 + 1 + 1 + 0 + 1 とすると、2進数なので【101】となります。この一桁目の【1】を先ほどの7bitの最後に付加して送信用の1byteとするのです。 

つまり、最初に送受信されるデータは【01011011】となります。 


あとは、この手順を元データの先頭から順に繰り返すだけです。 


受信側は受信したデータの前7bitから同じ計算をして、それが8bitめのbitと一致しているかをチェックします。 

これが一致していたら一応OK、一致していなかったらNGというわけです。 


これはチェックサムと比べると0か1かのbitをチェックに使っているので、ノイズがのったりして正しいデータが送受信できていない場合でも1/2の確立でOKと判断されてしまいます。 

しかしながら、チェックサムが1byte以上のデータでないと使えないのに比べ、パリティビットはbit単位でデータの整合性をチェックすることができます（ただし、あまり細かすぎる単位でパリティビットを持たせても、逆にパリティビット自体にノイズがのりやすくなりますし、データ量が増えてしまうため意味がありませんが）。 

チェックサムにしろ、パリティビットにしろ、それを使うことでデータの完全な保障はできませんが、併用することでかなり信頼性の高いデータの送受信が行えることになります。 


プログラムにおいては、例えばC言語の文法などよりもこういったアルゴリズムを知っているか、使えるかということのほうが重要なことが多いかもしれません。    </description>
    <dc:date>2006-02-19T01:00:31+09:00</dc:date>
  </item>
    <item rdf:about="http://www7.atwiki.jp/bogard/pages/74.html">
    <title>100 × 200 =32？：変数のオーバーフローの話</title>
    <link>http://www7.atwiki.jp/bogard/pages/74.html</link>
    <description>
      変数には「型」があります。 

この「型」って言うのは何なのかというと、 
主に値を格納できるサイズの違いです。 


C言語の場合、整数型の変数の型としては 
 char、int、short int、long int、long long int 
がありますね。 
（実数型も入れたらdouble、floatなどもありますが） 

それぞれ、1byte、2byte、4byte、8byteの領域を持っています。 

1byteは8bitでした。なので、1byteで256通りの状態を表せるのでした。 

ということは、 
2byteなら256×256通り、 
4byteなら256の4乗通り、 
8byteなら256の8乗通りの状態が表せるわけです。 

これは逆に言うと、ある型で表せる範囲が限定されているということでもあります。 

unsigned long long intなら0～18,446,744,073,709,551,615まで表せるわけで、まあ普通の数値であれば収まるとは思いますが。 

でも例えばcharの変数には1000なんて数字を表すことはできません。 

これは結構、不便なことなのです。それは、 

例えばunsigned charの変数ca,cbがあったとします。 
この二つの変数の乗算の結果を受け取るためには、 
unsigned shortの変数が必要となります。 
unsigned short同士の乗算であれば、unsigned longがやはり同様に必要です。 

なぜかというのはお分かりだと思います。 
計算の結果が変数の表せる値の範囲におさまらないことがあるためです。 

このような「変数の表せる値の範囲におさまらない」値を代入しようとした時には、はみ出した部分は捨てられてしまいます。これを「変数のオーバーフロー」といいます。 

例えば、 
 unsigned char ca = 100, cb = 200; 
 ca *= cb; 
などとするとcaには20000(0x4E20)が入って欲しいわけですが、caは1byteしかないためはみ出した部分（0x4E）が捨てられます。 
なので、結果としてcaには32(0x20)が格納されるわけです。 

100×200の答えが、32になってしまうわけです。恐ろしいですね。 

同様に、100 + 200も300(0x012C)ではなく44(0x2C)となります。 

結局、たとえlong long intを使ったとしても、表せる状態は多くなりますが限界があることには変わりません。 

変数の計算（特に加算・乗算）には特に注意をしましょう。 



逆に、この切り捨てられることを利用したのがチェックサムと呼ばれるデータの整合性の保障方法です。 
あるデータが100byteあるとして、 
 unsigned char dat[100]; 
 unsigned char sum; 
 int i; 
 ・・・ 
 for(i = 0; i &lt; sizeof(dat); i++) 
 { 
 　　sum += dat[i]; 
 } 
などとして1byteのサム（SUMとは合計のこと）をとります。 
オーバーフローすることを逆手に取るわけです。 

通信する際にデータの最後にこのサム値を付加してやり 
受信側でも受信後同様の処理を行って、 
計算したサムと受信したサム値が一致していればノイズなどがのることなく正常に受信できたと解釈できるわけです。 

もちろん、1/255の確立で偶然一致することもありえます。 
（例えばデータ{100,200}のチェックサムは0x2cですが、 
データ{256,200}のチェックサムも0x2cとなってしまいます） 

しかしながら通信におけるデータの整合性チェックは簡便かつ軽量であることも求められるので、クリティカルなデータで無い場合にはこれで十分チェックの役割を果たします。 


変数の表せる範囲に限界があるということは、結構見落としがちなことで、思わぬ不具合につながることがあります。 

プログラムを書いた本人は思い込みもあるので、ソースを追っていっても不具合の原因がわからず、デバッガでステップ実行していったりして始めて原因がわかるようなことにもなりかねません。 

「数値」は最も基本的で、もっとも扱うことの多いデータです。だからこそ、たかが足し算、掛け算であってもプログラミングする際にはキチンと気をつけることが重要だと思います。 



【おまけ】 
bitを表示するデバッグ用関数。 
いろいろな変数を食わせて雰囲気つかんでください。 

使い方： 
第一引数にデバッグ用の文字列 
第二引数にbitデータのポインタ 
第三引数にbitデータのサイズ（byte単位） 
※以下のコードはWebできれいに見せるために 
　全角スペースを含んでいます!! 
 void vDbgBit(char* str, unsigned char* ucp, size_t len) 
 { 
 　　unsigned char ucWork, i; 
 
 　　printf(&quot;[DBG]vDbgBit:%s [&quot;, str); 
 
 　　for(i = 0; i &lt; (len * 8); i++) 
 　　{ 
 　　　　ucWork = 0x80 &gt;&gt; (i % 8); 
 　　　　printf(&quot;%c&quot;, 
 　　　　　　((ucp[i / 8] &amp; ucWork) ? &#039;1&#039; : &#039;0&#039;)); 
 　　　　if(!(i / 4)) 
 　　　　{ 
 　　　　printf(&quot; &quot;); 
 　　　　} 
 　　} 
 　　printf(&quot;]\n&quot;); 
 }     </description>
    <dc:date>2006-02-17T00:36:53+09:00</dc:date>
  </item>
  </rdf:RDF>

