シンプルなストップウォッチを実装する


25

チャレンジ

あなたの仕事は、プログラムを作成することです。プログラムは、1秒に1回(プログラムの開始時を含む)、プログラムが開始されてからの経過時間を出力します。

ルール

  • 時間はhh:mm:ss形式で印刷する必要があります。(1桁の値の場合は先行ゼロ)
  • タイムスタンプは、CR、LF、またはCRLFで区切る必要があります。(先頭に空白がない)
  • 毎秒新しい時間が表示されなければなりません。(stdoutは1秒間バッファリングできません)
  • 23:59:59を過ぎて実行された場合のプログラムの動作は未定義です。
  • sleep(1)印刷、計算、ループなどのオーバーヘッドが1秒に累積するたびに特定の1秒がスキップされる場合でも使用できます。

出力例:

00:00:00
00:00:01
00:00:02
00:00:04
00:00:05
⋮

00:00:03処理のオーバーヘッドのためにここにないことに注意してください。実際にスキップされた値(もしあれば)は、もちろん実装やシステムに依存します。

Cでの参照実装:(POSIX互換システムのみ)

#include <unistd.h> // sleep()
#include <tgmath.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

#ifndef __STDC_IEC_559__
#error "unsupported double"
#endif
static_assert(sizeof(double) == 8, "double must have double precision");
#define MAX_PRECISE_DOUBLE ((double)(1ULL << 52))

int main(void) {
    time_t start = time(NULL);
    if (start == (time_t)-1) return EXIT_FAILURE;
    while (1) {
        time_t now = time(NULL);
        if (now == (time_t)-1) return EXIT_FAILURE;

        double diff = difftime(now, start);
        if (isnan(diff) || diff < 0) return EXIT_FAILURE;
        if (diff > MAX_PRECISE_DOUBLE) return EXIT_FAILURE;

        unsigned long long seconds = diff;
        unsigned long long h = seconds / 3600;
        seconds %= 3600;
        unsigned long long m = seconds / 60;
        seconds %= 60;
        unsigned long long s = seconds;

        (void)printf("\r%02llu:%02llu:%02llu", h, m, s);
        (void)fflush(stdout);

        (void)sleep(1);
    }
}

受賞基準

これは、バイト単位の最短コードが勝ちです!


後の課題に注意してください、コメントの明確化は悪いことです。参照
user202729

回答:


9

MATL17 16バイト

`Z`12L/13XOD1Y.T

MATL Online試しください

使い方

`         % Do...while loop
  Z`      %   Push seconds elapsed since start of program
  12L     %   Push 86400 (predefined literal)
  /       %   Divide. This transforms seconds into days
  13XO    %   Convert to date string with format 13, which is 'HH:MM:SS'
  D       %   Display
  1Y.     %   Pause for 1 second
  T       %   True. Used as loop condition for infinite loop
          % End loop (implicit)

4
それが閉じられてから37分後に、あなたはどのように答えましたか?O_Oはキャッシング非難
氏Xcoder

9
@ Mr.Xcoder最近、フォースの使用を学びました
ルイスメンドー

29

操作Flashpointスクリプト言語、 174  171バイト

s=""
#l
t=_time
t=t-t%1
a=t%60
c=(t-a)/60
b=c%60
c=(c-b)/60
d=""
e=d
f=d
?a<10:d=0
?b<10:e=0
?c<10:f=0
s=s+format["%1%2:%3%4:%5%6\n",f,c,e,b,d,a]
hint s
@t+1<_time
goto"l"

動作中:

158バイト、前回が次回までに上書きされる場合:

#l
t=_time
t=t-t%1
a=t%60
c=(t-a)/60
b=c%60
c=(c-b)/60
d=""
e=d
f=d
?a<10:d=0
?b<10:e=0
?c<10:f=0
hint format["%1%2:%3%4:%5%6",f,c,e,b,d,a]
@t+1<_time
goto"l"

技術的には、キャリッジリターンは使用されないため、このバージョンが規則に限定されるかどうかはわかりません。


5
操作の引火点を期待していませんでした。
Polyducks

