Implementa un semplice cronometro


25

Sfida

Il tuo compito è quello di scrivere un programma che, una volta al secondo (anche immediatamente all'avvio del programma), stampa il tempo trascorso dal momento dell'avvio del programma.

Regole

  • L'ora deve essere stampata nel hh:mm:ssformato. (zeri iniziali per valori a una cifra)
  • I timestamp devono essere separati da CR, LF o CRLF. (nessuno spazio bianco iniziale)
  • Un nuovo orario deve apparire ogni secondo. (stdout non può essere bufferizzato per un secondo)
  • Il comportamento del programma se viene eseguito alle 23:59:59 non è definito.
  • È possibile utilizzare sleep(1)anche se un secondo specifico può essere saltato ogni volta che l'overhead per la stampa, il calcolo, il ciclo, ecc. Si accumula in un secondo.

Esempio di output:

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

Si noti che 00:00:03manca qui a causa del sovraccarico di elaborazione. I valori effettivamente ignorati (se presenti) dipendono ovviamente dall'implementazione e / o dal sistema.

Implementazione di riferimento in C: (solo sistemi compatibili 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);
    }
}

Criteri vincenti

Questo è , il codice più corto in byte vince!


Nota per le sfide successive, il chiarimento nei commenti è una brutta cosa da fare. riferimento
user202729,

Risposte:


9

MATL , 17 16 byte

`Z`12L/13XOD1Y.T

Provalo su MATL Online!

Come funziona

