实施简单的秒表


25

挑战

您的任务是编写一个程序,该程序每秒(包括立即在您的程序启动时)每秒打印一次从您的程序启动起经过的时间。

规则

  • 时间必须以hh:mm:ss格式打印。(单位值的前导零)
  • 时间戳记必须用CR,LF或CRLF分隔。(无前导空格)
  • 新的时间必须每秒出现一次。(stdout不能缓冲一秒钟)
  • 如果程序在23:59:59之后运行,其行为是不确定的。
  • sleep(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

Answers:


9

MATL17 16字节

`Z`12L/13XOD1Y.T

MATL在线上尝试一下

怎么运行的

`         % 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先生17年

9
@ Mr.Xcoder我最近学会了使用力量
Luis

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将覆盖该行,我认为第二个答案已通过“允许CR,LF或CRLF验证”
Stan Strum,

1
@StanStrum至少在我的Ubuntu上CR不会覆盖该行。其实CRLFLFCR并且LF都是语义上等同。

13

Bash + coreutils,28个 26字节

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

+和之间的不可打印字符%ESC字节。

这会将系统时间设置为00:00:00,因此需要root特权。它还假定时区为UTC,并且没有其他进程会干扰系统时钟。

每个新的时序都会重置终端,从而覆盖前一个。


Bash + coreutils,38个 29字节

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

与以前相同的限制适用。每个新的时间显示在新的一行上。


由于它不会改变字节数,因此我date用一个很小的换行符将第一个字节与其余字节分开。但是对于能够提出类似您的第二个解决方案的人来说,这可能太好了::-(
Aaron

date -s0将新时间打印到STDOUT;我正在使用管道使该输出静音。
丹尼斯

哦,对了,谢谢您的解释!
亚伦

5

APL(Dyalog Unicode),51字节

完整的程序主体。

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

在线尝试!(按Ctrl + Enter开始,然后再按一次停止。)

⎕AI ccount 载文信息(用户ID,计算时间,连接时间,键控时间)

s← 分配给s(用于小号馅饼时间)
⎕AI-s 中减去s⎕AI

3⊃ 选择第三个元素(连接时间(以毫秒为单位))
0 60 60 1E3⊤转换为此混合基数,
3↑ 将前三个元素(下降毫秒)
100+ 加至每个元素的一百个(填充零)
':'@1∘⍕¨ ,并在每个
ϵ的字符串表示形式的第一个字符处加上冒号nlist(变平)
1↓ 删除第一个冒号(并隐式打印到stdout)

⎕DL 1d Ë AY1秒

→2 转到第二行


5

R59 44字节

FR中的in默认为FALSE,但这是一个常规变量,可以重新定义。用于算术运算时,FALSE被强制为0F+1因此要求退货1。我们将指定FF+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((...))循环短一个字节。


AFAICT $[]是已弃用/未记录但仍受支持的形式$(())。我不确定在代码高尔夫球的答案中是否经常使用它,但是一般规则是您的代码仅必须在至少一种版本的语言解释器上工作。IMO很好。
彼得·科德斯

s=0不需要,因为算术替换会将未设置的变量视为0-u如果仅假设默认时区(UTC),也不需要。
丹尼斯,

-u在我的计算机上是必需的:)
Will Crawford

4

迅捷,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

@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

感谢队友:)
Thiago Oleinik

@LuisMendo感谢您的建议,但我不明白...在您的示例中,变量是t什么?此外,to的输入datestr是以天为单位的,因此我将必须除以86400,这将使字节数增加两个……
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内置的时间处理方法要短。

不带睡眠的旧解决方案(1),使用DateTime

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()

内置时间本身并不重要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

学分


您可以通过替换"%02d:%02d:%02d"(":%02d"*3)[1:]
wnnmaw

1
您不需要%24,之后的行为是不确定的23:59:59
Erik the Outgolfer

@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:

在线尝试!

+7个字节,用于使用标志-t.0125使每条指令占用1/80秒。每个循环有80条指令,使每个循环长一秒。由于计算时间长,实际上实际上更长。

实际上,我必须一直将其一直缓冲到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

奖金:

相同大小的单行版本,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个字节。
Daniel W.


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

立即运行:预期的故障点约为2300万年(浮点解析失败〜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

APL(Dyalog),37字节

{∇⍵+×⎕DL 1⊣⎕←1↓∊':'@1∘⍕¨100+⍵⊤⍨360}0

在线尝试!

完整程序。

与Adám的答案非常相似,但是它是独立编写的,并且使用基于非⎕AI基于语言的方法。


2

Bash + coreutils + GNU日期,50个字节

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

受@Dennis的启发,此解决方案不需要更改时间。它以'o'存储从现在到UNIX时期(UT​​C 1970年1月1日00:00:00)的初始偏移量,然后以UTC日期显示[-ud options](当前时间-偏移量),但是仅[+%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捆绑软件下有效。

如果希望它在Linux下工作,请添加3个字节,如CLK_PER_TICK :== 1000000* nix上的Clean即可。如果您希望它是跨平台的,请添加8个字节,因为您需要使用它CLK_PER_TICK而不是它设置的值。(由于上述原因,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字节

感谢Jo King推荐-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秒稍长。将\\第二行的更改<<为可以更准确地确定TIO的时序。

您还可以在鱼游乐场观看正在运行的代码,除了此解释器对待空白与正式解释器略有不同。或者,您可以删除TIO上的标志以使代码以最快的速度运行,以在一分钟后验证行为。


-1字节,方法是用第一行中的v替换\!并删除多余的两个<。如果使用该-a标志,则另外两个字节,该标志将空格和跳过的指令计数为刻度
Jo King

@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秒后超时,所以我将sleep设置为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秒后超时,所以我将sleep设置为1以查看更多输出)。

说明:

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

这是一个小的gif,可以看到它在使用1000 ms时可以正常工作:

在此处输入图片说明


2

PHP,59 48字节

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

受到Darren H的回答的启发。

旧版本

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

答案中可以省略PHP开放标签,从而节省6个字节。
Daniel W.

很好的想法,但是3600必须是86400,否则计数器从23:00:00开始,因此很遗憾,您获得了一个字节,尽管如此我还是被9击败!
达伦·H

@DarrenH我认为这取决于您的语言环境,我还没有考虑过。我在GMT + 1上,这就是为什么我加3600的原因,但是我猜对于英国人来说,您可以-3600完全删除它,这将节省5个字节。
roberto06年

1

Shell,177字节

请注意,这并不完全符合POSIX,因为它使用date +%s,这是常见的date扩展。

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
@Adám我没有接受我的答案,而当时我发布的答案要短得多(就像您的答案一样)。
MarkWeston

1

Ruby,192,117字节(贷给Dada)

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,则将数字字符串中的INT⍵转换为该字符串的长度,而不是在其前面加上一个“ 0”

{∊⍵,¨':: '}

将in中的数组与数组'::'

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 + open /dev/cpu/%d/msr,因此我决定将频率设为构建时间常数。(FREQ_RDTSC根据需要进行调整:任何32位常量都不会更改机器代码的大小)

请注意,多年来x86 CPU具有固定的RDTSC频率,因此除非您采取措施禁用频率更改,否则它可用作时间源,而不是核心时钟周期性能计数器。(有一些实际的性能计数器可用来计算实际CPU周期。)通常,它以标称的标贴频率滴答,例如,对于我的i7-6700k,其频率为4.0GHz,无论是否采用涡轮增压或节能模式。无论如何,这种繁忙等待时间并不取决于平均负载(就像经过校准的延迟环路一样),并且对CPU的节能也不敏感。

该代码适用于参考频率低于2 ^ 32 Hz(即高达〜4.29 GHz)的任何x86。除此之外,时间戳的低32位将在1秒内完全结束,因此我也必须查看edx结果的高32位。

总结

推入00:00:00\n堆栈。然后循环:

  • sys_write 系统调用
  • ADC环路在数字(开始于最后)由1包装/递增时间搬出与处理cmp/ cmov,与CF结果提供搬入下一个数字。
  • rdtsc 并节省开始时间。
  • 旋转rdtsc直到增量> = TDTSC频率的每秒刻度数。

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指令以节省大量功率:在不使用的情况下pause,一个内核加热约15摄氏度,在使用时仅加热约9摄氏度pause。(在Skylake上,它的pause睡眠时间为〜100个周期,而不是〜5 个周期。我认为,如果运行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 edx。该int 0x80系统调用ABI不会使用ESI / EDI,因此寄存器设置为系统调用与LODSB / STOSB可能比较简单。


我本可以使用nanosleep系统调用,但这更有趣。在Linux上具有root用户,可以读取正确的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

说明:

这里执行三个命令:

  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二进制文件中。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.