Implementar un cronómetro simple


25

Reto

Su tarea es escribir un programa que, una vez por segundo (incluso inmediatamente cuando se inicia su programa), imprime el tiempo transcurrido desde el momento en que se inició su programa.

Reglas

  • El tiempo debe imprimirse en hh:mm:ssformato. (ceros a la izquierda para valores de un solo dígito)
  • Las marcas de tiempo deben estar separadas por CR, LF o CRLF. (sin espacios en blanco iniciales)
  • Un nuevo tiempo debe aparecer cada segundo. (stdout no se puede almacenar por un segundo)
  • El comportamiento del programa si se ejecuta más allá de las 23:59:59 no está definido.
  • Puede usar sleep(1)incluso si se puede omitir un segundo específico cada vez que la sobrecarga para imprimir, calcular, repetir, etc. se acumula a un segundo.

Salida de ejemplo:

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

Tenga en cuenta que 00:00:03falta aquí debido a la sobrecarga de procesamiento. Los valores omitidos reales (si los hay) dependen, por supuesto, de la implementación o del sistema.

Implementación de referencia en C: (solo sistemas compatibles con 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);
    }
}

Criterios ganadores

Este es el , ¡el código más corto en bytes gana!


Nota para los desafíos posteriores, la aclaración en los comentarios es algo malo. referencia
usuario202729

Respuestas:


9

MATL , 17 16 bytes

`Z`12L/13XOD1Y.T

¡Pruébalo en MATL Online!

Cómo 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)

44
¿Cómo respondiste esto 37 minutos después de que se cerró? o_O culpa al almacenamiento en caché
Sr. Xcoder

99
@ Mr.Xcoder Recientemente aprendí a usar la Fuerza
Luis Mendo

29

Lenguaje de script Operation 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"

En acción:

158 bytes, si la hora anterior se sobrescribe la 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"

Técnicamente, no se utiliza el retorno de carro, por lo que no estoy seguro de si esta versión se limita a las reglas.


55
No esperaba el punto de inflamación de la operación.
Polyducks

10
@Polyducks nadie espera un punto
crítico de


Dado que en Unix, un CR sobrescribirá la línea, creo que la segunda respuesta está validada por 'se permiten CR, LF o CRLF'
Stan Strum

1
@StanStrum Al menos en mi Ubuntu CRno sobrescribirá la línea. De hecho, CRLF, LFCRy LFson todos semánticamente equivalentes.

13

Bash + coreutils, 28 26 bytes

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

El carácter no imprimible entre +y %es un byte ESC .

Esto establece la hora del sistema en 00:00:00 y, por lo tanto, requiere privilegios de root. También supone que la zona horaria es UTC y que ningún otro proceso interferirá con el reloj del sistema.

Cada nueva sincronización restablece el terminal, sobrescribiendo así el anterior.


Bash + coreutils, 38 29 bytes

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

Se aplican las mismas restricciones que antes. Cada nueva sincronización se muestra en una nueva línea.


Como no cambia el bytecount, separaría el primero datedel resto con un pequeño salto de línea. Pero podría ser demasiado bueno para alguien capaz de encontrar algo como su segunda solución> :-(
Aaron

date -s0imprime la nueva hora en STDOUT; Estoy usando la tubería para silenciar esa salida.
Dennis

Oh cierto, gracias por la explicación!
Aaron

5

APL (Dyalog Unicode) , 51 bytes

Programa completo del cuerpo.

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

Pruébalo en línea! (Presione Ctrl + Enter para comenzar, y nuevamente para detener).

⎕AIA UENTA I nformación (ID de usuario, tiempo de cálculo, el tiempo de conexión, tiempo de Keying)

s← asignar a s(por tiempo de tarta s )
⎕AI-s restar sde⎕AI

3⊃ seleccione el tercer elemento (tiempo de conexión en milisegundos),
0 60 60 1E3⊤convierta a esta mezcla mixta,
3↑ tome los primeros 3 (suelte los milisegundos)
100+ cien agregados a cada (para rellenar ceros)
':'@1∘⍕¨ enmendar con dos puntos en el primer carácter de la representación de cadena de cada
ϵ nlist (flatten)
1↓ suelta los primeros dos puntos (e implícitamente imprime en stdout)

⎕DL 1D e l ay un segundo

→2 ir a la línea número dos


5

R , 59 44 bytes

Fen R por defecto FALSE, pero es una variable regular y se puede redefinir. Cuando se usa en aritmética, FALSEse obliga a 0. Pidiendo por lo F+1tanto vuelve 1. Asignamos Fa ser F+1, formatearlo bien, imprimir y esperar un segundo. Continúa indefinidamente.

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

No funciona en TIO (debido a la falta del hmspaquete), pero aquí hay una salida de muestra de mi 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

bash + sleep + date, también 50 49 47 46 45 41 bytes

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

Para tomar un tiempo de vuelta, presione rápidamente ^ C, ejecute esto y luego vuelva a ejecutar lo anterior:

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

Reiniciar:

s=0; unset laps

La sintaxis $ [s ++] parece seguir funcionando, pero ya no está documentada (AFAICS) en la bashpágina del manual. Y todavía es un byte más corto que usar el ciclo for ((...)), una vez que eliminé las comillas a su alrededor.


AFAICT, $[]es una forma de obsoleto / indocumentado pero aún compatible$(()) . No estoy seguro de si se usa comúnmente en las respuestas de código de golf, pero la regla general es que su código solo debe funcionar en al menos una versión del intérprete para su idioma. OMI está bien.
Peter Cordes

s=0no es obligatorio, ya que la sustitución aritmética tratará una variable no establecida como 0 . -utampoco es necesario si solo asume la zona horaria predeterminada (UTC).
Dennis

-u es necesario en mi 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)}

