(確認した Ruby バージョン: 3.2.2, 3.3.7)
節目の AtCoder Beginner Contest 400 に Ruby で参加したら、C問題で謎のWAになって苦しんだ。
解説のひとつにもある平方根で解く方法を選んだ。浮動小数点数による誤差が危険だが、 Ruby だと Integer.sqrt というメソッドで回避できる。
…のに正解にならない。さんざん悩んだ末に、自力で二分探索して平方根を計算するように変えたところ正解になった。
コンテスト後に解説を読んで、考え方は妥当だったとわかったため、何の平方根を求める際に間違えたのか調べた。その結果 Integer.sqrt(4503599761588224)
が正しい値を返していない(小数を切り上げている)ことがわかった。
この値を検索したところいくつかページがヒットした。浮動小数点数による計算でずれるのは仕方ないとして、 sympy の isqrt でも同じ問題があったことが目に留まった。
比較的小さい入力に対しては isqrt の内部で浮動小数点数の sqrt を利用して高速化しているため、結果的にずれる可能性があるらしい。(十分に小さい入力であれば大丈夫)
Ruby のソースコードは確認できていないが、実際に誤った値を返す場合があることはわかった。エッジケースとして狙い撃ちされたら死ぬので、当面は Integer.sqrt を過信しないように注意する必要がある。