質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

6710閲覧

time.perf_counter()の最大値と最小値はなんですか?

takey

総合スコア312

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2017/02/14 04:30

編集2017/02/16 01:04

Raspbian Jessieでpython3.4.2を使用しています。

タイムアウト秒経過したら処理を抜けるプログラムを書いています。

python

1import time 2 3elapsed_sec = 0.0 4pre_time = time.perf_counter() 5 6while elapsed_sec <= timeout_sec: 7 (処理) 8 now_time = time.perf_counter() 9 elapsed_sec += now_time - pre_time 10 pre_time = now_time

このプログラムは、time.perf_counter()がオーバーフローしたら意図しない動作をしてしまいます。
time.perf_counter()の最大値を知りたい(というか、とりうる値の範囲を知りたい)のですが、どうすればいいでしょうか?

[追記1]
回答より、想像以上に早くオーバーフローしそうだということで、1分ごとのtime.perf_counter()の値をperf_counter.historyファイルに保存するコードを書きました。

python

1#-*- coding:utf-8 -*- 2import time 3import datetime 4 5while 1: 6 time.sleep(60) 7 d = datetime.datetime.now() 8 timestamp = "{}:{}:{}".format(d.hour, d.minute, d.second) 9 perf_c = str( time.perf_counter() ) 10 text = "[{}]{}\r\n".format(timestamp, perf_c) 11 12 f = open("/var/tmp/perf_counter.history", "a") 13 f.write( text ) 14 f.close()

↓perf_counter.history

[17:19:6]5345.205548377 [17:20:6]5405.256627527 [17:21:6]5465.262088711 [17:22:6]5525.313487511 ... (略) ... [8:40:40]60639.65602925 [8:41:40]60699.664641323 [8:42:40]60759.669727713

ファイルを眺めた所、オーバーフローはしていませんでした。
そもそもtime.perf_counter()の型は何?と思い調べた所、float型でした。

>>> import time >>> type( time.perf_counter() ) <class 'float'>

float型ということは、オーバーフローした後はマイナスの値を取る可能性があります。
ここで、pythonのfloat型の範囲がわからなかったので調べた所、次のサイトにヒントが書いてありました。
文系のための「数値型」(2)

さて、次に実際の「有効桁数」と「精度」について見てみる。

Python の数値型は、C言語の数値型を借用していることはすでに述べた。
では、C言語のどの型を借用しているのか?
int ← C言語のlong型
long ← C言語には無い?
float ← C言語におけるdouble型
なんと、C言語のデータ型の大きい方だけを使っているようである。

pythonのfloat型はどうやらdouble型だそうです。

混乱してきたので整理すると、
time.perf_counter()は
・float型の数値を返す
・pythonのfloat型はC言語のdouble型に当たる
・ということは、値の範囲は-2^308~2^308(間違ってたらすみません)

time.perf_counter()のオーバーフロー後の動作が気になりますが、とりあえず「タイムアウト秒経過したら処理を抜ける」コードは次のように変更することで問題を回避できそうです。

python

1import time 2 3elapsed_sec = 0.0 4pre_time = time.perf_counter() 5 6while elapsed_sec <= timeout_sec: 7 (処理) 8 now_time = time.perf_counter() 9 if now_time > pre_time: 10 elapsed_sec += now_time - pre_time 11 pre_time = now_time

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

まずtime.perf_counter()を確認したところ

パフォーマンスカウンターの値 (小数点以下がミリ秒) を返します。クロックは短期間の計測が行えるよう、可能な限り高い分解能をもちます。これにはスリープ中の経過時間も含まれ、システム全体で一意です。

のみで、明確な値の範囲は記載されていませんでした。

しかしtime.clock() によれば

Unix では、現在のプロセッサー時間秒を浮動小数点数で返します。時刻の精度および “プロセッサー時間” の定義そのものは同じ名前の C 関数に依存します。
バージョン 3.3 で撤廃: この関数の挙動はプラットフォームに依存します: 必要に応じて挙動が明確に定義されている perf_counter() または process_time() を使用してください。

とのことなので、perf_counter()もC言語のclock関数と同じ動作と推測してみました。

そこでLinux Programmer's Manual (3) CLOCKを確認すると

C89, C99, POSIX.1-2001. POSIX は実際の精度にはよらず CLOCKS_PER_SEC が 1000000 であることを要求している。

時刻は桁あふれする可能性がある点に注意すること。 CLOCKS_PER_SEC が 1000000 である 32 ビットシステムでは、 この関数は約 72 分毎に同じ値を返すことになる。

との記載がありました。意外と短い時間でオーバーフローしそうです。

よって、高い分解能が不要であれば、datetime.nowを代わりに利用することも検討してもよいかと思います。

投稿2017/02/15 05:44

編集2017/02/15 05:45
can110

総合スコア38233

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takey

2017/02/15 07:42

回答ありがとうございます。 >意外と短い時間でオーバーフローしそうです。 実機で試してみようと思います。それからdatetime.now()の検討をしてみます。
can110

2017/02/16 01:35

追記について補足です。 C言語のCLOCKの説明では、カウンター変数は、符号なし32bit整数で保持している例で説明されているようです。 この場合、カウンター変数の最大 = 2^32(約4億) [clock] なので 2^32[clock] / 1000000[clock/sec] = 4294[sec] = 72[min] となり でオーバーフロー(その後はまた0からカウントされる)ということになります。 このカウンター値の最大が約4億であれば、戻り値の型がfloatであっても、それ以上の値が返ることはないです。 また、対応方法としては追記分でよいかと思います。 厳密にいえばカウンター値が最大→最小に変わった1区間分だけ、経過時間は少なくなりますが。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問