mutsuで「ループなしで1〜100を印字」を動かす実験

1000/999²の小数展開を使って1〜100を連番出力するトリックを、自作Rakuインタプリタmutsumutsu)で再現できるか試した記録。

#raku #mutsu #experiment #math

目的

Gaucheの多倍長有理数演算で成立するこのトリックが、Rakuの数値タワー(Int/Rat/FatRat)でも同様に動くかを確認する。

環境

  • mutsu 0.21.0(miseでグローバルインストール: ~/.local/share/mise/installs/github-tokuhirom-mutsu/0.21.0/bin/mutsu

試行錯誤

最初はGaucheの有理数演算に倣ってFatRat(Rakuの任意精度有理数型)で組んだ。

my $x = FatRat.new(1000, 999**2) * FatRat.new(10**303, 1);
my $n = $x.floor.Str;
$n = ('0' x (3 - $n.chars % 3) % 3) ~ $n;
for $n.comb(3) -> $g { print "$g "; }

これは動いたが、FatRatが実は不要と気づいた。RakuのIntはデフォルトで多倍長整数なので、1000 * 10^303をそのまま999²で整数除算(div、floor除算)すればよい。

my $digits = ((1000 * 10**303) div 999**2).Str;
$digits = '0' x (-$digits.chars % 3) ~ $digits;
say $digits.comb(3).head(100).join(' ');

さらにゼロパディングを手計算せずsprintfの幅指定に任せれば1行に収まる。

say sprintf("%0303d", (1000 * 10**303) div 999**2).comb(3).head(100).join(' ');

実行結果

$ mutsu print100.raku
001 002 003 004 005 006 007 008 009 010 ... 097 098 099 100

3桁ずつのグループが001から100まで途切れなく並んだ(さらに先の101まで正しく続くことも別途確認済み)。

読み取れること

  • mutsu上でRakuのIntは最初から多倍長(bignum)であり、FatRatを持ち出さなくても整数のdivだけで元のトリックを再現できる。Gauche版が有理数演算(/)を使っていたのに対し、Rakuでは10^303倍を先にIntの乗算に織り込めるため整数除算1回で済む。
  • divは正の被除数・除数に対してはfloorと同じ結果になるため、明示的な.floor呼び出しは不要。
  • sprintfの幅指定(%0303d)でゼロ埋めを任せられるので、桁数を手動計算するコードが消せる。

躓いた点

substrで先頭から30文字を単純に切り出すと、ゼロパディングをしていない生の数字列は3の倍数境界からズレており、001,002,...ではなく100,200,300,...のようにズレたグループ化に見えてしまった。ゼロパディングして総桁数を3の倍数に揃えることで解決した。

作成日時: 2026-08-15 10:04 / 更新日時: 2026-08-15 10:04