HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2008
1114
ペロ制限時間について15解決


ペロ

リンク

2008/11/14(Fri) 22:53:44|NO.20784

制限時間を設けて課題を行うスクリプトを書いているのですが、
課題全体の制限時間を、


*TIME1 start.time = 0 jie=gettime(4) hune=gettime(5) byoue=gettime(6) mirie=gettime(7) start.time= (hune*60000)+(byoue*1000)+mirie return *TIME2 jie=gettime(4) hune=gettime(5) byoue=gettime(6) mirie=gettime(7) now.time= (hune*60000)+(byoue*1000)+mirie if now.time-start.time>120*1000: gosub *owari return
とやると、あるタイミングで開始したときに、永久に待機状態になって
制限時間内に終わらないという話が以前掲示板に書かれていたのですが、
そうならないようにする対処法はありますか。

自分で書き直そうとしたのですが、うまくいかなかったので、
上述したスクリプトのままでも、永久に終わらないという事態にならない
ようにするやり方がありましたら教えてください。



この記事に返信する


check

リンク

2008/11/14(Fri) 23:08:59|NO.20785

gettimeでの判定する項目を増やして年まで判定するとか、
あとは Windowsが起動してからの経過時間で調べるとか。
永久に終わらないという保証はないが、ほとんど大丈夫だろう。



SYAM

リンク

2008/11/15(Sat) 00:13:03|NO.20786

年単位にしたところで、1年に1度 大晦日〜元日をまたいだらアウトです。
すんごいレアケースではありますが…。
なので、Windows起動からの経過時間を使うのが正しいと思います。


または、制限時間の長さによって秒→分→時→…の繰り上がり分を切り捨てて考えます。

制限時間が秒単位で、
制限時間が1秒以上60秒未満であれば
終了予定時刻の「秒」が60以上になったら時刻の数値から60を引けばよいです。

制限時間が1分以上60分未満であれば、
終了予定時刻の「分+秒」が3600秒以上になったら3600を引けばよいです。


実例だと

時刻「?時?分35秒」 から制限時間30秒とすると、

35+30=65ですから60を引いて5です.

なので、次に時刻が?時?分05秒になった時に、制限時間が経過したことになります。


また、
時刻「?時50分45秒」 から制限時間900秒(15分) とすると、

59×60+45+900=3945ですから 3600を引いて345.

次に時刻「?時5分45秒」 になった時に、制限時間が経過したことになります。



GENKI

リンク

2008/11/15(Sat) 01:11:17|NO.20787

最近、gettimeの質問をよく見る気がするのですが、気のせいでしょうか…。
http://hsp.tv/play/pforum.php?mode=all&num=20351

> 年単位にしたところで、1年に1度 大晦日〜元日をまたいだらアウトです。

新年迎える瞬間に何をやっているんでしょう。w
そういう意味でもレアさが増しますね。

http://hspdev-wiki.net/?%BE%AE%A5%EF%A5%B6%2F%A5%B9%A5%C8%A5%C3%A5%D7%A5%A6%A5%A9%A5%C3%A5%C1


#include "d3m.hsp" start = d3timer() button "押す", *bpush stop *bpush mes "起動からの経過時間:" + (double(d3timer()-start)/1000) + " sec" stop



ANTARES

リンク

2008/11/15(Sat) 01:28:34|NO.20788

>時刻「?時50分45秒」 から制限時間900秒(15分) とすると、
>59×60+45+900=3945ですから 3600を引いて345.
 これじゃダメでは? gettimeの引数を2種類以上使っちゃダメ。
それがわかってないとすると、何を問題にしているのか私にはわからないので、
以下の質問の答を教えてください。

>年単位にしたところで、1年に1度 大晦日〜元日をまたいだらアウトです。
 どうしてですか?


本題の答
 結論としては、GetTickCountとかtimeGetTimeとか、何らかのWin32APIを
使う必要があるということになります。
 gettimeを使った場合の問題は、例えば秒と分を取得した場合、
2つの時点の年月日時分の値が同じとは限らないということ。
もし、異なっていれば、秒数やミリ秒数を計算しても意味がありません。

 さっきまで、以下のスクリプトでOKと思っていましたが、これでは