Explicación

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
Las horas no comienzan en 0 para mí. El desplazamiento cambia según la zona horaria del reloj del sistema. (Win10)
Lucas

@LukeS Whoops, arreglado!
darrylyeo

4

Matlab (R2016b), 50 bytes

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

Explicación:

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

Versión alternativa (50 bytes también: P):

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

Bienvenido al sitio! :)
DJMcMayhem

Gracias amigo:)
Thiago Oleinik

@LuisMendo Gracias por la sugerencia, pero no entendí ... En su ejemplo, ¿cuál es la variable t? Además, la entrada datestres en días, por lo que tendría que dividir por 86400, lo que aumentaría el recuento de bytes en dos ...
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

Pruébalo en línea!

Con sleep (1) permitido, los bucles for anidados simples son más cortos que el uso de los métodos de gestión de tiempo integrados de Julias.

Solución anterior sin dormir (1) usando DateTime

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

tes la cantidad de tiempo transcurrido desde el 'día 0' hasta que se inicia el programa. now()-tes un momento en el tiempo , que luego se formatea con Dates.format().

t0=now(); ...; now()-t0produciría una diferencia horaria , que no se puede usar con Dates.format().

El tiempo en sí mismo es trivial con el incorporado 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


Puede guardar un byte reemplazando "%02d:%02d:%02d"con(":%02d"*3)[1:]
wnnmaw

1
No es necesario %24, el comportamiento es indefinido después 23:59:59.
Erik the Outgolfer

@EriktheOutgolfer Buen punto, actualizado.
Neil

3

JavaScript (ES6), 88 bytes

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

Esencialmente el mismo enfoque que la respuesta de @ darrylyeo , pero funciona para todas las zonas horarias y utiliza una forma ligeramente diferente para llegar a 0.

[Editar] La respuesta de Darryl ha sido corregida. Sin embargo, esto es aún más corto.


3

> <> , 82 + 7 = 89 bytes

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

Pruébalo en línea!

+7 bytes por usar la bandera -t.0125para hacer que cada instrucción tome 1/80 de segundo. Cada bucle tiene 80 instrucciones, lo que hace que cada bucle dure un segundo. Debido al tiempo de cálculo, esto en realidad es más largo en la práctica.

De hecho, tuve que amortiguar esto hasta 100 hasta que vi la respuesta de @Not A Tree, que tenía 7 bytes mejor que la mía para generar las horas y minutos, recortándola por debajo de 80. También inspiraron el uso de los \/cuales se ejecutan dos veces por bucle

Cómo 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

Prima:

Una versión de una línea del mismo tamaño, 80 + 9 bytes:

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

Esto usa la -abandera para agregar marcas para las instrucciones omitidas.


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;

Las etiquetas abiertas de PHP se pueden omitir en la respuesta ahorrándole 6 bytes.
Daniel

2

Python 3 , 112 bytes

Suponiendo que usar retrasos de 1 segundo está bien, incluso si (rara vez) puede omitir un 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

ejecutar en ventana inmediata: punto de falla esperado en algún lugar alrededor de 23 millones de años (la resolución de punto flotante falla ~ 8.5e9 días)



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

No funciona en TIO.


Su programa no parece imprimirse 00:00:00en el momento en que se inicia.
user202729

Arreglado. Gracias
Noskcaj


2