`         % 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
In che modo hai risposto a questo 37 minuti dopo la sua chiusura? o_O incolpa la memorizzazione nella cache
Mr. Xcoder il

9
@ Mr.Xcoder Di recente ho imparato a usare la Forza
Luis Mendo il

29

Operazione linguaggio di scripting Flashpoint ,  174  171 byte

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"

In azione:

158 byte, se la volta precedente viene sovrascritta dalla volta successiva:

#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, non viene utilizzato alcun ritorno a capo, quindi non sono sicuro che questa versione sia limitata alle regole.


5
Non mi aspettavo un'operazione flashpoint.
Polyducks il

10
@Polyducks nessuno si aspetta un'operazione
flashpoint


Dato che in Unix, un CR sovrascriverà la riga, penso che la seconda risposta sia convalidata da "Sono consentiti CR, LF o CRLF"
Stan Strum,

1
@StanStrum Almeno sul mio Ubuntu CRnon sovrascriverà la linea. In realtà, CRLF, LFCRe LFsono tutti semanticamente equivalenti.

13

Bash + coreutils, 28 26 byte

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

Il carattere non stampabile tra +e %è un byte ESC .

Ciò imposta l'ora di sistema su 00:00:00 e quindi richiede i privilegi di root. Presuppone inoltre che il fuso orario sia UTC e che nessun altro processo interferisca con l'orologio di sistema.

Ogni nuovo timing resetta il terminale, sovrascrivendo così quello precedente.


Bash + coreutils, 38 29 byte

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

Si applicano le stesse restrizioni di prima. Ogni nuovo tempismo viene mostrato su una nuova riga.


Dato che non cambia il bytecount, separerei il primo datedal resto con un piccolo avanzamento di riga. Ma potrebbe essere troppo bello per qualcuno in grado di inventare qualcosa come la tua seconda soluzione> :-(
Aaron,

date -s0stampa il nuovo orario su STDOUT; Sto usando la pipa per mettere a tacere quell'uscita.
Dennis,

Oh giusto, grazie per la spiegazione!
Aaron,

5

APL (Dyalog Unicode) , 51 byte

Corpo del programma completo.

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

Provalo online! (Premi Ctrl + Invio per iniziare e di nuovo per interrompere.)

⎕AIUn CCOUNT I nformazione (ID utente, il tempo di calcolo, tempo di connessione, tempo di keying)

s← assegnare a s(per il periodo di prova)
⎕AI-s sottrarre sda⎕AI

3⊃ scegli il terzo elemento (tempo di connessione in millisecondi)
0 60 60 1E3⊤convertito in questo radix misto
3↑ prendi i primi 3 (elimina i millisecondi)
100+ cento aggiunti a ciascuno (per zeri di pad)
':'@1∘⍕¨ modificano con due punti al primo carattere della rappresentazione di stringa di ciascuno
ϵ nlist (appiattisci)
1↓ rilascia i primi due punti (e stampa implicitamente su stdout)

⎕DL 1D e l ay uno seconda

→2 vai alla riga numero due


5

R , 59 44 byte

Fin R il valore predefinito è FALSE, ma è una variabile regolare e può essere ridefinita. Se usato in aritmetica, FALSEè costretto a 0. Chiedere F+1quindi ritorni 1. Assegniamo Fdi essere F+1, formattarlo bene, stampare e attendere un secondo. Continua indefinitamente.

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

Non funziona su TIO (a causa della mancanza del hmspacchetto), ma ecco un esempio di output dalla mia macchina:

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, anche 50 49 47 46 45 41 byte

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

Per prendere un tempo sul giro, premi rapidamente ^ C, esegui questo e quindi esegui nuovamente quanto sopra:

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

Resettare:

s=0; unset laps

La sintassi $ [s ++] sembra funzionare ancora, ma non è più (AFAICS) documentata nella bashpagina man. Ed è ancora un byte più breve rispetto all'uso del ciclo for ((...)), una volta rimosse le virgolette attorno ad esso.


AFAICT, $[]è una forma obsoleta / non documentata ma ancora supportata$(()) . Non sono sicuro che sia comunemente usato nelle risposte di code-golf, ma la regola generale è che il tuo codice deve funzionare solo su almeno una versione dell'interprete per la tua lingua. IMO va bene.
Peter Cordes,

s=0non è richiesto, poiché la sostituzione aritmetica tratterà una variabile non impostata come 0 . -uinoltre non è necessario se si assume semplicemente il fuso orario predefinito (UTC).
Dennis,

-u è necessario sulla mia macchina :)
Will Crawford il

4

Rapido , 144 byte

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

Spiegazione

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 byte

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


2
Le ore non iniziano a 0 per me. L'offset cambia in base al fuso orario dell'orologio di sistema. (Win10)
LukeS,

@LukeS Whoops, risolto!
darrylyeo,

4

Matlab (R2016b), 50 byte

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

Spiegazione:

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

Versione alternativa (anche 50 byte: P):

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

Benvenuti nel sito! :)
DJMcMayhem

Grazie :)
amico

@LuisMendo Grazie per il suggerimento, ma non ho capito ... Nel tuo esempio, qual è la variabile t? Inoltre, l'input datestrè in giorni, quindi dovrei dividere per 86400, il che aumenterebbe il conteggio dei byte di due ...
Thiago Oleinik,

3

Julia 0.6 , 75 68 byte

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

Provalo online!

Con sleep (1) consentito, i semplici cicli for nidificati sono più brevi rispetto all'utilizzo dei metodi di gestione del tempo integrati di Julias.

Vecchia soluzione senza sonno (1) utilizzando DateTime

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

tè il periodo di tempo trascorso da 'giorno 0' a quando il programma è avviato. now()-tè un momento nel tempo , che viene quindi formattato utilizzando Dates.format().

t0=now(); ...; now()-t0produrrebbe una differenza di tempo , che non può essere utilizzata con Dates.format().

Il tempismo stesso è banale con il build-in Timer.


3

Python 2 , 85 byte

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

Crediti


È possibile salvare un byte sostituendo "%02d:%02d:%02d"con(":%02d"*3)[1:]
wnnmaw il

1
Non è necessario %24, il comportamento non è definito dopo 23:59:59.
Erik the Outgolfer,

@EriktheOutgolfer Buon punto, aggiornato.
Neil,

3

JavaScript (ES6), 88 byte

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

Essenzialmente lo stesso approccio della risposta di @ darrylyeo , ma funziona per tutti i fusi orari e utilizza un modo leggermente diverso per arrivare a 0.

[Modifica] La risposta di Darryl è stata corretta. Questo è ancora più breve, però.


3

> <> , 82 + 7 = 89 byte

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

Provalo online!

+7 byte per l'utilizzo del flag -t.0125per far sì che ciascuna istruzione impieghi 1/80 di secondo. Ogni ciclo ha 80 istruzioni, rendendo ogni ciclo lungo un secondo. A causa del tempo di calcolo, questo in realtà è più lungo in pratica.

In realtà ho dovuto bufferizzare tutto questo fino a 100 fino a quando non ho visto la risposta di @Not A Tree che aveva un modo migliore di 7 byte del mio per generare ore e minuti, tagliandolo sotto 80. Hanno anche ispirato l'uso dei \/quali vengono eseguiti due volte per loop.

Come funziona

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

Bonus:

Una versione a una riga della stessa dimensione, 80 + 9 byte:

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

Questo utilizza il -aflag per aggiungere segni di spunta per le istruzioni saltate.


3

PHP 4+, 70 64 byte

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

PHP 5.3+, 69 63 byte

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

I tag aperti di PHP possono essere omessi nella risposta salvandoti 6 byte.
Daniel W.

2

Python 3 , 112 byte

Supponendo che l'uso dei ritardi di 1 secondo sia corretto, anche se (raramente) potrebbe saltare un secondo.

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

eseguito in una finestra immediata: punto di guasto previsto da qualche parte circa 23 milioni di anni (risoluzione in virgola mobile non riuscita ~ 8,5e9 giorni)



2

AWK , 110 87 86 byte

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

Non funziona in TIO.


Il tuo programma non sembra stampare 00:00:00al momento dell'avvio.
user202729

Aggiustato. Grazie
Noskcaj il

2

APL (Dyalog) , 37 byte

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

Provalo online!

Programma completo.

Abbastanza simile alla risposta di Adám, comunque scritta in modo indipendente e utilizza un ⎕AIapproccio non basato.


2

Bash + coreutils + data GNU, 50 byte

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

Ispirata da @Dennis, questa soluzione non richiede tempo per essere modificata. Memorizza l'offset iniziale da ora all'epoca UNIX (1 gennaio 1970 00:00:00 UTC), in 'o', e quindi visualizza [-ud opzioni] (l'ora corrente - offset), in data UTC, ma solo [+% X opzione] HH: MM: SS. Questo dovrebbe funzionare nei paesi in cui il fuso orario corrente non è UTC.


2

Pulito , 173 172 168 byte

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]

Questo funziona solo con i bundle di Windows Clean.

Aggiungi 3 byte se vuoi che funzioni sotto Linux, come Clean è CLK_PER_TICK :== 1000000su * nix. Se si desidera che sia multipiattaforma, aggiungere invece 8 byte, poiché è necessario utilizzare CLK_PER_TICKinvece del valore su cui è impostato. (Il collegamento TIO è più grande a causa di quanto sopra )

Provalo online!


2

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

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

Questo viene eseguito in un ciclo continuo, senza dormire, aggiornando l'ora sulla stessa riga anziché stampare una nuova riga ogni secondo. (Spero ancora nelle regole).

Questa versione leggermente più lunga (72 + 3 = 75 byte) stampa invece su una nuova riga ogni secondo:

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

Entrambi richiedono di essere nel fuso orario UTC. Su Linux puoi farlo impostando la TZvariabile d'ambiente. Es TZ= python.


2

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

Grazie a Jo King per aver suggerito la -abandiera! Controlla anche la loro risposta .

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

Provalo online! (ma dovrai aspettare il timeout di 60 secondi).

Devo usare una funzionalità di> <> che non ho mai avuto bisogno prima: questo codice richiede il flag -t.0125, che imposta la velocità di esecuzione su 0,0125 secondi per tick o 80 tick per secondo. C'è anche la -abandiera, che rende gli spazi bianchi un segno di spunta (in alcuni casi - l'interprete è un po 'strano al riguardo).

Fondamentalmente, il codice mantiene un contatore che viene incrementato ogni volta che il pesce passa attraverso il loop e il resto del loop converte il contatore per hh:mm:ssformattarlo e stamparlo. Il ciclo richiede esattamente 80 tick.

Questo dovrebbe funzionare in teoria, ma in pratica ogni tick è leggermente più lungo di 0,0125 secondi, a causa del tempo di calcolo. Modificando la \\seconda riga per <<ottenere tempi più precisi su TIO.

Puoi anche guardare il codice in azione nel parco giochi per pesci , tranne per il fatto che questo interprete tratta gli spazi leggermente in modo diverso dall'interprete ufficiale. In alternativa, è possibile rimuovere i flag su TIO per far funzionare il codice alla massima velocità, per verificare il comportamento per volte dopo un minuto.


-1 byte sostituendo la v nella prima riga con \!e rimuovendo due extra <. Un'altra coppia di byte se si utilizza la -abandiera, che conta gli spazi bianchi e le istruzioni saltate come segni di spunta
Jo King,

@JoKing, La -abandiera mi ha permesso di giocarci ancora un po ', grazie! Penso che puoi usare anche il \!trucco nel tuo codice: provalo online!
Non un albero il

2

Java 8, programma completo, 150 byte

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

Provalo qui (timeout dopo 60 secondi, quindi ho impostato lo sleep su 1 per vedere più output).

Spiegazione:

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, funzione, 94 byte

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

Provalo qui (timeout dopo 60 secondi, quindi ho impostato lo sleep su 1 per vedere più output).

Spiegazione:

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

Ecco una piccola gif per vedere che funziona come previsto quando vengono utilizzati 1000 ms:

inserisci qui la descrizione dell'immagine


2

PHP, 59 48 byte

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

Ispirato dalla risposta di Darren H .

Vecchia versione :

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

I tag aperti di PHP possono essere omessi nella risposta salvandoti 6 byte.
Daniel W.

Ottima idea, ma 3600 devono essere 86400 altrimenti il ​​contatore inizia alle 23:00:00 quindi sfortunatamente guadagni un byte, comunque mi batti di 9!
Darren H,

@DarrenH Penso che dipenda dal tuo paese, non ci avevo pensato. Sono in GMT + 1, ecco perché ho aggiunto 3600, ma suppongo che per gli inglesi, potresti rimuoverli del -3600tutto, il che risparmierebbe 5 byte.
roberto06,

1

Shell , 177 byte

Si noti che questo non è completamente conforme a POSIX perché utilizza date +%s, che è dateun'espansione comune .

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, dovresti dare alle persone la possibilità di rispondere alla tua sfida prima di rispondere tu stesso. Consiglio una settimana perché alcuni potrebbero essere qui solo in determinati orari durante la settimana.
Adám,

1
@Adám Non ho accettato la mia risposta e al momento ho pubblicato risposte molto più brevi (come la tua).
MarkWeston,

1

Rubino, 192 117 byte (credito a 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

Come funziona?

Andando a utilizzare la versione espansa (la conversione in un'ora è data come una funzione separata e utilizza un formato di output diverso):

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
Benvenuti nel sito! Ogni risposta a una sfida di code-golf deve essere golfata. Dovresti almeno rimuovere gli spazi bianchi inutili e usare nomi di variabili di 1 carattere. Ciò ti farebbe guadagnare circa 120 byte e l'utilizzo al printfposto di putspuò salvare qualche altro byte: provalo online! . Buon golf su PPCG!
Dada,

1

APL NARS, 109 63 57 caratteri

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

3 + 3 + 48 + 3 = 57 (viste anche le altre soluzioni Apl)

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

converti INT ⍵ nella stringa di cifre in un modo se la lunghezza di quella stringa è 1 piuttosto che aggiungi uno '0' davanti ad essa

{∊⍵,¨':: '}

combina array in ⍵ con l'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

codice macchina x86-64 (chiamata di sistema Linux): 78 byte

Temporizzazione spin-loop RDTSC , sys_writechiamata di sistema Linux .

x86-64 non fornisce un modo conveniente per interrogare la frequenza "clock di riferimento" RDTSC in fase di esecuzione. Puoi leggere un MSR (e fare un calcolo basato su quello) , ma ciò richiede la modalità kernel, o root + apertura /dev/cpu/%d/msr, quindi ho deciso di rendere la frequenza una costante di tempo di costruzione. (Regola FREQ_RDTSCse necessario: qualsiasi costante a 32 bit non cambierà la dimensione del codice macchina)

Si noti che le CPU x86 da diversi anni hanno una frequenza RDTSC fissa, quindi è utilizzabile come fonte di tempo, non come contatore delle prestazioni del ciclo di clock principale a meno che non si adottino misure per disabilitare le variazioni di frequenza. (Esistono contatori perf effettivi per il conteggio dei cicli CPU reali.) Di solito spunta alla frequenza nominale dell'adesivo, ad esempio 4,0 GHz per il mio i7-6700k indipendentemente dal turbo o dal risparmio energetico. Ad ogni modo, questo tempismo di attesa non dipende dalla media del carico (come farebbe un loop di ritardo calibrato) e non è sensibile al risparmio energetico della CPU.

Questo codice funzionerà con qualsiasi x86 con una frequenza di riferimento inferiore a 2 ^ 32 Hz, ovvero fino a ~ 4,29 GHz. Oltre a ciò, i 32 bassi del timestamp andrebbero a capo in 1 secondo, quindi dovrei guardare anche i edx32 bit alti del risultato.

Riepilogo :

spingere 00:00:00\nin pila. Quindi in un ciclo:

  • sys_write chiamata di sistema
  • Scorri ADC sulle cifre (iniziando dall'ultima) per aumentare il tempo di 1. Avvolgimento / esecuzione gestita con un cmp/ cmov, con il risultato CF che fornisce il carry-in per la cifra successiva.
  • rdtsc e salva l'ora di inizio.
  • ruotare rdtscfino a quando il delta è> = tick per secondo della frequenza RDTSC.

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

Scomponi le pauseistruzioni per risparmiare energia significativa: questo riscalda un nucleo di ~ 15 ° C senza pause, ma solo di ~ 9 con pause. (Su Skylake, dove pausedorme per ~ 100 cicli invece di ~ 5. Penso che risparmierebbe di più se rdtscnon fosse anche lento, quindi la CPU non sta facendo molto tempo).


Una versione a 32 bit sarebbe più corta di alcuni byte, ad esempio utilizzando una versione a 32 bit per inviare la stringa iniziale 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

E anche usando 1 byte dec edx. La int 0x80chiamata di sistema ABI non userebbe esi / edi, quindi la configurazione del registro per syscall vs. lodsb / stosb potrebbe essere più semplice.


Avrei potuto usare una nanosleepchiamata di sistema, ma questo era più interessante. Con root su Linux, è possibile leggere il giusto MSR e ottenere a livello di codice la frequenza RDTSC.
Peter Cordes,

1

q / kdb + , 40 byte

Soluzione:

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

Esempio:

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

Spiegazione:

Esistono tre comandi in esecuzione qui:

  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

Ripartizione della funzione timer:

.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

Bonus:

Alternativa 1 per 41 byte :

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

Alternativa 2 per 26 + 7 byte = 33 byte

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

e aggiungendo -t 1000come argomenti al binario q.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.