科学と家事とプログラミング (python を中心に)

python 温度計測 湿度計測 DS18B20 USB9097

時刻を秒の少数まで表示するのは、ちょっと難しいんです

時刻表示の落とし穴

天文や宇宙関連のプログラムを作っていると、時刻表示で落とし穴にはまることがありますね。 例えば、秒の少数1桁まで表示したいのだけど、四捨五入されて秒が 60.0 になってしまったり...

>>> "%02d:%02d:%04.1f" % (23, 59, 59.95)
'23:59:60.0'

事前に四捨五入をチェックすれば大丈夫か ?

ありがちな対応策は、事前に四捨五入をチェックすることかと思います。 こんなコードでしょうか

if s >= 59.95:
    s = int(s) + 1 # 少数以下を切り捨てて 1 秒追加
    # 必用に応じて、繰り上がりを上位に伝搬してから文字列表現を編集...

これで、回避できそうですが、計算機誤差(計算機ε)を考慮すると 59.95 のまるめ誤差も気になります。 たとえば(?) 、少数 3 桁の時は、繰り上がりがなかったりして、ちょっと不安になります。

>>> "%02d:%02d:%06.3f" %(23,59,59.9995)
'23:59:59.999'

まるめ誤差はやっかいですね。

やってみて、だめならやり直す!

こういう時は、実際に文字列を作ってみて、繰り上がったかどうかを調べるのも一つの方法です。

if float('%4.1f' % s) >= 60:
    s = int(s) + 1 # 少数以下を切り捨てて 1 秒追加
    # 必用に応じて、繰り上がりを上位に伝搬してから文字列表現を編集...

試しに文字列を作るのは無駄が多い感じもしますが ^^; やりたいこと(文字列変換の四捨五入が発生するかどうかで場合分けしたい)を直接表現したコードに見えてきませんか?処理系が有する書式変換の細かな仕様を気にする必要もない。 少なくとも、検証の観点から有利な設計と思います。

落穂ひろい

繰り上げが発生した場合は、必用に応じて 分,時,日,月,年 まで上位に繰り上げ を伝搬しないといけません(うるう年の判定も必要)と、時刻の印字は、なかなか、奥が深いですね。 秒の少数以下を表現できるライブラリがあれば、それを使った方が良いけれど、 うるう秒の補正や表示(60.0~60.999...)まで対応したものはなさそう。 自前で実装する場合は、秒の整数部と少数部を完全に分離して管理することをお勧めします。 以上、時刻の表示は、秒の少数の表示上の繰り上がりが年にまでおよぶ可能性がある。 ということで、ちょっと難しいんです。