Bash + coreutils + fecha GNU, 50 bytes

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

Inspirada por @Dennis, esta solución no requiere tiempo para ser cambiada. Almacena almacena el desplazamiento inicial desde ahora hasta la época UNIX (1 de enero de 1970 00:00:00 UTC), en 'o', y luego muestra [-ud opciones] (la hora actual - desplazamiento), en la fecha UTC, pero solo [+% X opción] HH: MM: SS. Esto debería funcionar en países donde la zona horaria actual no es UTC.


2

Limpio , 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 solo funciona bajo los paquetes de Windows Clean.

Agregue 3 bytes si desea que funcione en Linux, como Clean está CLK_PER_TICK :== 1000000en * nix. Si desea que sea multiplataforma, agregue 8 bytes en su lugar, ya que debe usarlos en CLK_PER_TICKlugar del valor establecido. (El enlace TIO es más grande debido a lo anterior )

Pruébalo en línea!


2

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

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

Esto se ejecuta en un bucle continuo, sin dormir, actualizando el tiempo en la misma línea en lugar de imprimir una nueva línea cada segundo. (Todavía permitido por las reglas, espero).

Esta versión un poco más larga (72 + 3 = 75 bytes) se imprime en una nueva línea cada segundo en su lugar:

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

Ambos requieren que estés en la zona horaria UTC. En Linux puede lograr esto configurando la TZvariable de entorno. Por ej TZ= python.


2

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

¡Gracias a Jo King por sugerir la -abandera! Mira su respuesta también.

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

Pruébalo en línea! (pero tendrá que esperar el tiempo de espera de 60 segundos).

Tengo que usar una función de> <> que nunca antes había necesitado: este código requiere la bandera -t.0125, que establece la velocidad de ejecución en 0.0125 segundos por tic u 80 ticks por segundo. También está la -abandera, que hace que los espacios en blanco cuenten como una marca (en algunos casos, el intérprete es un poco extraño al respecto).

Básicamente, el código mantiene un contador que se incrementa cada vez que el pez pasa por el bucle, y el resto del bucle convierte el contador al hh:mm:ssformato y lo imprime. El bucle toma exactamente 80 ticks.

Esto debería funcionar en teoría, pero en la práctica, cada tic es ligeramente más largo que 0.0125 segundos, debido al tiempo de cálculo. Cambiar el \\en la segunda línea para <<obtener tiempos más precisos en TIO.

También puede ver el código en acción en el área de juegos para peces , excepto que este intérprete trata los espacios en blanco de manera ligeramente diferente del intérprete oficial. Alternativamente, puede eliminar las banderas en TIO para hacer que el código se ejecute a la máxima velocidad, para verificar el comportamiento por momentos después de un minuto.


-1 byte reemplazando la v en la primera línea con \!y eliminando dos de los extras <. Otro par de bytes si usa la -abandera, que cuenta los espacios en blanco y las instrucciones omitidas como ticks
Jo King

@JoKing, la -abandera me dejó jugar un poco más al golf, ¡gracias! Creo que también puedes usar el \!truco en tu código: ¡ Pruébalo en línea!
No es un árbol

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

Pruébelo aquí (agota el tiempo de espera después de 60 segundos, así que configuré la suspensión en 1 para ver más resultados).

Explicación:

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, función, 94 bytes

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

Pruébelo aquí (agota el tiempo de espera después de 60 segundos, así que configuré la suspensión en 1 para ver más resultados).

Explicación:

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

Aquí hay un pequeño gif para ver que funciona según lo previsto cuando se usan 1000 ms:

ingrese la descripción de la imagen aquí


2

PHP, 59 48 bytes

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

Inspirado por la respuesta de Darren H .

Versión antigua :

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

Las etiquetas abiertas de PHP se pueden omitir en la respuesta ahorrándole 6 bytes.
Daniel

Gran pensamiento, pero 3600 debe ser 86400, de lo contrario el contador comienza a las 23:00:00, así que desafortunadamente ganas un byte, ¡aún así me ganaste por 9!
Darren H

@DarrenH Creo que depende de tu ubicación, no había pensado en eso. Estoy en GMT + 1, por eso agregué 3600, pero supongo que para los ingleses, podría eliminarlos por -3600completo, lo que ahorraría 5 bytes.
roberto06

1

Shell , 177 bytes

Tenga en cuenta que esto no es totalmente compatible con POSIX porque utiliza date +%s, que es una dateexpansión común .

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

77
Normalmente, debe dar a las personas la oportunidad de responder a su desafío antes de responderlo usted mismo. Recomiendo una semana ya que algunos solo pueden estar aquí en ciertos momentos durante la semana.
Adám

