組み込みの埋まってるとこ

システム寄りの組み込みCプログラミングBLOG

100と99.999…は等しいか否か? ~組み込みの場合~

数学では100と99.999…は等しい数になるそうです。 厳密な証明は私には難しいのですが次のように理解できます。

3分の1してから3倍すると元の数と等しい数になる。だとすれば、 3分の1したときに少数で書き直したものを3倍した数も元の数と等しい。


\frac{100}{3} = 33.333\cdots
\\
3 \times \frac{100}{3} = 3 \times 33.333\cdots
\\
100 = 99.999\cdots

ところがある日そうではない事件が発生したのです!

100.00MHzの水晶と99.99MHzの水晶はまったく別物だった件

数学の世界では100と99.99…は同じ数なのですが、 電子回路に載せる水晶振動子では100.00MHzと99.99MHzはまったく別物だったのです!

ある日のこと、部品表に載っていた100MHzの水晶の見積書を先輩に見せたところ「あり得ない値段」と怪訝な顔。 そこで商社さんに見積もりの確認をお願いすると「100MHzの水晶は特注品になります」というご回答。「聞き違えたか?」と思いつつもそのことを先輩に報告にいくとその先輩、何が起こっているのかそこで察しがついたらしく「100MHzの水晶というのは無いんだ。99.99MHzの水晶を発注しなさい」とのお言葉。 99.99MHzで度見積もりを取り直し事なきを得ることができましたとさ。

水晶というのは結晶軸に対する切り出し角度で振動数が決り、 よくあるのが33.33…MHzで切り出した系列のオーバートーンの製品だったらしいのです。 100.00MHzもあるのですが25.00MHz系列の製品はその時はあまり流通していなかったようです。

第4回 水晶振動子の発振周波数はどう決まるのか:水晶デバイス基礎講座 - EE Times Japan

そういえば16MHzとして売られている水晶も実は16.666…MHzのことがあって、 自分が昔使っていた16MHzのパソコンが実は16.67MHz だと知らされたときなんだかとっても得した気分になったことがありました。

#define HZ 33000000 ちょっと待った!

組み込みでプログラムの仕事をしているとPLLにクロック分周の設定をする機会があります。 そこで見かけたのが次のクロック周波数の定義。

#define HZ 33000000ul

「こっ、これはもしや若いときに経験したあの事件と同じパターンでは!」と咄嗟に悟り、 急いで確認するとやはり33333333MHzが正しい値でした。

ちゃんとulがついているあたりおっちょこちょいな人が間違えたわけではなさそうですが、ハード屋さんでもなければカタログに33MHzと書いてあったらそれを疑う人はまずいません。

#define HZ 33333333 にすれば正しいのか?

しかし33333333で良いかというとこれも少し引っかかるところがあります。

定義が無限ではなくて有限なのです!

そのせいで3倍しても100000000にならず99999999になります。 カーネルのログに99999999MHzって出てるのを見るとなんか違和感ありますよね? そういう理由だったのです。

そこで何かよい方法がないかと考えたのが次のマクロ定義

#define HZ 100000000ul/3ul

これだとプログラムの中で3倍したときちゃんと100000000になります。ヤッター!

・・・しかしこれを先ほどのulの人にレビューしてもらうと「ちゃんと括弧で括りましょう」と指摘を受けてしまいそうです。

#define HZ (100000000ul/3ul)

確かにどこでどう使われるかわからないマクロを演算子を剥き出しのまま定義するマナーのソフト技術者はいません。除算の演算子C言語の算術演算の演算子の中では優先度高い方なので、このままでもおかしなバグになることは無さそうですがやめておくべきでしょう。 でも括弧で括ると折角のアイデアもご破算です。 何か上手い方法はないものでしょうかね?