晴れ時々雨。 在宅勤務。 部屋の中はひんやりしていたので時々セラミックファンヒーターでぬくぬくしていたが、外はそれなりに暖かかった。
テレビアニメ『るろうに剣心 ―明治剣客浪漫譚―』2023 年版。 14 話。 新オープニング・エンディング。 弥彦ちゃんの日雇い仕事。 こんな話あったのか。 竹刀で真剣に勝っちゃう弥彦ちゃん。
テレビアニメ『MF ゴースト』。 ABEMA 配信。 1 話。 あの『頭文字 D』の作者が描く原作漫画のアニメ版。 電気自動車が主流になった未来に、内燃機関でレースをするみたいな話らしい。 登場人物の顔がどこか『頭文字 D』の登場人物の顔に似て見えるところがある。 全員ではないけど。 かたせえのしま駅。 イギリスから来た少年、日本語は流暢で、日本語に混じる英語は日本語訛りw 「小田原事務所」。 すき家。 「緒方自動車」。 鎌倉。 涼介とはあの涼介か? トヨタ 86 で予選へ。 小田原パイクスピーク、一周 40 km。 未来の設定だけど、スマートフォンの連携、人と人のやりとりなどに過去を感じるw
小田原パイクスピークってたぶんコロラドのパイクスピークを意識したんだろうけど、あれ元はパイクさんのピークだからね、小田原にもパイクさんが来たのかなw Pikes Peak を調べていたら、頂上まで 2 回行った Mount Evans の名前が変わっていたことを知った。 今は Mount Blue Sky らしい。 Pikes Peak は 2 回行ったけど頂上まで行ったのは一度だけだ。 Mount Evans のほうも 3 回行っていて一度は頂上までは行けていない。
テレビアニメ『16bit センセーション ANOTHER LAYER』。 ABEMA 配信。 1 話。 いきなり左右黒帯 4:3 画面で始まって、4:3 ディスプレイで見ていると画面拡大すべきか迷うが最初だけだったw 2023 年から 1992 年、「タイムリープ」。 秋葉原。 「ブルーベル」。 美少女ゲーム。 イラストレーター。 ソフマップっぽい音楽、いや、ソフマップそのものか。 西荻窪。 三鷹。 中古ゲーム屋。 実在したゲーム Kanon を力説する主人公。 からの、タイムリープだ。 PC-9801。 RA っぽいデザイン。 ミニフロッピーディスクの入れ方に違和感あるな。 パソコン本体に指引っ掛けて入れることはあまりしなかった気がする。 まぁ、自分は 1992 年はまだ IBM JX を主に触っていたんだけどw 次回予告はタイトルのみ、MIFES 風の画面で。
去年買ったダイソーの 100 円 USB マウス、ホイールによるスクロール操作が時々チャタリングを起こしているような感じになってきたかなー、というところ。 100 円のくせに 1 年半近く持つとは。 優秀。
晴れ。
昼休みに整形外科。 いつもの。 インフルエンザのワクチン接種が始まっているらしいので予約した。 健保の割引はきかないんだけど、まぁいいや。 これでも去年のクリニックより安いしな。 内科と違って整形外科はゴホゴホ咳をしているような人がほとんどいないのも良い。 今年のインフルエンザワクチン接種のベストタイミングはさっぱりわからんので (夏の間に静まらず今も感染が拡大している状況)、普通に近々接種を受ける予定。
夕食を食べながら将棋の王座戦の中継を眺めた。 藤井 vs 永瀬。 永瀬が先手。 途中、コンピューターは藤井の竜の筋を防ぎつつ王手をする裏技みたいな手を示していたが、対局者はそこまで気づけなかったのだろう。 それで藤井優位かと思いきや、藤井は 1 分将棋でベストな手をさせずに、少しずつ永瀬が優位に。 もうちょっとで決まりそうというところで、永瀬が大きなミスをやらかしコンピューターの評価値が見事にひっくり返った。 大逆転! 藤井の頭の中にはその評価値が見えていたに違いない。 どちらも 1 分将棋になっていたとはいえ、永瀬本人も明らかにあーやらかしたーっていう顔になっていて... 藤井がそこから本当にひとつのミスもなく詰めていって藤井八冠の誕生!
今時の将棋観戦は本当におもしろい。 コンピューターが出した、相手の竜の筋を防ぎつつ王手をする裏技みたいな手は、解説のプロ棋士もなるほどこれはと言うような手だった。 すごいけど大駒ひとつは確実にとられちゃうからなかなか打てないですよね、みたいな。 コンピューターはそのベストな手をもとに、こっちが有利だと表示しているのだ。 もうちょっとで決まりそうというところも、コンピューターがこっちが圧倒的に有利と出していて、この手で王手をすれば、と候補をあげていた。 プロ棋士もそれを見て、詰めろではなさそうだけどかなりこちらが有利になり、相手は勝ちにくくなりますね、みたいな解説をする。 でも対局者にはそんな数字は見えていないわけで、形勢もそれぞれの判断でしかわからない中必死に考えているのを、観戦している側はなるほどねーなんていいながら見ているわけだ。 かと思えば、あまり差がない状況では、コンピューターが不思議な手を候補にあげてくることもあり、プロ棋士もそれは指さないですよねみたいな解説をすることもある。 それに、1 分将棋の微妙な局面では、1 分近く経っても候補がコロコロと変わる局面もあった。 深く探索をしないと適切な評価値が得られないような難しい局面ってことだ。
全国銀行データ通信システムのシステム障害についてまとめてみた - piyolog
なんか大変そっすねー、っていう人ごと気分なのは、特に金融関係の仕事はしていないのと、このシステム障害の影響を受ける金融機関の口座を持っていないからである。 が、持っていなくても、それらの口座への振り込みも障害の影響を受けているそうなので、たまたまそういう振り込みをしなきゃならん、みたいなことになっていたら、困っていたかも知れない。 しかしモアタイム (平日 8:30-15:30 以外) は振り込み OK ということで、SBI 新生銀行も農業協同組合もモアタイムシステム参加金融機関に含まれているから、そこまで困るもんでもなさそう。
三菱 UFJ 銀行が今回のシステム障害の影響を受けている中で最大手の都市銀行だろう。 三菱 UFJ 銀行と JA バンクは現金自動預払機の相互利用で手数料優遇があるため、システム障害の影響も同じように受けてしまうのではないかと一瞬身構えてしまうんだけど、そこは全く関係がないようだ。
いろんな人のポストを見ていておもしろいなと思ったことのひとつは、光熱費、クレジットカードの請求額支払いやローン返済等の引き落とし (口座振替) の問題だ。 引き落としは特に影響なく実施されているが、引き落とし前にお金を入れておこうと他の金融機関から振り込みをしたものや、場合によっては給与振り込みが、今回のシステム障害の影響で届いていなくて、引き落としに失敗した、なんていう悲しい事例がそれなりに存在していそう。 別に残高ギリギリにしていなければいいじゃん、というのはそれはそうなんだけど、低所得者においてはそれが難しい人もいるだろうし、そうでなくても、例えばローンを組むのに A 銀行の審査しか通らなかった、みたいな場合に A 銀行の口座を作って、他のメインの口座からそこに振り込みで移している、みたいなケースも少なくはないだろうな。 クレジットカードの支払いに関しては、以前限度額に達して振り込みで回避したことがあったのを思い出したよ。 システム障害にしろ何にしろ、通常の手段で払うはずのところを別手段で払うってことは、一時的に二重にお金が出ていった状態になる、ということではあるのだ。
あと、次回の年金支給があさって 13 日なんだって。 そこまで引きずらないようにがんばるだろうし、別系統で影響がない可能性もあるけど、そういうことでトランザクションが溜まっていくのはうれしくはないだろうね。
晴れていたが、夜に雨が降った。 涼しい日。
いや、涼しいで済めばいいんだが、このところ睡眠時間が細切れになりがちなのは、冷えのせいだな、たぶん... 夏場はエアコンを 24〜25 度設定の除湿にして寝ていたくせに、秋になって自然と室温がそれより低くなってくると勝手に目覚めるとはひどい体である。 いや、たぶん、昼間に冷えているのが夜まで響いているんだろうとは思う。 なお、こんなに気温が変動しても、風邪は引いていない... やっぱり風邪はウイルスや細菌が原因なんだ...
そういえば、こないだの港南区、なんとつくばから来た先生方は列車の乗り換えは 1 回だったとのこと。 確かに、検索するとうまくいけば秋葉原から乗り換え不要で、しかもつくば駅から最短 1 時間 57 分とは驚きだ。 そこまでうまくいかなくてもだいたいは 2 時間 10 分程度らしい。 うちからだと最寄り駅からベストタイミングで乗れれば 3 回乗り換えで 1 時間 49 分だったらしい。 乗り換え回数を少なくすると 2 回乗り換えで 1 時間 59 分、これは東京駅乗り換えのルートだ。 距離で見ると、渋谷や川崎を使って詰めれば 60 km ちょっとにおさまるが、それは別に早くない。 早いルートや東京駅乗り換えルートは 75 km ぐらい。 そして、うちから車のルートだとなんと 50 km を割る。 地図を見ると、明らかに第三京浜が良いところを通っている。 一般道ルートにしても、空いていれば 1 時間半を切れるらしい。 鉄道はどうしても不利になる。 つくば駅からだと鉄道で 105 km ぐらい、車では 110 km ちょっととなり鉄道よりも遠い。 時間は車でも 1 時間 45 分ぐらいで意外と短いんだけど、あっちは首都高を通るから渋滞ポイント多数なんだよね。 ちなみに、所沢駅からだと、鉄道で 1 時間 45 分ぐらい、70 km ぐらい、直通運転がパワーを発揮し乗り換え 1 回。 明らかにうちからより遠いのに時間的には近い。 車で 1 時間 25 分ぐらい、65 km ぐらい、環八経由のルートなので土曜日の混雑はありそう。 ま、いいや。 横浜はともかく、港南区に行く機会はあまりあるまい。
晴れ。 出社。
テレビアニメ『オーバーテイク!』。 ABEMA 配信。 1 話。 SUPER GT。 富士スピードウェイ。 見覚えがある景色がいっぱい! F4。 声の役がすべてわざとらしいアニメ。 フォトグラファーが主人公、なのかな。 サーキットのモータースポーツ観戦初心者向けみたいな解説中心の内容だ。
テレビアニメ『呪術廻戦』。 36 話。 「都心メトロ」。 明治神宮前駅-渋谷駅間。 「首都高速 3 号渋谷線 セルリアンタワー前」。 とばりあがる。 魂の情報。 だんだん進む。
テレビアニメ配信、TVer や局の配信プラットフォームで配信されないアニメが多いのは本当にクソさんだが、ABEMA で配信されている率が高く、アニメといったら ABEMA、みたいな立ち位置になっているように思える。 アニメの公式サイトを見ても、なんかごちゃごちゃ書いてある中に ABEMA ってあったら、もうそれでいいかってなる。 こんだけ慣れていると、例えお金を払うことになったとしても、ABEMA ならいいか、となるかも知れない。 まぁ、自分みたいなケチは無料配信を全力で使うんだけどw
かごしま国体 桜島噴火活動活発化で火山灰 競技への影響も|NHK 鹿児島県のニュース
鹿児島で開かれる国民体育大会では降灰に慣れている鹿児島出身者が強いという、冗談のような本当の話?
この前の話でまとめて書き込みが重要らしいことがわかったので、さらに整理して、setbuf()
を使いバッファリングをオフにした上で、BUFSIZ
に近い長さを一気に生成して書き込むという実装をしてみた。
さすがに C のマクロでいろいろとやるのは限界を感じたため、template
のためだけに C++ 化した。
各桁用の構造体を作ってそれを template
で使用することで、桁ごとに別々のコードが生成されるから、関数の中で桁数による分岐を書いても、それが実質的にはコンパイル時に決定されるはず、という狙いである。
また、10 桁目問題 (処理的には 9 桁目) を以前のものとは異なる方法で処理することで、10 桁の処理の分割も無くした。
内部処理で 8 桁目をわざと 0xf6 ではなく 0x36 にすることで 2 ビットを確保し、0x36, 0x76, 0xb6, 0xf6 の 4 種類の 9 桁目を持てるようにした。
4 種類あれば 1000000000 から 4294967294 の 10 億の位を表現できる。
ただしこの影響で 9 桁の場合の 8 桁目と 9 桁目は取り出しの際に別途ビットマスクなどが必要になる。
これが性能面でいいのか悪いのかは未調査だけど、コードはシンプルになった。
今回もオペレーティングシステムに依存するシステムコールの使用は避け、標準 C ライブラリを用いた実装にしている。
性能は狙い通りさらに向上し、17 秒ぐらいから 11 秒ぐらいに短縮した。
出だしから 3GiB/s 近い勢いだ。
これでも、すずき氏の最適化てんこ盛りバージョンに比べれば倍近い時間が掛かるのだけど、むしろ、こんな移植性重視のコードでも倍で済むのか、と。
なお、すずき氏のコードでは 15 の倍数を "FizzBuzz"
と出力しているが、自分のコードでは "Fizz Buzz"
と出力するため若干出力の長さが異なる。
そのおかげで 10 桁 30 個が 256 バイトになるというおいしい恩恵があるが、今回の実装ではバッファリングをオフにしたのであまり恩恵はなさそうだ。
今回も clang より gcc のほうが圧倒的に速い。
今回は -march=native
をつけてもあまり差が出ないが、つけたほうがやや速そう。
基本的に -O3
で試しているが、-O2
でも速い。
なお、GNU/Linux の GNU C ライブラリにおける BUFSIZ
は 8192 らしい。
前のバッファリングありバージョンを strace コマンドで観察すると出力は 4096 バイト単位だったが、BUFSIZ
はなぜかその倍の 8192 らしい。
そうだなぁ、前の実装でも 8192 バイトのバッファリングにしたら速くなるだろうか?
static _Alignas (4096) char filebuf[BUFSIZ];
setbuf (stdout, filebuf);
これを入れることでバッファリングが 8192 バイトになり、性能は実際にやや向上し 15 秒ぐらいになる。
つまり速くはなった。
でも今回のチューニングに比べれば遅い。
おそらく、今回のものと違い、前の実装では fwrite()
によるメモリーコピーがあるのが、この差につながるんだろう。
おまけ。
8 バイトの書き込みが異様に速いであろう AMD64/Intel 64 アーキテクチャーを想定した泥臭いチューニングを追加した。
内部 7 桁の書き込みを手前の '\n'
まで含めて 8 バイト書き込みにして高速化、しかし 7 桁だけ集中して計測すれば差はあるものの、7 桁は一瞬で通過するため効果は 0.1 秒未満だろう。
9 桁の書き込みを 8 桁だけで済む範囲は 8 桁で済ませる高速化、これはきいてはいるようだが、0.2 秒ぐらいのものか。
コードが読みづらくなった割にはたいした効果はなかった。
晴れ。 寒い日。
インフルエンザワクチン接種。 保険適用外で 3960 円 (3600 円 + 消費税かな)。 整形外科で普段のリハビリ等は受けなかったためか領収書は 1 枚だ。
例によって注射針が刺さっている時間が長くて痛いものの、注射針が抜かれた後はしばらく痛みを感じなかった。 ここの先生は注射がうまいんだよと、平日毎朝のようにリハビリテーションに並ぶおにいさんにパンデミック前に聞いたことがあったが、確かにそうなのかも知れない。 でも注射針が刺さっている間はさすがに痛かった。 それは仕方がないかw 3 時間ぐらいしたら注射箇所に痛みを感じるようになった。
なお、インフルエンザは今めちゃくちゃ流行っているんですよ、とおっしゃっていた。 コロナで免疫が落ちているのかも知れないけど、みたいな。 学級閉鎖なども頻発しているらしい。 ソーシャルメディアで見かける医師達の情報通りだ。 受け付けに貼られていた三鷹市内の先週の感染者数の情報も、新型コロナウイルスが 100 人台なのに対してインフルエンザ A 型が 800 人台と圧倒的だった。 この勢いなら、例年と違って 1 月ぐらいには流行が落ち着くのでは? なぁんて淡い期待を抱いているけど、そんなことは実際にその時になってみないとわからんね。
午後はゴロゴロ、眠くて昼寝したのはワクチン接種の影響か否か。 いつも週末はゴロゴロしているから大差ないか。 昼寝中に見た夢、鍵を掛けている戸の、がたつき分だけ動かすだけで部屋にすきま風がとんでもない強さでゴーゴー入ってきたり止まったりする不思議な世界。 近所の人の会話みたいなのも聞こえていたような気がする。 これは夢だなー、でもおもしろいなー、と思って戸をガタガタやっていたんだけど、そのうちなぜか息ができなくなって、起きなきゃ! 鼻が詰まっている!? みたいになって、それから目が覚めた。 夢から覚めるのに時間がかかったのは、どうやら夢の中で夢を見ていたようだった。 睡眠時無呼吸症候群的な何かでないことを祈る。
DOS 版を作った (笑) 例によって 4294967294 まで出力する。 DOS では 4GiB 以上のファイルは作れないので (試していないけど、NTFS な 32 ビット Windows のコマンドプロンプトの DOS ならもしかしたら作れるかも?)、画面に流すか AUX (シリアルポート) や PRN (プリンター) にリダイレクトするかしかなく、はっきり言って実用性はない。 そこで性能は度外視で、コードサイズを小さくしようと試みた。 8086 向けのコードとしては、レジスターが 16 ビット幅のため、どうしても 32 ビットの値を扱うのは面倒くさい。 そのため 3 で割ったり 5 で割ったりする単純なコードも長くなってしまう。 それでどう工夫するかというところ。
3 と 5 についてはそれぞれカウンターを用いて数える手がある。 さらに詰められないかと考えていたらパリティフラグを思い出した。 1 から 15 までの数を 2 進数で思い浮かべてみると、なんと見事に 3 の倍数と 5 の倍数が偶数パリティで、他が奇数パリティである。 これを逆に 14 から 0 に減る方向にしても、2 進数で見たら 4 ビットを反転しているに等しいのでパリティは変わらない。 減る方向にすると、15 番目にあたる 0 もゼロフラグで判定ができるので、15 の倍数の判定とともに値をリセットするのに使えておいしい。 あとは 3 の倍数なのか 5 の倍数なのかを判定しなきゃならない。 それには困って、判定用ビットパターンを作って、シフトして取り出すことにした。 15 回のビットシフトだと 15 ビットが必要だが、3 の倍数か 5 の倍数の時だけに絞れば 7 ビットで表せる。
数字への変換も、32 ビットの値を 10 で割って生成していたら、処理時間だけでなくコードサイズの点でも話にならない。 0xf6 の活用をしようにも、あの方法では 16 ビットに 2 桁しか入らないからメリットが生かせない。 それで単純に最初から US-ASCII を使う。 9 の次に来たら 0 に戻し桁上がりを処理する。 最初に使っていない桁にはわざと数字より大きな文字コードを入れておき、9 の次に来たかどうかの比較の際についでにそれを判定して、桁数を増やしてそこを 1 にする処理を入れている。 ループを書いてもコードサイズはあまり大きくならずに済む。
終了判定。 別途 32 ビットのループカウントを持たざるを得ないが、少しは性能のことを考えて、15 の倍数ごとに判定するようにした。 4294967294 は 15 の倍数から 1 を引いた値なので、15 の倍数の処理の時についでに判定する。 0xffffffff を 0xf で割ったら 0x11111111、わかりやすい。 1 を引くのに DEC 命令を使えば 1 バイトで済むので DEC 命令を使いたいが、DEC 命令はキャリーフラグを更新しないため、これを 0x1111 * 0x10000 + 0x1111 と考え、2 つのカウンターを 0 まで減らすという作戦にした。 さすがにレジスターが足りず片方のカウンターはメモリー上に置いた。
性能という意味では中にバッファーを持たせているのも少しは性能のことを考えてである。 まぁ画面や AUX や PRN だと PC 互換機では BIOS の仕様で 1 バイトずつになってしまうのでメリットは小さいんだけど、それでも出力はまとめたほうが少しはマシだろう。 出力途中でバッファーがいっぱいになるのを扱うのは面倒くさいので、少し後ろにはみ出せるようにして、バッファーに転送した上でしきい値の長さを超えていたら出力、という形にした。 これを、15 の倍数のタイミングで毎回出力ということにすれば、もうほんのちょっと短くできそう。
性能については HIDOS に入れてある拙作 doscomm を使って実行して計測して 46MiB/s。 命令インタープリターで実行してこれっていうのは結構速いほうなんじゃないかと思う。
で、それを HIDOS を QEMU Linux KVM で立ち上げて NUL へのリダイレクトで実行したら、なあんと、42 分かかった。 裏でちょっと負荷をかけていた時もあったとはいえ、根本的にペースが遅い。 試しにデバッガーで書き込みのシステムコールを NOP でつぶしたところ 1 分ちょっとになった。 16 ビットコードの実行が遅いんじゃなくて、DOS のシステムコールが遅いんだな。 NUL への転送なんて、メモリーコピーもなく渡されるものかと思っているんだけど、違うのかな。
雨のち曇り時々雨。 寒い日。
腕は痛いが体調は悪くない。 DAZN が見られるのが今日までなので、Wednesday F1 Time の日本 GP 後の分を見ておいた。
テレビアニメ『葬送のフリーレン』。 6 話。 ドワーフの弟子は村の英雄。 「怖がることは、悪いことではない」。 竜が街を襲わなかった理由。 くだらなくて楽しい旅。 魔物が活発なための関所。 商人ギルド、盗賊ギルド。 何かのゲームみたいなキーワード。 フリーレンの名前は英雄として一部の人達に知られている。 本人は魔法の研究をしたいw
テレビアニメ『オーバーテイク!』。 2 話。 お金の話。 そして菅生、か? スポンサー集めは大変。 それはそう。
なんかきのうのを書いた後で、見直していたらいろいろ縮められることが判明して、ゴリゴリ縮めて、2 つのカウンターもレジスターに置くまでになった。 なんかもうちょっと縮められそうな気もするけど、わからんなー。 もはや、10 桁用という前提を忘れてしまうようなコードになってしまったが、データに 10 桁分しか用意していないから 10 桁である。 これ EXE 形式なので余計に容量を食っているところがあって、COM 形式に変えればさらにギリギリまでいける。 先頭のセグメントロード以外は COM でもいけるように書いたつもり。
晴れ。 少し暖かくなったんだけど部屋はちょっぴりひんやり。
夜ちょっと車で買い物に行く途中、ちょっと寄せすぎて、道路脇のスピード落とせの立て看板に左ドアミラーの角をあててしまったw 少し目測を見誤ったというか、少しボケッとしていたというか。 バイクと違って車の幅は広いから気をつけないとね。
ダイソーで 100 円の USB マウスを再び買ってきたんだけど、帰ってきてみると前のマウスのホイールのご機嫌がなおっていてなんともよくわからない。
テレビアニメ『16bit センセーション ANOTHER LAYER』。 2 話。 VZ Editor の画面! 謎の SLL 命令!! ここで働かせてくださいパターン。 パソコンは DA。 クッソ懐かしいペイントソフトの画面。 まるぺ、マルチペイントか。 いにしえの技術。 ハードドライブついているふうじゃないのに、フロッピーディスクドライブのレバーがあがっているの気になるよねw あっ、でもマイクロフロッピーディスクも使っていたから外付けドライブありか? VZ Editor の画面に PLAY とか STOP とか .mid とか何か MIDI プレイヤーみたいなのがオーバーレイされていてあれは何だ。 知らない世界。 美少女ゲームから始まり世の中に美少女があふれるのだ! (?) その因果関係は知らないけど、確かにこの 31 年の間にずいぶん変わったね。
テレビアニメ『MF ゴースト』。 2 話。 「ありえねぇ」連発は『頭文字 D』的な展開だ。 慣れる前のアップヒルですでに速く、慣れてきたダウンヒルで攻めるw 高橋涼介が医師になっているw 一般には Ryo Takahashi という謎の人物ということになっているらしい。 そして藤原拓海の名前も出てきた。 片桐ってのも『頭文字 D』にいたっけ? いや、いないか。 過去に富士山が爆発してガスが出て霧が云々、という未来設定。 『MF ゴースト』、雑に言えば『頭文字 D』の公道バトルを合法化した作品か?w
テレビアニメ『るろうに剣心 ―明治剣客浪漫譚―』2023 年版。 15 話。 出稽古。 道場破り。 竹刀で道場の師匠は敗れ、剣心が木刀で相手して決着着かず。 そして呼ばれる。 これも過去のシリーズで見たことがない話でとまどっている。 原作を見ていないからなぁ。
2 バイト縮められたぁ! CALL がふたつあって 6 バイト、CALL があれば RET の 1 バイトもあって、しかし終了時にもバッファーのフラッシュが必要なので縮めるのは無理かと思っていた。 フラッシュのルーチンをメインループに持ってくれば、メインループの CALL/JMP/RET はいらなくなるが、フラッシュ後に終了判定が必要。 最低でも条件分岐に 2 バイト、そしてフラグのセット用にあと何バイトか、あるいは、フラグを必要としない条件分岐といえば JCXZ。 CX はシステムコールの引数で壊してしまっているが、スタックにある CX には桁数を保持しているので、それが最後に 0 になるのは理にかなっている。 しかし 0 を PUSH するには XOR と PUSH の 3 バイト必要で、最後のフラッシュ処理のための無条件ジャンプの 2 バイトを加えたら、せっかく CALL と RET で削った 7 バイトを別で追加することになって何も減らないじゃないか、と思ったら、最後はカウンターが 0 になるんだった! XOR いらない!
などと思いついて実際削れたので、もう CALL/RET もなくなった。
後は厳密にはフラッシュ処理で LEA を使えば 1 バイト削れそうということに気づいてはいるものの、MASM が [DI-BUF]
を拒否するので無理かな。
あと、この 1 バイトは COM 形式にしたら削れない部分でもある。
もうひとつ、15 個カウントと判定用ビットパターンのレジスターを戻すところを、0 になっていることを利用して符号判定でメインループに入れることで初期値設定を流用することができ、もう 1 バイト削れた。 これ以上は無理かなーと思って風呂に入っていた時、改行文字を切り離すアイディアが。 改行 (13, 10) 4 つを削り MOV と STOSW で書き込むと、8 バイトのデータが 4 バイトのコードに化ける。 それだけでなく、FizzBuzz の文字列の流用ができるようになりさらに 8 バイトのデータが削減できたし、文字列のオフセットアドレスも MOV immediate の代わりに演算で求められるようになり、1 バイト削れた。 数値のインクリメントの際のアドレス代入も、改行文字の分を考えなくていいので、PUSH/POP に変えて 1 バイト減った。 そうなったらもうあとは COM 形式だな、と思って作ったのがこれ。
124 バイト! 立派な誰得プログラムの完成!
晴れ。 昼は暖かく、夜はひんやり。
きのう昼のラジオで紹介されていた、駅近くの弁当屋さん (なのかな?) に行ってみた。 最近オープンしたらしい。 作り置きタイプなので待ち時間がない! 量は普通、値段はこのへんにしては高めだが、野菜が多めなのは好感が持てる。 いつもの弁当屋さんがこんでいる時なんかに使おうかな。
そういえば、スマートフォン Android One S9 は、アップデート後は比較的ちゃんと動いているんだけど、Pokemon Go は起動しなかったケースが一度だけあった。 その時はやはり Google Play 開発者サービスを強制終了するとちゃんと起動した。 その時も Google Fit などのアプリはちゃんと動いていたし、Firefox のトラブルにも遭遇していないので、やっぱりアップデートで何か修正されたってことだろうな。 まぁ、Android 14 のアップデートがそのうち来るんだろうけど、先日リリースされたばかりだから、アップデートとして届くのはいつになることやら。 おそらくそれまで Bluetooth Low Energy が使えないから Qrio Lock が使えないんだよね。
MOV
のひとつを XOR
に変更PUSH
を最初にするように変更AX
をあらかじめセットしておき JCXZ
で直接 INT 21H
にジャンプするように変更し INT 21H
をひとつ削除STOSW
を下に移動し、改行文字の LF (10) を数字の桁上がりの際の減算に流用118 バイト。 コードゴルフってのは、どうしてこう、もう減らないだろと思ったところから 1 日経つと 6 バイトも減るんだろうなぁ... このぐらい短くなってくると、命令のひとつひとつにすごく意味があって、おもしろい。
まぁ、カウンターについては、当初は性能のことを少し考えて 15 ごとになっていたのを、結局諦めたって話なんだが、これでもバッファリングはしているからいいだろw
やってみたらゼロ PUSH も移せて、ちゃんとスタックが最初の位置まで戻ってから終了するかっこいいプログラムになった。
8KiB のバッファリングをやめるなら、シンプルにバッファーフラッシュの比較と条件分岐を取っ払って、6 バイト縮む。
STOSW
の位置を戻して SUB
の 1 バイトを復活させれば、さらにゼロ PUSH
と JCXZ
を取っ払って、終了判定時のフラッシュへのジャンプを INT 21H
へのジャンプに変更できるので、さらに 3 バイト縮む、つまり、バッファリングを外すだけで全部で 8 バイトは縮められる見込みがある。
あー、カウンターはきのうのコードでも MOV BX,BP
にして DEC BX
の後ろの JNE
を JNS
にしておけば 1 バイト縮んだな。
それと終了システムコールの INT 21H
共有も簡単でそれだけで 2 バイト縮むんだよな。
そして数字の処理の変更で 1 バイト。
合わせて 4 バイトだけど、さらに 2 バイトはもうカウンターを毎回減らすのじゃないと無理かな。
一瞬 15 ごとでもできそうな気がしたんだけど、それは 4294967295 (FizzBuzz) で終わるならという話だった。
ひとつ前で終わらせたいのが微妙に罠だ。
数字の処理のは単に、9+1 したものを 10 引いて 0 に戻す、その定数 10 をレジスターから使えば immediate を使わなくていいよねという、そういう話だが、何となく MOVSB
の直後にやらないといけない気がしていて、その後にフラッシュ処理と終了判定が来るから AX
が壊れてしまうということで、やっていなかった。
よく考えたら終了時はフラッシュを呼ぶから、それまでに書き込めていればフラッシュの後でも OK なんだ。
桁が増えるかどうかの判定がパリティフラグ判定になってしまったものの、最初から 10 引いたら 1 になる文字コードを入れておくことで、無駄に 0 を入れてから 1 にするという過程はなくなった。
晴れ。 このところ昼はぽかぽか朝晩冷え冷えみたいな日が続いているが、なんか、週末は寒くなるらしい。 ひー。
急に現代的な話になって、ファイルディスクリプター 1 に書き出す仕様の、x86_64 Linux 用のコンパクトな Fizz Buzz プログラムである。 きのうまでの DOS 用のと同様に、libc も何も使っていないので、別に GNU/Linux でなくても動作する。 .text セクションのみのコードで、.text セクションのサイズはなんと 128 バイト未満に収まった。
DOS のとは違い、AMD64 の仕様によりコードサイズを縮めるのは難しい傾向にある。 特に、1 バイトの INC/DEC 命令がなくなったので、いろいろ難しさがある。 その代わり、わざと 16 ビットの INC/DEC 命令を用いてサイズを縮めていたものは、その必要がなくなり 8 ビットの演算でもサイズが変わらなくなった。 もちろん、カウンターも 32 ビットで扱えるので簡単。 あとは immediate が基本 32 ビットで長いので、そこはできるだけオペランドサイズプリフィックスを使って 16 ビットで済ませたり、XOR でゼロにしてから 8 ビットだけセットしたりする。 あと、AMD64 特有の REX プリフィックスももったいないので、できるだけ 64 ビットレジスターへのアクセスは避ける。 アドレスは 64 ビットなので避けられないが、PUSH/POP が引き続き 1 バイトなので 64 ビットのレジスター間転送は PUSH/POP で行う。
当初は .data セクションと .bss セクションも入れて DOS のプログラムをそのまま持ってきたみたいなのを書いたが、今時なので position independent executable (pie) にしようと思ったら、(%rip)
の相対アドレスは 32 ビット使っちゃうんだな、つらい。
それならスタックのほうが簡単だな、と。
スタックに数字の初期値データを生成してもそんなに長さを食わない。
おまけに、Fizz Buzz の文字列は 32 ビットのレジスターに入るので、immediate でアキュームレーターにセットして stosl で書き込むという裏技がある。
これは強い。
数字のデータの直後にバッファーが来るのでアドレスを使い回しやすくなって、なんとスタックポインターが出てくるのは最初の 2 命令だけ。
REX プリフィックスは 3 命令のみで済んだ。
ひとつは lodsb を使って減らすこともできるが、長さが変わらないのでそれはしていない。
逆アセンブルして見れば、64 ビットのプログラムとは思えないような短い命令が並んでいる (笑)。
システムコールを直接使っているので C の呼び出し規約も関係がない。 AMD64 で追加された番号レジスターには手を出すことなく書けてしまった。 思ったより短く書けたなぁと思っているんだが、数日でさらに縮むだろうか。
晴れ。 暖かい日。
Linux のシステムコール、x86_64 だと int $0x80
は使えないんだな。
使ってみたらプログラムは黙って終了してしまった。
知らなかった。
最初から syscall
命令が利用可能なのでそれでいいやってことか。
そして syscall
命令も 2 バイトなんだな。
デバッガーで sleep コマンドみたいなのを実行して intr で止めた時、syscall
命令の次のアドレスが出てくる。
ちゃんと __GI___clock_nanosleep
みたいな関数の中でそうなっていて、つまりライブラリも直接 syscall
命令を使っているのだ。
32 ビットの時は sysenter
命令の登場が遅れたし、sysenter
命令は戻り番地が固定になっているので使うにしてももっと面倒なことになっていた。
手元の Atom Z530 環境で試したら、__kernel_vsyscall
の中で、int $0x80
命令の次のアドレスに...
えっ? まさか sysenter
命令も使っていないの? と思ったら、int $0x80
命令のさらに前に sysenter
命令があるw