1
@ Adám No he aceptado mi respuesta, y en ese momento publiqué respuestas mucho más cortas (como la suya).
MarkWeston

1

Ruby, 192117 bytes (crédito 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

¿Como funciona?

Para usar la versión expandida (la conversión a una hora se da como una función separada y usa un formato de salida 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

66
Bienvenido en el sitio! Cada respuesta a un desafío de código de golf debe ser golfizada. Al menos debe eliminar espacios en blanco inútiles y utilizar nombres de variables de 1 carácter. Eso le daría alrededor de 120 bytes, y usar en printflugar de putspuede ahorrar unos pocos bytes más: ¡ Pruébelo en línea! . ¡Feliz golf en PPCG!
Dada

1

NARS APL, 109 63 57 caracteres

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

3 + 3 + 48 + 3 = 57 (visto las otras soluciones Apl también)

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

convierta el INT ⍵ en la cadena de dígitos de una manera si la longitud de esa cadena es 1 que agregue un '0' delante de ella

{∊⍵,¨':: '}

combinar matriz en ⍵ con la matriz '::'

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 de máquina x86-64 (llamada al sistema Linux): 78 bytes

RDTSC spin-loop timing, sys_writellamada al sistema Linux .

x86-64 no proporciona una manera conveniente de consultar la frecuencia del "reloj de referencia" RDTSC en tiempo de ejecución. Puede leer un MSR (y hacer un cálculo basado en eso) , pero eso requiere el modo kernel, o la raíz + apertura /dev/cpu/%d/msr, por lo que decidí hacer que la frecuencia sea constante en el tiempo de construcción. (Ajuste FREQ_RDTSCsegún sea necesario: cualquier constante de 32 bits no cambiará el tamaño del código de máquina)

Tenga en cuenta que las CPU x86 durante varios años han tenido una frecuencia RDTSC fija, por lo que se puede usar como fuente de tiempo, no como contador de rendimiento del ciclo de reloj principal, a menos que tome medidas para deshabilitar los cambios de frecuencia. (Hay contadores de rendimiento reales para contar los ciclos reales de la CPU). Por lo general, funciona a la frecuencia nominal de la pegatina, por ejemplo, 4.0 GHz para mi i7-6700k, independientemente del turbo o el ahorro de energía. De todos modos, este tiempo de espera ocupado no depende del promedio de carga (como lo haría un ciclo de retardo calibrado), y tampoco es sensible al ahorro de energía de la CPU.

Este código funcionará para cualquier x86 con una frecuencia de referencia inferior a 2 ^ 32 Hz, es decir, hasta ~ 4.29 GHz. Más allá de eso, el bajo 32 de la marca de tiempo se ajustaría completamente en 1 segundo, por lo que también tendría que mirar los edx32 bits altos del resultado.

Resumen :

Empuja 00:00:00\nla pila. Luego en un bucle:

  • sys_write llamada al sistema
  • ADC realiza un bucle sobre los dígitos (comenzando con el último) para incrementar el tiempo en 1. Envoltura / extracción manejada con una cmp/ cmov, con el resultado CF proporcionando la transferencia para el siguiente dígito.
  • rdtsc y guardar la hora de inicio.
  • gire rdtschasta que el delta sea> = tics por segundo de la frecuencia RDTSC.

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

Elimine el comentario de las pauseinstrucciones para ahorrar energía significativa: esto calienta un núcleo en ~ 15 grados C sin pause, pero solo en ~ 9 con pause. (En Skylake, donde pauseduerme ~ 100 ciclos en lugar de ~ 5. Creo que ahorraría más si rdtscno fuera lento, por lo que la CPU no está haciendo mucho tiempo).


Una versión de 32 bits sería unos pocos bytes más corta, por ejemplo, usar una versión de 32 bits de esta para empujar la cadena inicial 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

Y también usando 1 byte dec edx. La int 0x80llamada al sistema ABI no usaría esi / edi, por lo que la configuración del registro para syscall vs. lodsb / stosb podría ser más simple.


Podría haber usado una nanosleepllamada al sistema, pero esto fue más interesante. Con root en Linux, es posible leer el MSR correcto y obtener mediante programación la frecuencia RDTSC.
Peter Cordes

1

q / kdb + , 40 bytes

Solución:

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

Ejemplo:

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

Explicación:

Aquí se ejecutan tres comandos:

  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

Desglose de la función del 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

Prima:

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

y agregando -t 1000como argumentos al binario q.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.