10
@Polyducks誰を期待動作引火点
Pureferret


UNIXでは、CRはラインが上書きされますので、私は2番目の答えが「許可されているいずれかのCR、LF、あるいはCRLF」で検証されると思う
スタン・ストラムを

1
@StanStrum少なくとも私のUbuntuではCR行を上書きしません。実際には、CRLFLFCRおよびLFすべての意味的に等価です。

13

Bash + coreutils、28 26バイト

date -s0|yes date +c%T|sh

間の印刷できない文字+%あるESCのバイト。

これにより、システム時刻が00:00:00に設定されるため、ルート権限が必要になります。また、タイムゾーンはUTCであり、他のプロセスがシステムクロックに干渉しないことを前提としています。

新しいタイミングごとに端末がリセットされるため、前の端末が上書きされます。


Bash + coreutils、38 29バイト

date -s0|yes date +%T|sh|uniq

前と同じ制限が適用されます。新しいタイミングはそれぞれ新しい行に表示されます。


バイトカウントは変更されないので、最初dateの行を残りの行から分離するには、素敵な小さな改行を使用します。しかし、誰かがあなたの2番目の解決策のようなものを思い付くにはあまりにもいいかもしれません> :
アーロン

date -s0新しい時間をSTDOUTに出力します。パイプを使用して、その出力を抑制しています。
デニス

ああ、説明ありがとう!
アーロン

5

APL(Dyalog Unicode)、51バイト

完全なプログラム本体。

s←⎕AI
1↓∊':'@1∘⍕¨100+30 60 60 1E33⊃⎕AI-s
DL 1
2

オンラインでお試しください!(Ctrl + Enterを押して開始し、もう一度押して停止します。)

⎕AICCOUNTのIの nformation(ユーザーID、計算時間、接続時間、キーイング時間)

s← に代入ssタルト時間)から
⎕AI-s 減算s⎕AI

3⊃ 第三の要素(ミリ秒接続時間)ピック
0 60 60 1E3⊤この混合基数に変換する
3↑ (ミリ秒滴)最初の3を取る
100+ 百は、(パッドゼロに)それぞれに加え
':'@1∘⍕¨ それぞれの文字列表現の最初の文字にコロンを修正
ε nlist(平坦化)
1↓ 最初のコロンをドロップ(および暗黙的にstdoutに出力)

⎕DL 1Dの E のL AY一秒

→2 行番号2に移動します


5

R59 44バイト

FRのデフォルトはFALSEですが、通常の変数であり、再定義できます。算術で使用される場合、FALSEに強制され0ます。F+1したがってを求めると戻ります1。に割り当てF、適切F+1にフォーマットし、印刷して、1秒間待機します。無期限に続きます。

repeat{print(hms::hms(F<-F+1))
Sys.sleep(1)}

TIOでは機能しません(hmsパッケージがないため)が、ここに私のマシンからの出力例を示します:

00:00:00
00:00:01
00:00:02
00:00:03
00:00:04
00:00:05
00:00:06
00:00:07
00:00:08
00:00:09
00:00:10
00:00:11
00:00:12
00:00:13

5

bash + sleep + date、また50 49 47 46 45 41バイト

while date -ud@$[s++] +%T;do sleep 1;done

ラップタイムを取るには、すばやく^ Cを押して、これを実行してから上記を再実行します。

laps=("${laps[@]}" $s) ; echo ${laps[-1]}

リセットするには:

s=0; unset laps

$ [s ++]構文はまだ機能しているように見えますが、bashマニュアルページには文書化されていません(AFAICS)。また、引用符を削除すると、for((...))ループを使用するよりも1バイト短くなります。


AFAICT $[]は、非推奨/文書化されていませんが、まだサポートされている形式です$(())。コードとゴルフの回答で一般的に使用されるかどうかはわかりませんが、一般的な規則は、コードは少なくとも1つのバージョンのインタープリターで使用する必要があるということです。IMOそれは大丈夫です。
ピーターコーデス

s=0算術置換は未設定の変数を0として扱うため、必須ではありません。-uデフォルトのタイムゾーン(UTC)を想定している場合も必要ありません。
デニス

