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

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

ただいまの
回答率

90.54%

  • Python 3.x

    9420questions

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

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

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,848

takey

score 277

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

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

import time

elapsed_sec = 0.0
pre_time    = time.perf_counter()

while elapsed_sec <= timeout_sec:
  (処理)
  now_time     = time.perf_counter()
  elapsed_sec += now_time - pre_time
  pre_time     = now_time


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

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

#-*- coding:utf-8 -*-
import time
import datetime

while 1:
  time.sleep(60)
  d = datetime.datetime.now()
  timestamp = "{}:{}:{}".format(d.hour, d.minute, d.second)
  perf_c    = str( time.perf_counter() )
  text      = "[{}]{}\r\n".format(timestamp, perf_c)

  f = open("/var/tmp/perf_counter.history", "a")
  f.write( text )
  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()のオーバーフロー後の動作が気になりますが、とりあえず「タイムアウト秒経過したら処理を抜ける」コードは次のように変更することで問題を回避できそうです。

import time

elapsed_sec = 0.0
pre_time    = time.perf_counter()

while elapsed_sec <= timeout_sec:
  (処理)
  now_time     = time.perf_counter()
  if now_time > pre_time:
    elapsed_sec += now_time - pre_time
  pre_time     = now_time
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

まず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 16:42

    回答ありがとうございます。

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

    キャンセル

  • 2017/02/16 10:35

    追記について補足です。
    C言語のCLOCKの説明では、カウンター変数は、符号なし32bit整数で保持している例で説明されているようです。
    この場合、カウンター変数の最大 = 2^32(約4億) [clock] なので
    2^32[clock] / 1000000[clock/sec] = 4294[sec] = 72[min] となり
    でオーバーフロー(その後はまた0からカウントされる)ということになります。
    このカウンター値の最大が約4億であれば、戻り値の型がfloatであっても、それ以上の値が返ることはないです。

    また、対応方法としては追記分でよいかと思います。
    厳密にいえばカウンター値が最大→最小に変わった1区間分だけ、経過時間は少なくなりますが。

    キャンセル

同じタグがついた質問を見る

  • Python 3.x

    9420questions

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