1分未満の誤差が出てしまいます。これはとうてい許せる誤差ではありません。

 制限時間が秒単位の場合のスクリプトを以前、投稿しましたが、
そのスクリプトでは1秒未満の誤差が出てしまいます。
これを許せる誤差とするかどうかは微妙。

 制限時間がミリ秒単位の場合は1ミリ秒未満の誤差が出てしまいますが、
これはWindowsの時間計測の誤差を下回っているので、許せる誤差でしょう。

 結論としては、レアケースも考慮するなら、1分以上の制限時間を
gettimeで計ってはいけないということです。


*TIME1 start.time=gettime(5) return *TIME2 now.time=gettime(5) if (now.time-start.time+60)\60>2: gosub *owari return



SYAM

リンク

2008/11/15(Sat) 01:38:13|NO.20789

>>年単位にしたところで、1年に1度 大晦日〜元日をまたいだらアウトです。
>どうしてですか?

すいません、おもいっきり考え違いしました orz
大丈夫ですね・・・。



ANTARES

リンク

2008/11/15(Sat) 01:41:27|NO.20790

 GetLocalTimeでもかまいません。
上記のような欠陥のある関数はHSP以外には、まずあり得ないので。



SYAM

リンク

2008/11/15(Sat) 01:47:52|NO.20791

>>59×60+45+900=3945ですから 3600を引いて345.
>これじゃダメでは? gettimeの引数を2種類以上使っちゃダメ。

こちらは大丈夫で、
345秒→5分45秒(割り算と剰余で)ですから、以後、gettimeの分と秒がこれと一致した時点で制限時間いっぱいとなります。
誤差の問題はそっくり残りますし、たしかにあんまりイイ方法でもないですが。。。



ANTARES

リンク

2008/11/15(Sat) 02:40:29|NO.20792

>>>59×60+45+900=3945ですから 3600を引いて345.
>>これじゃダメでは? gettimeの引数を2種類以上使っちゃダメ。
>
>こちらは大丈夫で、
>345秒→5分45秒(割り算と剰余で)ですから、以後、gettimeの分と秒が
>これと一致した時点で制限時間いっぱいとなります。
 引用すべき部分を間違いました。

>時刻「?時50分45秒」 から制限時間900秒(15分) とすると、
 50分45秒なら確かに問題ありません。しかし、秒を先に取得するなら、50分59秒の場合、
実は49分59秒(または50分0秒)である可能性があり、分を先に取得するなら、
50分0秒の場合、実は51分0秒(または50分59秒)である可能性があります。
つまり、取得した分と秒の組み合わせが信用できないので、
どんな計算をしても無意味です。


> GetLocalTimeでもかまいません。
 いろいろ書いても全部調べるのは時間の無駄ですね。
時間を計る場合は、timeGetTimeがお勧めですが、GENKIさんが書いている
d3timerの実体はtimeGetTimeなので、d3timerがいちばん使いやすいということになります。



ANTARES

リンク

2008/11/15(Sat) 03:04:37|NO.20793

>あるタイミングで開始したときに、永久に待機状態になって制限時間内に終わらない
 ほんとうかどうか疑問を持ちつつ、めんどくさいので検討していませんが、
誰か詳細に検討して、ものぐさな私に教えてくれませんか?



ANTARES

リンク

2008/11/15(Sat) 05:25:25|NO.20794

