Implementar um cronômetro simples


25

Desafio

Sua tarefa é escrever um programa que, uma vez por segundo (inclusive imediatamente quando o programa for iniciado), imprima o tempo decorrido a partir do momento em que o programa foi iniciado.

Regras

  • A hora deve ser impressa no hh:mm:ssformato. (zeros à esquerda para valores de um dígito)
  • Os carimbos de hora devem ser separados por CR, LF ou CRLF. (sem espaço em branco à esquerda)
  • Um novo horário deve aparecer a cada segundo. (stdout não pode ser armazenado em buffer por um segundo)
  • O comportamento do programa se for executado depois das 23:59:59 é indefinido.
  • Você pode usar sleep(1)mesmo que um segundo específico possa ser pulado sempre que a sobrecarga de impressão, cálculo, loop, etc. se acumular em um segundo.

Exemplo de saída:

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

Observe que 00:00:03está faltando aqui devido à sobrecarga de processamento. Os valores ignorados reais (se houver) dependem da implementação e / ou sistema.

Implementação de referência em C: (apenas sistemas compatíveis com 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);
    }
}

Critérios de vitória

Este é o , o código mais curto em bytes ganha!


Nota para desafios posteriores, o esclarecimento nos comentários é uma coisa ruim a se fazer. Referência
user202729

Respostas:


9

MATL , 17 16 bytes

`Z`12L/13XOD1Y.T

Experimente no MATL Online!

Como funciona