私のマシンでは-uが必要です:)
ウィルフォードは

4

Swift、144バイト

import Foundation
let s=Date()
while 1>0{let d=Int(-s.timeIntervalSinceNow)
print(String(format:"%02d:%02d:%02d",d/3600,d/60%60,d%60))
sleep(1)}

説明

import Foundation                       // Import `Date` and `sleep()`
let s = Date()                          // Get the time at the start of the program
while 1 > 0 {                           // While 1 > 0 (forever):
  let d = Int(-s.timeIntervalSinceNow)  //   Calculate time difference
  print(String(format:"%02d:%02d:%02d", //   Print the time
      d/3600,d/60%60,d%60))
  sleep(1)                              //   Sleep one second
}

4

JavaScript(ES6)、99バイト

f=_=>console.log(new Date(new Date-d).toUTCString().slice(17,25))
f(d=Date.now(setInterval(f,1e3)))


2
私にとって時間は0から始まりません。オフセットは、システムクロックのタイムゾーンに応じて変わります。(Win10)
ルーク

@LukeSおっと、修正!
darrylyeo

4

Matlab(R2016b)、50バイト

t=now;while 1,disp(datestr(now-t,13)),pause(1),end

説明:

t=now; % Stores the current time
while 1 % Loops forever
    disp(datestr(now-t,13)) % Computes the difference since the program started
    % And prints with format 13 ('HH:MM:SS') - this may change between versions
    pause(1) % Waits one second
end

代替バージョン(50バイトも:P):

now;while 1,disp(datestr(now-ans,13)),pause(1),end

サイトへようこそ!:)
DJMcMayhem

おかげで仲間:)
チアゴオレニック

@LuisMendo提案をありがとう、しかし私は理解しませんでした...あなたの例では、変数は何tですか?また、への入力datestrは日86400単位であるため、で除算する必要があります。これにより、バイトカウントが2ずつ増加します。
Thiago Oleinik

3

ジュリア0.675の 68バイト

for h=0:23,m=0:59,s=0:59;@printf "%02i:%02i:%02i
" h m s;sleep(1)end

オンラインでお試しください!

sleep(1)が許可されると、単純なネストされたforループは、Juliasの組み込み時間処理メソッドを使用するよりも短くなります。

DateTimeを使用したsleep(1)なしの古いソリューション

t=now()-DateTime(0);Timer(x->println(Dates.format(now()-t,"HH:MM:SS")),0,1)

t「0日目」からプログラムが開始されるまでに経過した時間です。 now()-t瞬間であり、それを使ってフォーマットされDates.format()ます。

t0=now(); ...; now()-t0時間差をもたらすでしょう、それはと共に使用できませんDates.format()

タイミング自体はbuild-inで簡単Timerです。


3

Python 2、85バイト

import time
t=0
while 1:print(":%02d"*3)[1:]%(t/3600,t/60%60,t%60);time.sleep(1);t+=1

クレジット


あなたは置き換えることにより、1つのバイトを保存することができ"%02d:%02d:%02d"(":%02d"*3)[1:]
wnnmaw

1
あなたは必要としない%24行動をした後に定義されていません、23:59:59
エリックアウトゴルファー

@EriktheOutgolfer良い点、更新。
ニール

3

JavaScript(ES6)、88バイト

f=_=>console.log(new Date(i++*1e3).toUTCString().slice(17,25))
f(i=0,setInterval(f,1e3))

基本的に@darrylyeoの回答と同じアプローチですが、すべてのタイムゾーンで機能し、わずかに異なる方法で0に到達します。

[編集]ダリルの答えは修正されました。ただし、これはまだ短いです。


3

> <>、82 + 7 = 89バイト