> 結論としては、レアケースも考慮するなら、1分以上の制限時間を
>gettimeで計ってはいけないということです。
 これも間違いでした(^_^;;
でも、複雑になるので、d3timerを使う方がいいと思います。

*TIME1 gosub *l_gettime start.time=(min*60+sec)*1000+ms return *TIME2 gosub *l_gettime now.time=(min*60+sec)*1000+ms diff=now.time-start.time if diff<0: diff+=3600000 if diff>120000: gosub *owari return *l_gettime min=gettime(5) ;このときの分・秒・ミリ秒を分1・秒1・ミリ秒1とする sec=gettime(6) ;このときの分・秒・ミリ秒を分2・秒2・ミリ秒2とする if sec==0 { ;sec(秒2)が0なら、秒1は59かもしれないので、minを取得し直す min=gettime(5) ;このときの分・秒・ミリ秒を分3・秒3・ミリ秒3とする } ms=gettime(7) ;このときの分・秒・ミリ秒を分4・秒4・ミリ秒4とする if ms==0 { ;ms(ミリ秒4)が0ならミリ秒1やミリ秒2は999かもしれないので、minとsecを取得し直す min=gettime(5) ;このときの分・秒・ミリ秒を分5・秒5・ミリ秒5とする sec=gettime(6) ;このときの分・秒・ミリ秒を分6・秒6・ミリ秒6とする ;sec(秒6)が0だった場合でも、秒5は59ではないので、minを取得し直す必要はない ;証明 ;もし秒5が59で秒6が0なら、ミリ秒5は999以下で999に近い値のはずだから、 ;その直前のミリ秒4(=ms)が0のはずがない ;secだけでなく、minも取り直す必要がある ;証明 ;ミリ秒2が999で秒2が59というのはありうることで、その場合、ミリ秒4が0だから ;秒4も0。したがって秒6も0。秒2が59で秒6が0なら、分6は分2より1大きいはず。 ;しかし、秒2が0でなかったので、minは取得し直していず、分2のまま } return



ANTARES

リンク

2008/11/15(Sat) 06:28:17|NO.20795

>>あるタイミングで開始したときに、永久に待機状態になって制限時間内に終わらない
> ほんとうかどうか疑問を持ちつつ、めんどくさいので検討していませんが、
>誰か詳細に検討して、ものぐさな私に教えてくれませんか?
 そうか、23時58分1ミリ秒以降に開始したら差が2分以上になることは
あり得ないというだけのことだったのね。



SYAM

リンク

2008/11/15(Sat) 08:56:03|NO.20799

多分ペロさんが見たであろうスレッドでも書いたんですが、

あるコンピュータウイルスは、感染してから破壊活動を始めるまで1ヶ月待機するようプログラムされてました
が、活動開始予定時刻を 感染した月+1 なんてことにしたため、
12月に感染した場合には、ひたすら永遠に来るはずのない13月を待っていた

…っていう話です。
なので年まで数えてたら問題が起きるのは…いつなんだろ。


#そして最初に書いた式のうち59×69+45+900=3945も間違いでした。あかん私…。
#どっから出てきたんだ59ってorz



ペロ

リンク

2008/11/15(Sat) 20:50:09|NO.20811

皆さん、たくさんのご回答ありがとうございます。
d3timerを使って、やってみようと思います。

まだ全然初心者なのですが、gettimeについて、少し分かって
きた気がします。
ありがとうございました!



ANTARES

リンク

2008/11/16(Sun) 05:16:25|NO.20816

>なので年まで数えてたら問題が起きるのは…いつなんだろ。
 オーバーフローがないものと仮定するなら、
言い換えると、HSPの整数型変数が無限の容量を持つと仮定するなら
問題が起きることはありません。
 もし、将来、年の上の単位ができて、1万年ごとに1年から始める
なんてことになったら、そのときに問題が起きます。



naznyark

リンク

2008/11/16(Sun) 21:38:26|NO.20829

gettimeを使った信頼性の高い時間の取得方法ならこんなので良いでしょう。
(アルゴリズム的には安定動作のための前提条件がありますが
HSPで動かす分には問題ないでしょう。)

#module #deffunc gettime_a array p1, local p2, local f_ dim p1, 8 dim p2, 8 repeat repeat 8 : p1(cnt) = gettime( cnt ) : loop repeat 8 : p2(cnt) = gettime( cnt ) : loop f_ = 1 repeat 8 : if ( p1(cnt) != p2(cnt) ) { f_ = 0 : break } : loop if ( f_ ) { break } loop return #global gettime_a tm start_time = tm(5) * 60000 + tm(6) * 1000 + tm(7) mes start_time



ONION software Copyright 1997-2021(c) All rights reserved.