`         % 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
Como você respondeu 37 minutos após o fechamento? o_O culpa o cache
Mr. Xcoder

9
@ Mr.Xcoder Eu aprendi recentemente a usar o Force
Luis Mendo

29

Linguagem de script da operação Flashpoint ,  174  171 bytes

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"

Em ação:

158 bytes, se o horário anterior for substituído pela próxima vez:

#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"

Tecnicamente, nenhum retorno de carro é usado; portanto, não tenho certeza se esta versão se restringe às regras.


5
Eu não estava esperando o ponto de inflamação da operação.
Polyducks

10
@Polyducks ninguém operação de espera ponto de inflamação
Pureferret

1
@Pureferret "Se você
Steadybox

Como no Unix, um CR sobrescreve a linha, acho que a segunda resposta é validada por 'CR, LF ou CRLF são permitidos' #
228 Stan Strum

1
@ StanStrum Pelo menos no meu Ubuntu CRnão sobrescreverá a linha. Na verdade, CRLF, LFCRe LFsão todos semanticamente equivalente.

13

Bash + coreutils, 28 26 bytes

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

O caractere não imprimível entre +e %é um byte ESC .

Isso define a hora do sistema para 00:00:00 e, portanto, requer privilégios de root. Ele também pressupõe que o fuso horário é UTC e que nenhum outro processo irá interferir no relógio do sistema.

Cada novo tempo reinicia o terminal, substituindo, assim, o anterior.


Bash + coreutils, 38 29 bytes

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

As mesmas restrições de antes se aplicam. Cada novo tempo é mostrado em uma nova linha.


Como isso não muda o número de bytes, eu separaria o primeiro datedo resto com um pequeno e agradável avanço de linha. Mas pode ser muito agradável para alguém capaz de chegar a algo como sua segunda solução> :-(
Aaron

date -s0imprime o novo horário em STDOUT; Estou usando o cano para silenciar essa saída.
Dennis

Oh certo, obrigado pela explicação!
Aaron

5

APL (Dyalog Unicode) , 51 bytes

Corpo do programa completo.

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

Experimente online! (Pressione Ctrl + Enter para iniciar e novamente para parar.)

⎕AIA ccount I nformação (ID de usuário, tempo de computação, tempo de conexão, tempo de chaveamento)

s← atribuir a s(para s tart tempo)
⎕AI-s subtrair sdo⎕AI

3⊃ escolha o terceiro elemento (tempo de conexão em milissegundos)
0 60 60 1E3⊤converta para esta mistura mista,
3↑ pegue os 3 primeiros (descarta os milissegundos)
100+ cem adicionados a cada (para zeros),
':'@1∘⍕¨ altere com dois pontos no primeiro caractere da representação de seqüência de caracteres de
ϵ nlist (achatar)
1↓ soltar o primeiro dois pontos (e imprimir implicitamente em stdout)

⎕DL 1D e L ay um segundo

→2 vá para a linha número dois


5

R , 59 44 bytes

Fem R o padrão é FALSE, mas é uma variável regular e pode ser redefinida. Quando usado em aritmética, FALSEé coagido a 0. Solicitando, F+1portanto, retornos 1. Atribuímos Fpara ser F+1, formate-o bem, imprima e aguarde um segundo. Continua indefinidamente.

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

Não funciona no TIO (devido à falta do hmspacote), mas aqui está um exemplo de saída da minha máquina:

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

festança + suspensão + data, também 50 49 47 46 45 41 bytes

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

Para tirar uma volta, pressione ^ C, execute-o e execute novamente o procedimento acima:

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

Reiniciar:

s=0; unset laps

A sintaxe $ [s ++] parece ainda funcionar, mas não está mais (AFAICS) documentada na bashpágina do manual. E ainda é um byte mais curto do que usar o loop for ((...)), depois que removi as aspas.


AFAICT, $[]é uma forma obsoleta / não documentada, mas ainda é suportada$(()) . Não tenho certeza se é comumente usado em respostas de código-golfe, mas a regra geral é que seu código precisa funcionar em pelo menos uma versão do intérprete para o seu idioma. OMI está bem.
Peter Cordes

s=0não é necessário, pois a substituição aritmética tratará uma variável não definida como 0 . -utambém não é necessário se você apenas assumir o fuso horário padrão (UTC).
Dennis

-u é necessário na minha máquina :)
Will Crawford

4

Rápido , 144 bytes

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

Explicação

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 bytes

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


2
As horas não começam em 0 para mim. O deslocamento muda dependendo do fuso horário do sistema. (Win10)
LukeS

@LukeS Whoops, consertado!
darrylyeo

4

Matlab (R2016b), 50 bytes

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

Explicação:

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

Versão alternativa (50 bytes também: P):

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

Bem vindo ao site! :)
DJMcMayhem

Obrigado companheiro:)
Thiago Oleinik

@LuisMendo Obrigado pela sugestão, mas não entendi ... No seu exemplo, qual é a variável t? Além disso, a entrada para datestré em dias, então eu teria que dividir por 86400, o que aumentaria o número de bytes por dois ...
Thiago Oleinik

3

Julia 0.6 , 75 68 bytes

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

Experimente online!

Com sleep (1) permitido, for-loops aninhados simples são mais curtos do que os métodos de manipulação de tempo internos do Julias.

Solução antiga sem suspensão (1) usando DateTime

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

té a quantidade de tempo que passou do 'dia 0' para o início do programa. now()-té um momento no tempo , que é formatado usando Dates.format().

t0=now(); ...; now()-t0produziria uma diferença de tempo que não pode ser usada com Dates.format().

O tempo em si é trivial com o build-in Timer.


3

Python 2 , 85 bytes

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

Créditos


Você pode salvar um byte substituindo "%02d:%02d:%02d"por(":%02d"*3)[1:]
wnnmaw

1
Você não precisa %24, o comportamento é indefinido depois 23:59:59.
Erik the Outgolfer

@EriktheOutgolfer Bom ponto, atualizado.
28417 Neil

3

JavaScript (ES6), 88 bytes

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

Essencialmente, a mesma abordagem da resposta de @ darrylyeo , mas funciona para todos os fusos horários e usa uma maneira ligeiramente diferente de chegar a 0.

A resposta de Darryl foi corrigida. Isso ainda é mais curto, no entanto.


3

> <> , 82 + 7 = 89 bytes

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

Experimente online!

+7 bytes para usar o sinalizador -t.0125para fazer com que cada instrução tome 1/80 de segundo. Cada loop tem 80 instruções, tornando cada loop um segundo. Por causa do tempo de computação, isso é realmente mais longo na prática.

Na verdade, eu tive que armazenar isso em buffer até 100, até que vi a resposta do @Not A Tree que tinha 7 bytes de maneira melhor do que a minha para gerar horas e minutos, aparando abaixo de 80. Eles também inspiraram o uso dos \/quais são executados duas vezes por loop.

Como funciona

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

Bônus:

Uma versão de uma linha do mesmo tamanho, 80 + 9 bytes:

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

Isso usa o -asinalizador para adicionar ticks para instruções ignoradas.


3

PHP 4+, 70 64 bytes

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

PHP 5.3+, 69 63 bytes

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

As tags abertas do PHP podem ser omitidas na resposta, economizando 6 bytes.
Daniel W.

2

Python 3 , 112 bytes

Supondo que o atraso de 1 segundo seja aceitável, mesmo que (raramente) possa pular um segundo.

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

executado na janela imediata: ponto de falha esperado em torno de 23 milhões de anos (a resolução de ponto flutuante falha ~ 8,5e9 dias)



2

AWK , 110 87 86 bytes

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

Não funciona no TIO.


Seu programa parece não ser impresso 00:00:00no momento em que foi iniciado.
user202729

Corrigido. Graças
Noskcaj

2

APL (Dyalog) , 37 bytes

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

Experimente online!

Programa completo.

Bem parecido com a resposta de Adám, porém escrito de forma independente e usando uma ⎕AIabordagem não baseada.


2

Bash + coreutils + data GNU, 50 bytes

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

Inspirada em @Dennis, esta solução não exige que o tempo seja alterado. Ele armazena o deslocamento inicial de agora para a época UNIX (1 de janeiro de 1970 00:00:00 UTC), em 'o' e exibe [-ud options] (o horário atual - deslocamento), na data UTC, mas somente [opção +% X] HH: MM: SS. Isso deve funcionar em países onde o fuso horário atual não é UTC.


2

Limpo , 173 172 168 bytes

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]

Este funciona apenas nos pacotes do Windows Clean.

Adicione 3 bytes se quiser que ele funcione no Linux, como o Clean CLK_PER_TICK :== 1000000no * nix. Se você deseja que ela seja multiplataforma, adicione 8 bytes, em vez disso, conforme for necessário, em CLK_PER_TICKvez do valor definido. (O link do TIO é maior devido ao acima )

Experimente online!


2

Python 2 , 69 + 3 ( TZ=) = 72 bytes

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

Isso é executado em um loop contínuo, sem suspensão, atualizando o horário na mesma linha, em vez de imprimir uma nova linha a cada segundo. (Ainda permitido pelas regras, espero.)

Esta versão um pouco mais longa (72 + 3 = 75 bytes) imprime em uma nova linha a cada segundo:

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

Ambos exigem que você esteja no fuso horário UTC. No Linux, você pode conseguir isso configurando a TZvariável de ambiente. Por exemplo TZ= python.


2

> <> , 106 bytes 82 + 9 = 91 bytes

Obrigado a Jo King por sugerir a -abandeira! Confira a resposta deles também.

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

Experimente online! (mas você terá que aguardar o tempo limite de 60 segundos).

Eu usei um recurso de> <> que eu nunca precisei antes: esse código requer o sinalizador -t.0125, que define a velocidade de execução para 0,0125 segundos por tick, ou 80 ticks por segundo. Há também a -abandeira, que faz com que o espaço em branco conte como uma marca (em alguns casos - o intérprete é um pouco estranho nisso).

Basicamente, o código mantém um contador que é incrementado toda vez que o peixe passa pelo loop, e o resto do loop converte o contador em hh:mm:ssformato e imprime. O loop leva exatamente 80 ticks.

Isso deve funcionar na teoria, mas na prática, cada tick é um pouco maior que 0,0125 segundos, devido ao tempo de computação. Alterar a \\na segunda linha para <<fornece tempos mais precisos no TIO.

Você também pode assistir o código em ação no playground de peixes , exceto que esse intérprete trata os espaços em branco de maneira um pouco diferente do intérprete oficial. Como alternativa, você pode remover os sinalizadores no TIO para fazer com que o código seja executado na velocidade máxima, para verificar o comportamento por momentos após um minuto.


-1 byte, substituindo v na primeira linha \!e removendo dois dos extras <. Outro par de bytes se você usar a -abandeira, que conta espaços em branco e ignorados instruções como carrapatos
Jo rei

@ JoKing, a -abandeira deixa-me jogar um pouco mais, obrigado! Acho que você também pode usar o \!truque no seu código: Experimente online!
Não é uma árvore

2

Java 8, programa completo, 150 bytes

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);}}

Experimente aqui (o tempo limite é excedido após 60 segundos, então configurei o sono como 1 para ver mais resultados).

Explicação:

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, função, 94 bytes

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

Experimente aqui (o tempo limite é excedido após 60 segundos, então configurei o sono como 1 para ver mais resultados).

Explicação:

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

Aqui está um pequeno gif para vê-lo funcionar conforme o esperado quando 1000 ms são usados:

insira a descrição da imagem aqui


2

PHP, 59 48 bytes

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

Inspirado pela resposta de Darren H .

Versão antiga :

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

As tags abertas do PHP podem ser omitidas na resposta, economizando 6 bytes.
Daniel W.

Boa ideia, mas o 3600 precisa ser 86400, caso contrário, o contador começa às 23:00:00, então, infelizmente, você ganha um byte, ainda assim me venceu por 9!
Darren H

@ DarrenH Eu acho que depende do seu local, eu não tinha pensado nisso. Estou no GMT + 1, foi por isso que adicionei 3600, mas acho que para os ingleses, você pode remover o -3600total, o que economiza 5 bytes.
Robert06

1

Concha , 177 bytes

Observe que isso não é totalmente compatível com POSIX porque ele usa date +%s, o que é uma dateexpansão comum .

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
Normalmente, você deve dar às pessoas a chance de responder ao seu desafio antes de responder você mesmo. Eu recomendo uma semana, pois alguns só podem estar aqui em determinados horários durante a semana.
Adám

1
@ Adám Não aceito minha resposta e, na época, publiquei respostas muito mais curtas (como a sua).
MarkWeston

1

Ruby, 192 117 bytes (Crédito ao 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

Como funciona?

Vai usar a versão expandida (a conversão para um horário é fornecida como uma função separada e usa um formato de saída diferente):

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
Bem-vindo ao site! Todas as respostas para um desafio de código-golfe devem ser jogadas. Você deve remover pelo menos espaços em branco inúteis e usar nomes de variáveis ​​com 1 caractere. Isso daria a você cerca de 120 bytes, e usar em printfvez de putspode economizar mais alguns bytes: Experimente online! . Feliz golfe no PPCG!
Dada

1

APL NARS, 109 63 57 caracteres

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

3 + 3 + 48 + 3 = 57 (veja as outras soluções Apl também)

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

converta o INT ⍵ na sequência de dígitos de uma maneira, se o comprimento dessa sequência for 1, em seguida, adicione um '0' na frente dela

{∊⍵,¨':: '}

combinar array em ⍵ com o array '::'

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

código da máquina x86-64 (chamada do sistema Linux): 78 bytes

Tempo de rotação do loop RDTSC , sys_writechamada do sistema Linux .

O x86-64 não fornece uma maneira conveniente de consultar a frequência do "relógio de referência" RDTSC em tempo de execução. Você pode ler um MSR (e fazer um cálculo com base nisso) , mas isso requer o modo do kernel, ou abertura de raiz + /dev/cpu/%d/msr, então decidi tornar a frequência um tempo de compilação constante. (Ajuste FREQ_RDTSCconforme necessário: qualquer constante de 32 bits não altera o tamanho do código da máquina)

Observe que as CPUs x86 há vários anos têm frequência RDTSC fixa, por isso é utilizável como fonte de tempo, não como contador de desempenho do ciclo do clock principal, a menos que você tome medidas para desativar as alterações de frequência. (Existem contadores de desempenho reais para contar os ciclos reais da CPU.) Geralmente, ele funciona na frequência nominal dos adesivos, por exemplo, 4,0 GHz para o meu i7-6700k, independentemente de turbo ou economia de energia. De qualquer forma, esse tempo de espera ocupada não depende da média da carga (como seria um loop de atraso calibrado) e também não é sensível à economia de energia da CPU.

Este código funcionará para qualquer x86 com uma frequência de referência abaixo de 2 ^ 32 Hz, ou seja, até ~ 4,29 GHz. Além disso, os 32 baixos do carimbo de data e hora seriam agrupados em 1 segundo, então eu teria que olhar também para os edx32 bits altos do resultado.

Sumário :

empurre 00:00:00\na pilha. Então, em um loop:

  • sys_write chamada do sistema
  • Loop ADC sobre os dígitos (começando com o último) para aumentar o tempo em 1. Acondicionamento / transporte tratado com a cmp/ cmov, com o resultado de CF fornecendo o transporte para o próximo dígito.
  • rdtsc e salve a hora de início.
  • gire rdtscaté que o delta seja> = marca por segundo da frequência RDTSC.

Listagem 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.

Remova o comentário da pauseinstrução para economizar energia significativa: isso aquece um núcleo em ~ 15 graus C sem pause, mas apenas em ~ 9 com pause. (No Skylake, onde pausedorme por ~ 100 ciclos em vez de ~ 5. Eu acho que economizaria mais se rdtsctambém não fosse lento, para que a CPU não fique muito tempo).


Uma versão de 32 bits seria alguns bytes mais curta, por exemplo, usando uma versão de 32 bits para enviar a string 00: 00: 00 \ n inicial.

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

E também usando 1 byte dec edx. A int 0x80chamada de sistema ABI não usaria esi / edi, portanto, a configuração do registro para o syscall vs. lodsb / stosb pode ser mais simples.


Eu poderia ter usado uma nanosleepchamada do sistema, mas isso foi mais interessante. Com o root no Linux, é possível ler o MSR correto e obter programaticamente a frequência RDTSC.
Peter Cordes

1

q / kdb + , 40 bytes

Solução:

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

Exemplo:

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

Explicação:

Existem três comandos sendo executados aqui:

  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

Repartição da função do temporizador:

.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

Bônus:

Alternativa 1 para 41 bytes :

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

Alternativa 2 para 26 + 7 bytes = 33 bytes

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

e adicionando -t 1000como argumentos ao binário q.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.