0\!
:/+1oan~?=3ln?$0(a:o":"n~?=4ln?$0(a:ro":"n~?=5ln?$0(a:,*a6-}:%*a6:,*a6-}:%*a6:

オンラインでお試しください!

フラグ-t.0125を使用して各命令に1/80秒かかるための+7バイト。各ループには80の命令があり、各ループの長さは1秒になります。計算時間のため、実際にはこれは実際には長くなります。

私は実際にこれを100までバッファリングしなければならなかったので、@ Not A Treeの答えは私のものよりも7バイト優れた方法で時間と分を生成し、それを80未満にトリミングし\/ました。ループごと。

使い方

0\...
./...
Initialises the stack with a 0 to represent the time

0\!
:/....................................................,*a6-}:%*a6:,*a6-}:%*a6:
Puts the hours, minutes and seconds in the stack

0\!
:/....n~?=3ln?$0(a:o":"n~?=4ln?$0(a:ro":"n~?=5ln?$0(a:...
Print out the hours, minutes, seconds separated by colons. 
If the number is below 0, print a leading 0. 
If the number is not, then there is an extra 0 on the stack, which is popped.

0\!
./+1oa...
Print a newline and increment the counter
And restart the loop

ボーナス:

同じサイズの1行バージョン、80 + 9バイト:

0::6a*%:}-6a*,:6a*%:}-6a*,:a(0$?nl5=?~n":"or:a(0$?nl4=?~n":"o:a(0$?nl3=?~nao1+>!

これは、-aフラグを使用して、スキップされた命令のティックを追加します。


3

PHP 4以降、 70 64バイト

$x=time();while(1){sleep(1);echo date('H:i:s',time()-$x)."\n";}

PHP 5.3以降、 69 63バイト

$x=time();a:sleep(1);echo date('H:i:s',time()-$x)."\n";goto a;

PHPのオープンタグは、6バイトを節約する回答で省略できます。
ダニエルW.

2

Python 3、112バイト

1秒の遅延を使用することは(まれに)1秒をスキップする場合でも問題ありません。

from time import*;a=0
while 1:d=divmod;m,s=d(a,60);print(":".join(f"{k:02d}"for k in(*d(m,60),s)));a+=1;sleep(1)

2

VBA、90

t=0:while(1):?format(t,"hh:mm:ss"):t=t+timeserial(0,0,1):q=timer:while q-timer<1:wend:wend

イミディエイトウィンドウで実行:約2,300万年の予想される障害ポイント(浮動小数点の解決は〜8.5e9日間失敗)



2

AWK110 87 86バイト

BEGIN{for(;;i++){printf("%02d:%02d:%02d\n",i/3600%60,i/60%60,i%60);system("sleep 1")}}

TIOでは機能しません。


プログラムは00:00:00、開始時に印刷されないようです。
user202729

それを修正しました。おかげで
Noskcaj


2

Bash + coreutils + GNU date、50バイト

o=`date +"%s"`;yes date +%X -ud\"-$o sec\"|sh|uniq

@Dennisに触発されたこのソリューションでは、時間を変更する必要はありません。これは、現在からUNIXエポック(1970年1月1日00:00:00 UTC)までの初期オフセットを「o」で保存し、[-udオプション](現在の時間-オフセット)をUTC日付で表示しますが、 [+%Xオプション] HH:MM:SSのみ。これは、現在のタイムゾーンがUTCではない国で機能するはずです。


2

クリーン173の 172 168バイト

import StdEnv,System.Time
$n i#i=(i/60^n)rem 60
=(i/10,i rem 10)
f i w#(Clock j,w)=clock w
#j=j/1000
|j>i=[j:f j w]=f i w
Start w=[($2i,':',$1i,':',$0i,'
')\\i<-f -1 w]

これは、Windows Cleanバンドルでのみ機能します。

Clean CLK_PER_TICK :== 1000000が* nixにあるように、Linuxで動作させたい場合は3バイトを追加します。クロスプラットフォームにしたい場合CLK_PER_TICKは、設定されている値の代わりに使用する必要があるため、代わりに8バイトを追加します。(TIOリンクは上記のために大きい

オンラインでお試しください!


2

Python 2、69 + 3(TZ=)= 72バイト

from time import*;s=time()
while 1:print ctime(time()-s)[11:19]+'\r',

これは、スリープせずに連続ループで実行され、毎秒新しい行を印刷するのではなく、同じ行の時間を更新します。(まだ規則で許可されていると思います。)

この少し長いバージョン(72 + 3 = 75バイト)は、代わりに毎秒新しい行に印刷されます。

from time import*;s=time()
while 1:print ctime(time()-s)[11:19];sleep(1)

どちらの場合も、UTCタイムゾーンにいる必要があります。Linuxでは、TZ環境変数を設定することでこれを実現できます。例えばTZ= python


2

> <>106バイト 82 + 9 = 91バイト

-a旗を提案してくれたジョー・キングに感謝します!彼らの答えもチェックしください。

0v+1oan<n0/
:/<</?(a:,*a6-}:%*a6:,*a6-}:%*a6:\\
n<n0/<</?(a:ro":"
":"n<n0/<</?(a:o

オンラインでお試しください!(ただし、60秒のタイムアウトを待つ必要があります)。

これまでに必要なかった> <>の機能を使用するようになりました。このコードにはflagが必要です。これ-t.0125により、実行速度をティックごとに0.0125秒、または毎秒80ティックに設定できます。-aフラグもあります。これにより、空白がティックとしてカウントされます(場合によっては、インタープリターがこれについて少し奇妙です)。

基本的に、コードは、魚がループを通過するたびに増分されるカウンターを保持し、残りのループはカウンターをhh:mm:ssフォーマットに変換して印刷します。ループはちょうど80ティックかかります。

これは理論上は機能するはずですが、実際には、計算時間のため、各ティックは0.0125秒よりわずかに長くなっています。\\2行目のを変更すると、<<TIOのタイミングがより正確になります。

また、このインタプリタが公式インタプリタとは少し異なる方法で空白を処理することを除いて、fish playgroundで実行中のコードを見ることができます。または、TIOのフラグを削除してコードを最高速度で実行し、1分後の動作を確認できます。


-1バイト、最初の行のvを\!2つの余分な<。バイトの別のカップルは、あなたが使用している場合-a、フラグ、およびダニなどの指示をスキップ空白カウント
ジョー・キングを

@JoKing、-a旗はもう少しゴルフをさせてくれました、ありがとう!\!コードでもこのトリックを使用できると思います:オンラインで試してみてください!
ツリーではない

2

Java 8、フルプログラム、150バイト

interface M{static void main(String[]a)throws Exception{for(int i=0;;Thread.sleep(1000))System.out.printf("%02d:%02d:%02d%n",i/3600,i/60%60,i++%60);}}

ここで試してみてください(60秒後にタイムアウトになるので、より多くの出力を見るためにスリープを1に設定しました)。

説明:

interface M{                    // Program:
  static void main(String[]a)   //  Mandatory main-method
     throws Exception{          //    Mandatory throws for Thread.sleep
    for(int i=0;                //   Start at 0
        ;                       //   Loop indefinitely
         Thread.sleep(1000))    //     After every iteration: Sleep for 1 sec
      System.out.printf("%02d:%02d:%02d%n",
                                //    Print in the format "HH:mm:ss\n":
        i/3600,i/60%60,i++%60); //     The hours, minutes and seconds
                                //     (and increase `i` by 1 afterwards with `i++`)
                                //   End of loop (implicit / single-line body)
  }                             //  End of mandatory main-method
}                               // End of program

Java 8、関数、94バイト

v->{for(int i=0;;Thread.sleep(1000))System.out.printf("%02d:%02d:%02d%n",i/3600,i/60%60,i++%60);}

ここで試してみてください(60秒後にタイムアウトになるので、より多くの出力を見るためにスリープを1に設定しました)。

説明:

v->{   // Method with empty unused parameter and no return-type
  ...  //  Same as the program above
}      // End of method

1000ミリ秒を使用した場合に意図したとおりに動作することを確認するための小さなgifを次に示します。

ここに画像の説明を入力してください


2

PHP、59 48バイト

while(1){sleep(1);echo date('H:i:s',$i++)."\n";}

ダレンHの答えに触発されました。

古いバージョン

<?php while(1){sleep(1);echo date('H:i:s',$i++-3600)."\n";}

PHPのオープンタグは、6バイトを節約する回答で省略できます。
ダニエルW.

素晴らしい考えですが、3600は86400である必要があります。そうしないと、カウンターは23:00:00から始まるので、残念ながら1バイト増えますが、それでも9で勝ちます!
ダレンH

@DarrenHそれはあなたのロケールに依存すると思う、私はそれについて考えていなかった。私はGMT + 1にいるので、3600を追加しましたが、英語の人は-3600完全に削除して5バイト節約できると思います。
roberto06

1

シェル、177バイト

これはdate +%s一般的なdate拡張であるを使用するため、これは完全にPOSIX準拠ではないことに注意してください。

a=`date +%s`;while true;do b=`date +%s`;s=`expr $b - $a`;h=`expr $s / 3600`;s=`expr $s % 3600`;m=`expr $s / 60`;s=`expr $s % 60`;printf '\r%02d:%02d:%02d' $h $m $s;sleep 1;done

7
通常、あなたは自分で答える前に、人々にあなたの挑戦に答える機会を与えるべきです。週の特定の時間にのみここに来る人もいるので、1週間をお勧めします。
アダム

1
@Adám私は自分の答えを受け入れませんでしたが、投稿した時点で、もっと短い答え(あなたのような)が投稿されました。
マークウェスト

1

ルビー、192 117バイト(クレジットからダダ)

t=Time.now
loop do
m,s=(Time.now-t).to_i.divmod(60)
h,m=m.divmod(60)
printf"%02d:%02d:%02d
",h,m,s
sleep 1
end

どのように機能しますか?

拡張バージョンを使用する場合(時間への変換は別の関数として提供され、異なる出力形式を使用します):

def format_secs(s) # Converts the value in seconds to the required format
    mins, secs = s.divmod(60) # divmod returns the quotient and the remainder of a number
    hours, mins = mins.divmod(60)
    [hours,mins,secs].map { |e| e.to_s.rjust(2,'0') }.join ':'

    =begin
    [hours,mins,secs] -Creates a new array using the values allready provided for hours, minutes and seconds
    .map { - Creates a new array based on a operation on each of an array's values
    .to_s.rjust(2,'0')} - Turns the number into a string, and then adds "0" if needed to make the timer's result at least two digits
    .join ':' - Combines the result of the operation into a single string with a ":" in between the two numbers
    =end
end

t = Time.now # Saves the time at the program's (Rough) start

loop do
    puts format_secs((Time.now - t).to_i) # Returns the result of  the "format_secs" operation on the difference between the two times (in seconds) converted to a pure integer
    sleep 1 # Waits for one second
end

6
サイトへようこそ!コードゴルフの挑戦に対するすべての答えはゴルフをしなければなりません。少なくとも不要な空白を削除し、1文字の変数名を使用する必要があります。これにより、約120バイトが得られ、printf代わりにを使用するとputs、さらに数バイト節約できます。オンラインで試してください!。PPCGでハッピーゴルフ!
ダダ

1

APL NARS、109 63 57文字

q;t
t←0
{∊⍵,¨':: '}{1<⍴x←⍕⍵:x⋄'0',x}¨(3⍴60)⊤⌊t+←⎕DL 1⋄→2

3 + 3 + 48 + 3 = 57(他のAplソリューションも見られます)

{1<⍴x←⍕⍵:x⋄'0',x}

文字列の長さが1の場合、その前に「0」を1つ追加する方法で、数字列のINT⍵を変換します

{∊⍵,¨':: '}

⍵の配列を配列 '::'と結合します

00:00:01 
00:00:02 
00:00:03 
00:00:04 
00:00:05 
00:00:06 
00:00:07 
00:00:08 
00:00:09 

1

x86-64マシンコード(Linuxシステムコール):78バイト

RDTSCスピンループタイミング、Linux sys_writeシステムコール。

x86-64は、実行時にRDTSCの「基準クロック」周波数を照会する便利な方法を提供しません。MSR読み取ることができます(それに基づいて計算を行います)が、それにはカーネルモード、またはroot + openingが必要な/dev/cpu/%d/msrので、周波数をビルド時定数にすることにしました。(FREQ_RDTSC必要に応じて調整:32ビット定数はマシンコードのサイズを変更しません)

x86 CPUは数年前からRDTSC周波数を固定していたため、周波数の変更を無効にする手順を実行しない限り、コアクロックサイクルパフォーマンスカウンターではなく、タイムソースとして使用できます。(実際のCPUサイクルをカウントするための実際のperfカウンターがあります。)通常、ターボや省電力に関係なく、i7-6700kの場合は4.0GHzなどの公称ステッカー周波数で作動します。とにかく、このビジー待機のタイミングは負荷平均に依存せず(キャリブレーションされた遅延ループがそうするように)、CPUの節電にも影響されません。

このコードは、2 ^ 32 Hz未満の基準周波数(つまり最大〜4.29 GHz)のすべてのx86で機能します。それを超えると、タイムスタンプの下位32は1秒で完全にラップするためedx、結果の上位32ビットも調べる必要があります。

まとめ

00:00:00\nスタックをプッシュします。次に、ループ内で:

  • sys_write システムコール
  • 1.ラッピング/搬出で処理することにより時間を増分する数字(最後から始まる)を介してADCループcmp/ cmovCF結果は、キャリーインの次の桁のを提供すること、。
  • rdtsc 開始時間を節約します。
  • rdtscデルタがRDTSC周波数の1秒あたりのティック数以上になるまでスピンオンします。

NASMリスト:

 1  Address                            ; mov  %1, %2       ; use this macro to copy 64-bit registers in 2 bytes (no REX prefix)
 2           Machine code           %macro MOVE 2
 3           bytes                      push  %2
 4                                      pop   %1
 5                                  %endmacro
 6                                  
 7                                      ; frequency as a build-time constant because there's no easy way detect it without root + system calls, or kernel mode.
 8                                      FREQ_RDTSC equ 4000000000
 9                                  global _start
10                                  _start:
11 00000000 6A0A                        push     0xa                       ; newline
12 00000002 48BB30303A30303A3030        mov      rbx, "00:00:00"
13 0000000C 53                          push     rbx
14                                      ; rsp points to  `00:00:00\n`
20                                  
21                                      ; rbp = 0                (Linux process startup.  push imm8 / pop is as short as LEA for small constants)
22                                      ; low byte of rbx = '0'
23                                  .print:
24                                      ; edx potentially holds garbage (from rdtsc)
25                                  
26 0000000D 8D4501                      lea      eax, [rbp+1] ; __NR_write = 1
27 00000010 89C7                        mov      edi, eax     ; fd = 1 = stdout
28                                      MOVE     rsi, rsp
28 00000012 54                  <1>  push %2
28 00000013 5E                  <1>  pop %1
29 00000014 8D5008                      lea      edx, [rax-1 + 9]     ; len = 9 bytes.
30 00000017 0F05                        syscall               ; sys_write(1, buf, 9)
31                                  
32                                      ;; increment counter string:  least-significant digits are at high addresses (in printing order)
33 00000019 FD                          std                        ;  so loop backwards from the end, wrapping each digit manually
34 0000001A 488D7E07                    lea      rdi, [rsi+7]
35                                      MOVE     rsi, rdi
35 0000001E 57                  <1>  push %2
35 0000001F 5E                  <1>  pop %1
36                                  
37                                      ;; edx=9 from the system call
38 00000020 83C2FA                      add   edx, -9 + 3      ; edx=3 and set CF (so the low digit of seconds will be incremented by the carry-in)
39                                      ;stc
40                                  .string_increment_60:          ; do {
41 00000023 66B93902                    mov    cx, 0x0200 + '9'    ; saves 1 byte vs. ecx.
42                                      ; cl = '9' = wrap limit for manual carry of low digit.  ch = 2 = digit counter
43                                    .digitpair:
44 00000027 AC                          lodsb
45 00000028 1400                        adc      al, 0           ; carry-in = cmp from previous iteration; other instructions preserve CF
46 0000002A 38C1                        cmp      cl, al          ; manual carry-out + wrapping at '9' or '5'
47 0000002C 0F42C3                      cmovc    eax, ebx        ; bl = '0'.  1B shorter than JNC over a MOV al, '0'
48 0000002F AA                          stosb
49                                  
50 00000030 8D49FC                      lea     ecx, [rcx-4]    ; '9' -> '5' for the tens digit, so we wrap at 59
51 00000033 FECD                        dec     ch
52 00000035 75F0                        jnz    .digitpair
53                                      ; hours wrap from 59 to 00, so the max count is 59:59:59
54                                  
55 00000037 AC                          lodsb                        ; skip the ":" separator
56 00000038 AA                          stosb                        ; and increment rdi by storing the byte back again.  scasb would clobber CF
57                                  
58 00000039 FFCA                        dec     edx
59 0000003B 75E6                        jnz   .string_increment_60
60                                  
61                                      ; busy-wait for 1 second.  Note that time spent printing isn't counted, so error accumulates with a bias in one direction
62 0000003D 0F31                        rdtsc                         ; looking only at the 32-bit low halves works as long as RDTSC freq < 2^32 = ~4.29GHz
63 0000003F 89C1                        mov      ecx, eax             ; ecx = start
64                                  .spinwait:
65                                  ;    pause
66 00000041 0F31                        rdtsc                      ; edx:eax = reference cycles since boot
67 00000043 29C8                        sub      eax, ecx          ; delta = now - start.  This may wrap, but now we have the delta ready for a normal compare
68 00000045 3D00286BEE                  cmp      eax, FREQ_RDTSC   ; } while(delta < counts_per_second)
69                                   ;   cmp      eax, 40  ; fast count to test printing
70 0000004A 72F5                        jb     .spinwait
71                                  
72 0000004C EBBF                        jmp .print
  next address = 0x4E = size = 78 bytes.

pause命令のコメントを外して、電力を大幅に節約します。これにより、1つのコアpauseがなしで〜15℃ だけ加熱されますが、で〜9だけ加熱されpauseます。(Skylake pauseでは、〜5の代わりに〜100サイクルでスリープします。rdtsc低速でもなかった場合、CPUが多くの時間を費やさないので、さらに節約できると思います)。


32ビットバージョンは数バイト短くなります。たとえば、32ビットバージョンを使用して最初の00:00:00 \ n文字列をプッシュします。

16                          ;    mov      ebx, "00:0"
17                          ;    push     rbx
18                          ;    bswap    ebx
19                          ;    mov      dword [rsp+4], ebx    ; in 32-bit mode, mov-imm / push / bswap / push would be 9 bytes vs. 11

また、1バイトを使用しますdec edxint 0x80システムコール対lodsb / stosbのためのレジスタ設定が簡単になるかもしれないので、システムコールABIは、EDI / ESI使用することはありません。


nanosleepシステムコールを使用することもできましたが、これはもっと面白かったです。Linuxのルートでは、適切なMSRを読み取り、プログラムでRDTSC周波数を取得できます。
ピーター

1

q / kdb +、40バイト

溶液:

.z.ts:{-1($)18h$a+:1};a:-1;(.)"\\t 1000"

例:

q).z.ts:{-1($)18h$a+:1};a:-1;(.)"\\t 1000"
q)00:00:00
00:00:01
00:00:02
00:00:03
00:00:04
00:00:05

説明:

ここで実行されている3つのコマンドがあります。

  1. .z.ts:{-1($)18h$a+:1}; / override timer function
  2. a:-1; / initialise variable a to -1
  3. (.)"\\t 1000" / start the timer with 1000ms precision

タイマー機能の内訳:

.z.ts:{-1 string 18h$a+:1} / ungolfed timer function
      {                  } / lambda function
                     a+:1  / add 1 to variable a
                 18h$      / cast to seconds
          string           / cast to string
       -1                  / write to stdout
.z.ts:                     / assign this function to .z.ts

ボーナス:

41バイトの代替1 :

a:.z.t;.z.ts:{-1($)18h$x-a};(.)"\\t 1000"

26 + 7バイトの場合の代替2 = 33バイト

.z.ts:{-1($)18h$a+:1};a:-1

-t 1000引数としてqバイナリに追加します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.