見出し画像

【常識?非常識?】高速化プログラマの数値処理と文字列操作の感覚3選

30年以上プログラミングしているムンペイです。
高速化にハマり、マルチコア、GPUなど向けにソフトウェアを書いてきました。

今は採用面接でプログラミング試験の実施を担当することもありますが、その中で若いプログラマの皆さんとの感覚の違いに気づくこともあります。数値処理と文字列操作の中で3つ紹介します。


1. 10進数、16進数、2進数は同一に見えている

多くのプログラミング言語では数値データを、10進数だけでなく、16進数、2進数、8進数あたりでも扱えるものが多いですが、高速化プログラマにとってはこれらは全く同じに見えています。
一方、16進数を扱うプログラム試験を行った場合、10進数に「変換」しようとするのを見ると、コンピュータアーキテクチャに慣れたプログラマにとっては強い違和感を感じます。

unsigned int x = 0x12ab56cd;
unsigned int y = hex2dec(x);  // 変換するなんて?!

よく聞くことと思いますが、コンピュータ内ではすべてのデータがビットで表現されています。ビットとはつまり0と1のどちらかです。ですので、プログラムのソースコードにどの進数で表現しても、コンピュータの内部ではなんらかのビットの並びとして保存されるのです。

同じ値であるならば、ある変数に、10進数で代入しようが、16進数で代入しようが、2進数で代入しようが、内部的には全く同一のビットの並びが保存されます。
プログラミング言語上の「進数」の違いは、プログラマにとってわかりやすいような表現の違いでしかないのです。

以下はどれも同じビットの並び
313218765  -->  0b10010101010110101011011001101
0x12ab56cd   -->  0b10010101010110101011011001101
0o2252653315  -->  0b10010101010110101011011001101

「16進数を10進数に変換する」という表現からは、コンピュータをブラックボックスとして見ている印象を受けます。
しかし、コンピュータの性能を引き出すプログラミングを目指すなら、データがコンピュータ内部でどのように表現されているかまで透けて見えるようになる訓練をしましょう。

2. 数値データの桁数が多いと身構える

パフォーマンスに敏感なプログラマは、数値データの桁数が多いと身構えます。具体的には、コンピュータの「ビット数」の長さを超えないかどうかいつも気にしています。

323218765 --> Easy!! 32bit!!
4294967295 --> Easy!! 32bit!!
4294967296 --> Caution!! 64bit!!
5323218765 --> Caution!! 64bit!!

よく、 32 ビットコンピュータとか、 64 ビットコンピュータとかいう表現を聞いたことがあると思います。これは、コンピュータの CPU の命令で扱うビット数を表しています。 32 ビットコンピュータならば、いつも 32 ビットの単位で計算をします。64 ビットコンピュータならば 64 ビットが単位です。

このビット数を超えてしまうと、CPU が1個の命令で扱えなくなり、何回かの命令に分けて計算する必要が出てきてしまいます。高速化を目指すならば避けたい状況です。

もう一つ、メモリアクセスの単位としてもビット数が重要ですが、ハードウェアの工夫や先読み機能などかなり事情が複雑で高度になります。CPU のビット数を意識するのがまずは重要ですが、64ビットは32ビットの2倍の容量を使うわけですから、無駄に使うわけにはいきません。

ということで、よく使うのは以下のような感じだと思います。

  • 整数ならば、まずは32ビット以内で間に合わないか考える。64ビットもの整数データを扱うことは暗号の演算程度に限られ、それほど多くない

  • 浮動小数点数は、64ビット(倍精度浮動小数点数)でまずは考える

3. 文字列を見ると身構える

文字列の処理は非常に複雑です。世界中に多様な言語があるためですね。
ですので、プログラミング上も非常に複雑で、処理時間もかかるため、文字列を見ると慎重になります。

現在はほとんどのOS、プログラミング言語でUnicodeが主流であるため、かなり楽にはなりました。Unicodeの文字はメモリ上では16ビット単位のデータとして表現されています。

では、16ビットで1文字かと思いきや、いつもそうとは言えない、というのが文字の世界の深い部分です。
世界中の文字を集めると、16ビット=65536個ではとても足りません。そのため65536個を1セットとし、第何番目のセットを使うという指示データをつける場合があります(※1)。
このような指示データがあったりなかったりするので、文字のデータは前から順に読み解いていかないと行けません。つまり逐次処理が必須であり、並列化できません。ここが、高速化の敵である部分です。

※1:Wikipediaに全文字が載っているようです。

また、高速化の文脈とは違いますが、ファイル(やネットワーク)上の表現がまた違うのが文字列の厄介なところです。Unicodeは16ビット(2バイト)を単位としていますが、例えばほとんど英数字のデータなのにいつも2バイトを使うのは無駄です(ファイルはデータ容量を小さくしたいのでした)。
そこで、ファイルに書き込むときは1バイト単位として、2バイトや3バイトが必要な文字はセットを切り替える指示データを入れるという方式で表現することが多くなっています。UTF-8は代表的な方式です(※2)。

※2:UTF-8だけでなく、様々な文字コードの解説が書かれています。

まとめと次回への期待

コンピュータの性能向上とプログラミング言語の進歩により、コンピュータはますますブラックボックスとして扱えるようになってきました。これは良いことなのかもしれませんが、コンピュータの性能をより引き出したいとか、多用される重要なコードを書く場合といった場合には、今回のようなプログラミングにおける数値データと文字列処理の高速化についての知識的・技術的な探求も必要でしょう。

プログラミングは単なるコードの書き方以上のものです。それは問題解決の芸術であり、創造的な表現の形です。コンピュータの歴史の中では多くの天才的プログラマが、限られた性能を極限まで引き出して高速に処理するために、まさに芸術的とも(あるいはトリックとも)いえる発想のコードも多く生まれてきましたが、この話はまたの機会に。

これにて御免!

(見出しにはUnsplashEkaterina Z.が撮影した写真を使わせていただきました)


この記事が気に入ったらサポートをしてみませんか?