Determine la versión de su idioma

51

Su desafío es escribir un políglota que funcione en diferentes versiones de su idioma. Cuando se ejecuta, siempre generará la versión del idioma.

Reglas

  • Su programa debería funcionar en al menos dos versiones de su idioma.
  • La salida de su programa solo debe ser el número de versión. No hay datos extraños.
  • Su programa puede usar cualquier método que desee para determinar el número de versión. Sin embargo, el resultado debe seguir la regla 2; sin embargo, usted determina el número de versión, la salida solo debe ser el número.
  • Su programa solo necesita generar la versión principal del idioma. Por ejemplo, en FooBar 12.3.456789-beta, su programa solo necesitaría la salida 12.
  • Si su idioma coloca palabras o símbolos antes o después del número de versión, no es necesario que los muestre, y solo el número. Por ejemplo, en C89, su programa solo necesita imprimir 89, y en C ++ 0x, su programa solo necesita imprimir 0.
  • Si se opta por imprimir los números de nombre o menor de la versión completa, por ejemplo, C89 a C99 en contraposición, se debe solamente imprimir el nombre. C89 build 32es válido, mientras error in C89 build 32: foo barque no lo es.
  • Su programa no puede usar indicadores de compilación integrados, macros o personalizados para determinar la versión del idioma.

Puntuación

Su puntaje será la longitud del código dividido por el número de versiones en las que funciona. El puntaje más bajo gana, ¡buena suerte!

MD XF
fuente
44
¿Qué es un número de versión de idioma? ¿Quién lo determina?
Wheat Wizard
99
Creo que el inverso lineal en el número de versiones no acepta respuestas con un alto número de versiones.
user202729
66
@ user202729 Estoy de acuerdo. La impresora entera versátil lo hizo bien - la puntuación fue (number of languages)^3 / (byte count).
Mego
66
¿Cuál es la versión para un idioma ? ¿No definimos un lenguaje como sus intérpretes / compiladores aquí? Digamos que hay una versión de gcc que tiene un error que con ciertos códigos C89 produce un ejecutable cuyo comportamiento viola la especificación C89, y se solucionó en la próxima versión de gcc. ¿Debería esto contar una solución válida si escribimos una base de código en este comportamiento de error para decir qué versión de gcc está usando? Está dirigido a diferentes versiones del compilador , pero NO a una versión diferente del lenguaje .
tsh
66
No entiendo esto. Primero dices "La salida de tu programa solo debe ser el número de versión". . Luego dice "Si elige imprimir el nombre completo o los números de versiones menores, por ejemplo, C89 en lugar de C99, solo debe imprimir el nombre". Entonces, ¿la primera regla no es realmente un requisito?
tubería

Respuestas:

16

En serio y en realidad , 3 bytes, puntaje 1.5

'1u

Pruébelo en línea: en realidad , en serio

Explicación:

'1u
'1   both versions: push "1"
  u  Actually: increment character to "2"; Seriously: NOP
     (both versions: implicit print)

uy Dtener funcionalidad en las cadenas solo se agregó en Actually (que es Seriously v2).

Mego
fuente
3
README.md de Actually dice que en realidad es el sucesor espiritual de Seriously. No me parece un simple cambio de versión.
Adám
77
@ Adám Si observa las ramas en el repositorio, reside seriamente en la v1rama. Antes de ser seriamente desaprobado, en realidad residía en la v2sucursal. Además, usó seriamente 1.xnúmeros de versión en lanzamientos , mientras que en realidad usa 2.x(tanto allí como en PyPI ).
Mego
115

Python 3.0 y Python 2, puntaje 6

(12 bytes, 2 versiones)

print(3/2*2)

Pruébelo en línea:

Se basa en el hecho de que Python 3+ usa la división flotante de forma predeterminada, a diferencia de Python 2, que usa la división de piso.

fireflame241
fuente
@MaltySen Your program should work in at least two versions of your language.Funciona en al menos dos versiones 2.7 y 3.0. He elegido to print the full name or minor version numbers.
fireflame241
Oh ya veo, mi mal.
Maltysen
44
¡DIOS MIO! Desarrolladores de Python pobres
Regis Portalez
44
@RegisPortalez from __future__ import division, problema resuelto :)
Łukasz Rogalski
62

Java, 189 bytes, 10 versiones, puntaje = 18.9

Las versiones compatibles: 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8y9

(¡Para puntajes anteriores, verifique el historial !)

Object v(){int i=0;try{for(String[]s={"Locale","Map","Timer","Currency","UUID","Deque","Objects","Base64","zip.CRC32C"};;i++)Class.forName("java.util."+s[i]);}finally{return i<9?"1."+i:i;}}

Ejecútelo en Java 8
Ejecútelo en Java 9 o posterior

Sin golf

Object v(){
  int v=0;
  try {
    for(
      String[] s={
        "Locale",          // 1.1
        "Map",             // 1.2
        "Timer",           // 1.3
        "Currency",        // 1.4
        "UUID",            // 1.5
        "Deque",           // 1.6
        "Objects",         // 1.7
        "Base64",          // 1.8
        "zip.CRC32C"       // 9
      };;v++)
      Class.forName("java.util."+s[v]);
  } finally {
    // Swallowing ClassNotFoundException when the version is not the last one
    // Swallowing ArrayIndexOutOfBoundsException that occurs after reaching the last version.
    return v < 9 ? "1." + v : v; // Return either an int or a String
  }
}

Tenga en cuenta que la parte del código return v<9?"1."+v:v;(anteriormente return(v<9?"1.":"")+v;) debe verificarse con cualquier versión incluida entre Java 1.0 y Java 1.3. No tengo ninguna instalación Java 1.3 o anterior a mi disposición para probar esta sintaxis.

Introducción

El control de versiones de Java tiene una historia especial. Todas las versiones han sido históricamente 1.xincluidas 1.0. Pero ... desde Java 9 en adelante y el JEP223 , el esquema de la versión ha cambiado de usar 1.xa x. Esa es la versión como se conoce internamente. Entonces tenemos la siguiente tabla (junto con el Javadoc y Wikipedia ):

 java.version | Rel. name | Product name
   property   |           |
--------------+-----------+-----------------
          1.0 | JDK 1.0   | Java 1
          1.1 | JDK 1.1   |
          1.2 | J2SE 1.2  | Java 2
          1.3 | J2SE 1.3  |
          1.4 | J2SE 1.4  |
          1.5 | J2SE 5.0  | Java 5
          1.6 | Java SE 6 | Java 6
          1.7 | Java SE 7 | Java 7
          1.8 | Java SE 8 | Java 8
          9   | Java SE 9 | Java 9

Esta entrada de desafío coincide con la columna de versión en la tabla anterior, que es lo que está contenido en la propiedad del sistema "java.version".

Explicación

El objetivo es verificar desde qué versión comienza a existir una clase, porque Java deja en desuso el código pero nunca lo elimina. El código se ha escrito específicamente en Java 1.0 para que sea compatible con todas las versiones, una vez más, porque el JDK es (en su mayoría) compatible con la fuente .

La implementación intenta encontrar los nombres de clase más cortos que introdujo cada versión. Sin embargo, para ganar bytes, es necesario tratar de elegir un subpaquete común. Hasta ahora encontré que el paquete más eficiente es java.utilporque contiene varias clases con nombres muy cortos distribuidos en todas las versiones de Java.

Ahora, para encontrar el número de versión real, los nombres de clase se ordenan introduciendo la versión. Luego trato de instanciar cada clase secuencialmente e incrementar el índice de la matriz. Si la clase existe, saltamos a la siguiente, de lo contrario, dejamos que la excepción sea detectada por el trybloque. Cuando se hace, se lanza otra excepción porque no hay más clases cuya existencia necesitemos verificar.

En cualquier caso, el hilo dejará el trybloque con una excepción. Esa excepción no se finallydetecta , sino que simplemente se pone en espera gracias al bloque, que a su vez anula la excepción en espera al devolver un valor que es "1."+vdonde vestá el índice utilizado anteriormente. También sucede que hicimos que este índice coincida con el número de versión menor de Java.

Una parte importante del golf era encontrar el nuevo nombre de clase más corto en el paquete java.util(o cualquier paquete secundario) para cada versión. Aquí está la tabla que usé para calcular ese costo.

Base cost: `java.util.` (10 chars)

 Version | Class name (cost in chars)     | Reduced name (cost in chars)
---------+--------------------------------+---------------------------
 9       | java.util.zip.CRC32C (20)      | zip.CRC32C (10)
 1.8     | java.util.Base64 (16)          | Base64 (6)
 1.7     | java.util.Objects (17)         | Objects (7)
 1.6     | java.util.Deque (15)           | Deque (5)
 1.5     | java.util.UUID (14)            | UUID (4)
 1.4     | java.util.Currency (18)        | Currency (8)
 1.3     | java.util.Timer (15)           | Timer (5)
 1.2     | java.util.Map (13)             | Map (3)
 1.1     | java.util.Locale (16)          | Locale (6)
 1.0     | <default>                      | <default>
---------+--------------------------------+---------------------------
Subtotal |                      144 chars |                  54 chars
    Base |                                |                  10 chars
   Total |                      144 chars |                  64 chars

Créditos

  • 30 bytes guardados gracias a Kevin Cruijssen (aunque lo estaba haciendo antes de leer su comentario, ¡lo prometo!).
  • 26 bytes adicionales guardados gracias a Neil (no, no estaba pensando en hacer eso)
  • ¡12 bytes gracias a Nevay y al buen pensamiento fuera de la caja !
  • 11 bytes más por Neil nuevamente y el buen finallytruco portátil .
  • 2 bytes más gracias a Kevin Cruijssen al reemplazar return(i<9?"1.":"")+i;con return i<9?"1."+i:i;(esto debe ser validado contra 1.0 o como máximo 1.3 ya que no se produjeron cambios de sintaxis antes de 1.4)

Con builtins

Si se permitieron las construcciones:

String v(){return System.getProperty("java.version");}

54 bytes para 13 versiones (de 1.0 a 12), por lo que el puntaje sería 4.1538.

Olivier Grégoire
fuente
1
@KevinCruijssen Abrí el javadoc y di clases con nombres cortos 1 por 1. Pero ... me ayudó un poco esta página: docs.oracle.com/javase/8/docs/technotes/guides/lang/…
Olivier Grégoire
1
260 bytes O tal vez 1 más, no sé si return"...sin espacio es posible en todas las versiones tbh.)
Kevin Cruijssen
1
235 bytes:String v(){return "1."+(e("time.Year")+e("nio.file.Path")+e("io.Console")+e("util.UUID")+e("text.Bidi")+e("util.Timer")+e("sql.Ref")+e("lang.Void"));}int e(String c){try{Class.forName("java."+c);return 1;}catch(Exception e){return 0;}}
Neil
3
216 bytes:String v(){int i=0;try{for(String[]s={"lang.Void","sql.Ref","util.Timer","net.URI","util.UUID","net.IDN","nio.file.Path","time.Year","lang.Module"};;i++)Class.forName("java."+s[i]);}catch(Exception e){}return"1."+i;}
Nevay
1
Ooh, me preguntaba si iterar una matriz y detectar una excepción, pero puedes elegir una mejor finally{return"1."+i;}.
Neil
22

Python , 606 bytes / 15 versiones = puntaje 40.4

-67 bytes (lol) gracias a NoOneIsHere.

Las versiones son 0.9.1, 2 (.0), 2.2, 2.2.2, 2.5.0, 2,5.1, 3 (.0), 3.1, 3.1.3, 3.2.1, 3.3, 3.4, 3.5 aa y 3.6 .

try:eval('1&2')
except:print('0.9.1');1/0
if`'\n'`<'\'\\n\'':print(2);1/0
try:from email import _Parser;print(2.2);1/0
except:0
try:eval('"go"in""')
except:print('2.2.2');1/0
try:int('2\x00',10);print(2.5);1/0
except:0
if pow(2,100)<1:print('2.5.1');1/0
if str(round(1,0))>'1':print(3);1/0
if format(complex(-0.0,2.0),'-')<'(-':print(3.1);1/0
if str(1.0/7)<repr(1.0/7):print('3.1.3');1/0
try:eval('u"abc"')
except:print('3.2.1');1/0
try:int(base=10);print(3.3);1/0
except:0
try:import enum
except:print('3.3.3');1/0
try:eval('[*[1]]')
except:print(3.4);1/0
try:eval('f""')
except:print(3.5);1/0
print(3.6)

Todo el crédito a la sorprendente respuesta de Sp3000 . La nueva línea final es necesaria.

Whee, eso fue divertido para el golf. Esto debería funcionar (sí, instalé cada una de estas versiones), pero podría haber descifrado algo accidentalmente. Si alguien encuentra un error, avíseme.

totalmente humano
fuente
... Oh, no es de extrañar. Me preguntaba por qué Sp3000 ha puesto paréntesis en cada printllamada ... ¡Gracias por hacérmelo saber!
totalmente humano
2
Puede guardar 68 bytes eliminando los tipos específicos de errores (reemplace todos los excepts con except:).
NoOneIsHere
¿ x=<string inside eval>Funcionaría esto si lo hicieras en lugar de solo evaluar el código manualmente?
Azul
@NoOneIsAquí pensé, al principio, que no podías por todas las cosas 1/0, pero luego me di cuenta. ¡Gracias!
totalmente humano
21

C ++ 14/11/17, puntaje = 147/3 = 49

Para distinguir entre C ++ 11 y C ++ 14/17, utiliza el cambio en la función predeterminada constde las constexprfunciones miembro en C ++ 14 (con crédito al ejemplo en https://stackoverflow.com/questions/23980929/ what-cambios-introducidos-en-c14-puede-potencialmente-romper-un-programa-escrito-en-c1 ). Para distinguir entre C ++ 14 y C ++ 17, utiliza el hecho de que C ++ 17 deshabilitó los trigrafos.

#include<iostream>
#define c constexpr int v
struct A{c(int){return 0;}c(float)const{return*"??="/10;}};int main(){const A a;std::cout<<11+a.v(0);}

Sin golf:

struct A {
    constexpr int v(int) { return 0; }
    constexpr int v(float) const {
        // with trigraphs, *"??=" == '#' == 35, v() returns 3
        // without trigraphs, *"??" == '?' == 63, v() returns 6
        return *("??=") / 10;
    }
};

int main() {
    const A a;
    std::cout << 11 + a.v(0);
}

(Probado con Debian gcc 7.1.0 usando -std=c++{11,14,17}.)

Daniel Schepler
fuente
1
Gran primera respuesta! Tenga en cuenta que puede jugar golf en los espacios entre el includey el <en las declaraciones de inclusión, por ejemplo #include<iostream>.
MD XF
1
Hmm ... si las reglas fueron revisadas para prohibir el uso de diferencias de biblioteca estándar (que en este caso usa indirectamente la __cplusplusmacro), entonces para distinguir C ++ 17 de C ++ 14 me inclinaría por usar el cambio en el rango para la semántica Tal vez cree clases mínimas de iterador / centinela a lo largo de las líneas de boost::integer_iteratortal manera que la conversión de centinela a iterador tenga un comportamiento "sorprendente".
Daniel Schepler
44
return 0;está implícito para mainque pueda guardar 9 bytes allí. También según wc -csu solución está usando 251 bytes y no 252 (su editor puede haber insertado una nueva línea al final).
nwp
1
Probablemente sea más corto usar la falta de trigrafos para separar c ++ 17 de c ++ 14
Papa44
1
¿Funcionaría esto? return *=>return*
Zacharý
19

EcmaScript 3/5/2015 / 2016/2017 en el navegador, 59 bytes / 5 versiones = 11.8 puntos

alert(2017-2*![].map-2010*![].fill-![].includes-!"".padEnd)

NetScape 7 informe 3 y Opera 12 informe 5

Ahorre 1 byte gracias a GOTO 0

tsh
fuente
1
Ninjaed ! ;)
Shaggy
¿Netscape 7 solo es compatible con ES3? Wow, es más viejo de lo que pensaba ...
Neil
1
Puede guardar algunos bytes usando en -!lugar de +!!donde tiene sentido (y cambiar las constantes numéricas en consecuencia).
GOTO 0
3
Tal vez alguna explicación? :)
Derek 朕 會 功夫
@Derek: vea mi solución (vinculada anteriormente) para obtener una explicación.
Shaggy
18

JavaScript (ES5 y ES6), 14 bytes / 2 versiones = 7

alert(5^"0o3")

0olas constantes octales de estilo son nuevas en ES6; ES5 convierte la cadena a la NaNque no afecta el resultado del XOR bit a bit.

Neil
fuente
13

JavaScript (ES 2, 3 y 5 - Para 8 9), 59/6 = 9,833 75/7 = 10,714

También puede enviar la solución con más versiones, incluso si tiene un puntaje ligeramente más alto que la solución de 2 versiones.

alert(9-(/./.dotAll!=0)-!"".padEnd-![].includes-![].keys-2*![].map-![].pop)

Pruébalo en línea

Comprueba la presencia de varios métodos en los prototipos Array, RegExp & String, los niega, da un valor booleano y resta ese valor booleano de un valor inicial de 9. La multiplicación de ![].mapcuentas por el hecho de que ES4 fue abandonado.

  • La dotAllpropiedad (y el sindicador relacionado ) para Expresiones regulares se introdujo en ES2018 (v9).
  • El padEndmétodo String se introdujo en ES2017 (v8).
  • El includesmétodo de matriz se introdujo en ES2016 (v7).
  • El keysmétodo Array se introdujo en ES2015 (v6).
  • El mapmétodo Array se introdujo en ES5.1 (v5).
  • El popmétodo Array se introdujo en ES3 (v3).
Lanudo
fuente
¿ES 7 o ES 8 es un número de versión válido? ¿Tal vez debería llamarse ES 201x?
tsh
1
@tsh: Sí, todavía usan números de versión; solo usan años para nombres reales .
Shaggy
9

PHP 5/7, puntaje 5.5

<?=7-"0x2";

¡3V4L en línea!

PHP 5.3.9 / 5.3.11, puntaje 10

<?='5.3.'.(9-0x0+2);

¡3V4L en línea!

La versión en línea es más larga porque las versiones antiguas de PHP en el sandbox no tienen etiquetas cortas habilitadas.

Sísifo
fuente
9

Befunge: 15 versiones de 11 bytes / 2 = 5.5

4 bytes recortados por @ Pietu1998

"89",;5-;,@  

Pruébelo en línea:
Befunge 93
Befunge 98
Utiliza el operador de punto y coma exclusivo de Befunge 98 ("saltar al siguiente punto y coma") para diferenciar las versiones. Ambos imprimirán "9". Befunge 93 ignorará los puntos y comas, restará 5 de "8" (valor restante en la parte superior de la pila), imprimirá el "3" resultante y terminará. Befunge 98, por otro lado, saltará, imprimirá "8" y terminará.

karhell
fuente
"89",;5-;,@para 11 bytes
PurkkaKoodari
@ Pietu1998 ¡Bien! Si desea publicar eso como respuesta, con gusto votaré :)
karhell
Adelante, tómalo si quieres, descubriste la ;parte.
PurkkaKoodari
@ Pietu1998 Editado en. Muchas gracias!
karhell
Para su información, logré reducirlo a 7 bytes, adoptando un enfoque diferente. Enlace
James Holderness
7

Pyth 4/5 - 6 bytes / 2 versiones = 3

  5 ;4

En Pyth 5, se ignora una cantidad uniforme de espacios al comienzo de la línea para su uso en la sangría, mientras que en Pyth 4, simplemente actúa como un solo espacio y evita imprimir 5. En Pyth 4, los puntos y comas solo terminan las declaraciones, lo que permite 4que se imprima, mientras que en Pyth 5, un espacio y un punto y coma hacen que el resto de la línea sea un comentario.

Maltysen
fuente
11
¿Quién sabía que Pyth tenía versiones?
Erik the Outgolfer
7

Python 3 y Python 2.0, 18 bytes, puntaje 18/2 = 9

print(3-round(.5))

Redondeo bancario en Python 3, redondeo estándar en Python 2.

Pruébelo en línea: ¡Python 3!

Pruébelo en línea: ¡Python 2!

Stephen
fuente
wow, siempre he visto personas que diferencian a Python 2 y 3 por división
phuclv
@ LưuVĩnhPhúc la división de pozos es más golfista, por eso: P
Stephen
7

Cúbicamente, 4 bytes, puntaje 4 / ∞

B3%0

Funciona en todas las versiones, su sistema tiene suficiente memoria para ejecutarse. No competir porque es cojo. Válido según esta meta publicación .

Básicamente, B3 gira una fila desde la cara izquierda hacia la cara superior. F3 funcionaría igual de bien, como lo haría F₁3 o B₁3. Como una fila en Cubically 3x3x3 es tres cubelets por un cubelet, esto pone tres 1en la cara superior, dándole una suma de caras de 3. %0imprime esa suma de caras superiores, imprimiendo 3 para Cubically 3 x3x3.

En Cubically 4x4x4, las filas son cubos 4x1. Pone 4 1's en la cara superior, produciendo una suma de 4.

MD XF
fuente
99
¿No debería ser el puntaje 4 / ∞?
nwp
7

Código de máquina x86 de 16/32/64 bits: 11 bytes, puntaje = 3.66

Esta función devuelve el modo actual (tamaño de operando predeterminado) como un entero en AL. Llámalo desde C con firmauint8_t modedetect(void);

Código de máquina NASM + lista de fuentes (que muestra cómo funciona en modo de 16 bits, ya que BITS 16le dice a NASM que arme los mnemónicos de fuente para el modo de 16 bits).

 1          machine      global modedetect
 2          code         modedetect:
 3 addr     hex          BITS 16

 5 00000000 B040             mov    al, 64
 6 00000002 B90000           mov    cx, 0       ; 3B in 16-bit.  5B in 32/64, consuming 2 more bytes as the immediate
 7 00000005 FEC1             inc    cl          ; always 2 bytes.  The 2B encoding of inc cx would work, too.
 8                       
 9                           ; want: 16-bit cl=1.   32-bit: cl=0
10 00000007 41               inc    cx       ; 64-bit: REX prefix
11 00000008 D2E8             shr    al, cl   ; 64-bit: shr r8b, cl doesn't affect AL at all.  32-bit cl=1.  16-bit cl=2
12 0000000A C3               ret
# end-of-function address is 0xB, length = 0xB = 11

Justificación :

El código de máquina x86 no tiene oficialmente números de versión, pero creo que esto satisface la intención de la pregunta al tener que producir números específicos, en lugar de elegir lo que es más conveniente (que solo toma 7 bytes, ver más abajo).

La CPU x86 original, la Intel 8086, solo admitía código de máquina de 16 bits. 80386 introdujo el código de máquina de 32 bits (utilizable en modo protegido de 32 bits y más tarde en modo compatible bajo un sistema operativo de 64 bits). AMD introdujo el código de máquina de 64 bits, utilizable en modo largo. Estas son versiones del lenguaje de máquina x86 en el mismo sentido que Python2 y Python3 son versiones de idiomas diferentes. En su mayoría son compatibles, pero con cambios intencionales. Puede ejecutar ejecutables de 32 o 64 bits directamente en un núcleo del sistema operativo de 64 bits de la misma manera que podría ejecutar los programas Python2 y Python3.

Cómo funciona:

Comenzar con al=64. Cambie a la derecha en 1 (modo de 32 bits) o 2 (modo de 16 bits).

  • 16/32 vs. 64 bits: Las 1-byte inc/ deccodificaciones son prefijos rex en 64 bits ( http://wiki.osdev.org/X86-64_Instruction_Encoding#REX_prefix ). REX.W no afecta en absoluto algunas instrucciones (por ejemplo, una jmpo jcc), pero en este caso para conseguir 16/32/64 quería inc o DEC ecxen lugar de eax. Eso también establece REX.B, lo que cambia el registro de destino. Pero afortunadamente podemos hacer que eso funcione, pero configurar las cosas para que no sea necesario cambiar de 64 bits al.

    Las instrucciones que se ejecutan solo en modo de 16 bits podrían incluir a ret, pero no me pareció necesario o útil. (Y haría imposible alinearse como un fragmento de código, en caso de que quisiera hacerlo). También podría estar jmpdentro de la función.

  • 16 bits frente a 32/64: los inmediatos son de 16 bits en lugar de 32 bits. Cambiar los modos puede cambiar la longitud de una instrucción, por lo que los modos de 32/64 bits decodifican los siguientes dos bytes como parte de la instrucción inmediata, en lugar de una instrucción separada. Mantuve las cosas simples usando una instrucción de 2 bytes aquí, en lugar de descodificar la sincronización de modo que el modo de 16 bits decodificaría desde límites de instrucción diferentes a 32/64.

    Relacionado: El prefijo de tamaño de operando cambia la longitud del inmediato (a menos que sea un signo de 8 bits inmediato extendido), al igual que la diferencia entre los modos de 16 bits y 32/64 bits. Esto hace que la decodificación de longitud de instrucción sea difícil de hacer en paralelo; Las CPU Intel tienen puestos de decodificación LCP .


La mayoría de las convenciones de llamadas (incluidas las psABI x86-32 y x86-64 System V) permiten que los valores de retorno estrechos tengan basura en los bits altos del registro. También permiten clobbering CX / ECX / RCX (y R8 para 64 bits). IDK si eso era común en las convenciones de llamadas de 16 bits, pero este es el código golf, por lo que siempre puedo decir que es una convención de llamadas personalizada de todos modos.

Desmontaje de 32 bits :

08048070 <modedetect>:
 8048070:       b0 40                   mov    al,0x40
 8048072:       b9 00 00 fe c1          mov    ecx,0xc1fe0000   # fe c1 is the inc cl
 8048077:       41                      inc    ecx         # cl=1
 8048078:       d2 e8                   shr    al,cl
 804807a:       c3                      ret    

Desmontaje de 64 bitsPruébelo en línea! ):

0000000000400090 <modedetect>:
  400090:       b0 40                   mov    al,0x40
  400092:       b9 00 00 fe c1          mov    ecx,0xc1fe0000
  400097:       41 d2 e8                shr    r8b,cl      # cl=0, and doesn't affect al anyway!
  40009a:       c3                      ret    

Relacionado: mi x86-32 / x86-64 polyglot machine-code Q&A en SO.

Otra diferencia entre 16 bits y 32/64 es que los modos de direccionamiento se codifican de manera diferente. por ejemplo lea eax, [rax+2]( 8D 40 02) decodifica como lea ax, [bx+si+0x2]en modo de 16 bits. Obviamente, esto es difícil de usar para el golf de código, especialmente desde entonces e/rbxy e/rsise conservan en muchas convenciones de llamadas.

También consideré usar el byte 10 mov r64, imm64, que es REX + mov r32,imm32. Pero como ya tenía una solución de 11 bytes, sería, en el mejor de los casos, igual (10 bytes + 1 para ret).


Código de prueba para el modo de 32 y 64 bits. (Realmente no lo he ejecutado en modo de 16 bits, pero el desmontaje le dice cómo se decodificará. No tengo un emulador de 16 bits configurado).

; CPU p6   ;  YASM directive to make the ALIGN padding tidier
global _start
_start:
    call   modedetect
    movzx  ebx, al
    mov    eax, 1
    int    0x80        ; sys_exit(modedetect());

align 16
modedetect:
BITS 16
    mov    al, 64
    mov    cx, 0       ; 3B in 16-bit.  5B in 32/64, consuming 2 more bytes as the immediate
    inc    cl          ; always 2 bytes.  The 2B encoding of inc cx would work, too.

    ; want: 16-bit cl=1.   32-bit: cl=0
    inc    cx       ; 64-bit: REX prefix
    shr    al, cl   ; 64-bit: shr r8b, cl doesn't affect AL at all.  32-bit cl=1.  16-bit cl=2
    ret

Este programa de Linux sale con exit-status = modedetect(), así que ejecútelo como ./a.out; echo $?. Ensamble y vincule en un binario estático, por ejemplo

$ asm-link -m32 x86-modedetect-polyglot.asm && ./x86-modedetect-polyglot; echo $?
+ yasm -felf32 -Worphan-labels -gdwarf2 x86-modedetect-polyglot.asm
+ ld -melf_i386 -o x86-modedetect-polyglot x86-modedetect-polyglot.o
32
$ asm-link -m64 x86-modedetect-polyglot.asm && ./x86-modedetect-polyglot; echo $?
+ yasm -felf64 -Worphan-labels -gdwarf2 x86-modedetect-polyglot.asm
+ ld -o x86-modedetect-polyglot x86-modedetect-polyglot.o
64

## maybe test 16-bit with BOCHS somehow if you really want to.

7 bytes (puntuación = 2,33) si puedo numerar las versiones 1, 2, 3

No hay números de versión oficiales para diferentes modos x86. Solo me gusta escribir respuestas. Creo que violaría la intención de la pregunta si solo llamara a los modos 1,2,3 o 0,1,2, porque el punto es forzarlo a generar un número inconveniente. Pero si eso estaba permitido:

 # 16-bit mode:
42                                  detect123:
43 00000020 B80300                      mov ax,3
44 00000023 FEC8                        dec al
45                                  
46 00000025 48                          dec ax
47 00000026 C3                          ret

Que decodifica en modo de 32 bits como

08048080 <detect123>:
 8048080:       b8 03 00 fe c8          mov    eax,0xc8fe0003
 8048085:       48                      dec    eax
 8048086:       c3                      ret    

y 64 bits como

00000000004000a0 <detect123>:
  4000a0:       b8 03 00 fe c8          mov    eax,0xc8fe0003
  4000a5:       48 c3                   rex.W ret 
Peter Cordes
fuente
No estoy seguro de que esto cuente como versiones diferentes . ¿No se correlacionan simplemente con diferentes configuraciones del sistema?
Uriel
1
@Uriel: Ejecutar un bloque de código de máquina con la CPU en modo de 16 bits, modo de 32 bits o modo de 64 bits es el código de máquina equivalente a ejecutar python2vs. python3intérpretes en el mismo programa Python. Las nuevas CPU x86 siempre incluyen un modo que es compatible con las CPU más antiguas (esta es su única excusa para usar un formato de código de máquina tan complicado y difícil de decodificar), pero el modo protegido de 32 bits de 386 y el modo largo de x86-64 realmente son Nuevas versiones del código de máquina x86. El modo largo incluso eliminó algunos códigos de operación, haciéndolos inválidos.
Peter Cordes
5

Brachylog / Brachylog v1 , 5/2 = 2.5

2,1hw

Pruébalo en línea! (Brachylog)

Pruébalo en línea! (Brachylog v1)

Explicación para Brachylog:

?2,1hw.
?2      Unify ? (input) with 2 (no input so it succeeds)
  ,1    Append 1 (21)
    h   First element/head (2)
     w. Write to STDOUT and unify with output (not displayed)

Explicación para Brachylog v1:

?2,1hw.
?2      Unify ? (input) with 2 (no input so it succeeds)
  ,     Break implicit unification/logical AND
   1h   Take first element/head of 1 (1)
     w. Write to STDOUT and unify with output (not displayed)
Erik el Outgolfer
fuente
¡Excelente! Como nota al margen, 2,1en Brachylog v2 no construye la lista [2,1]( 2;1would), sino el número 21(que no cambia la forma en que pretendía que su respuesta funcionara).
Fatalize
@Fatalize Ooh, gracias, confundí eso con Jelly ...
Erik the Outgolfer
@Fatalize BTW 2;1no habría funcionado en Brachylog v1 como ;lógico O allí.
Erik the Outgolfer
5

C89 / C99, 25 bytes, 2 versiones, puntaje = 12.5

#include <stdio.h>

int main() {
    int v = 11 //**/ 11
            + 88;
    printf("C%d\n", v);
    return 0;
}

// los comentarios de estilo no se reconocen en C89.

Versión de golf:

v(){return 20//**/2
+79;}

Pruébelo en línea: C89 , C99

nwellnhof
fuente
reemplazar int v()con main(), es más corto y en realidad se compilará como un programa completo!
Andrea
@Andrea Gracias. AFAIK, está permitido publicar funciones o programas completos.
nwellnhof
Estás en lo correcto.
Andrea
5

Perl 5 y Perl 6, 23 bytes 19 bytes, puntaje 9.5

print 6-grep '.',''

La grepprimera operación de Perl 5 siempre se trata como una expresión regular, no así en Perl 6.

Joshua
fuente
el puntaje es 19/2 = 9.5
Daniel Vestøl
5

Bash, las 4 versiones, 72 71 32 bytes ⇒ puntuación = 8

s=$'\ua\xa\n';expr 5 - ${#s} / 2

Este código utiliza diferentes interpretaciones de $'...'cadenas en cada versión de Bash.
Emite el número de versión principal, y eso es todo.

Doc encontrado aquí .

Sin golf:

s=$'\ua\xa\n';
expr 5 - ${#s} / 2
# Bash v4 sees three linefeeds => length of 3 => 5 - 3 / 2 = 4
# Bash v3 sees the literal '\ua' + two linefeeds: 5 chars in length
#    => 5 - 5 / 2 = 3
# Bash v2 sees '\ua\xa' + linefeed, 7 chars: 5 - 7 / 2 = 2
# Bash v1 does not even interpret $'..' strings, and sees literally '$\ua\xa\n' of length 9 => 5 - 9 / 2 = 1

Esta respuesta es una conjetura; Solo lo probé en bash 4 y 3, pero también debería funcionar en otras versiones.

Avíseme si lo hace / no, intentaré con otras versiones tan pronto como las tenga disponibles.

-1 char gracias a Jens.
-29 bytes gracias a Digital Trauma (toda la expridea)!

joH1
fuente
La gramática de shell no requiere un ;;en la última alternativa. Úselo ;para afeitarse un byte.
Jens
1
Acabo de probar esto en bash-2.05a (compilado ahora para Cygwin), e informa incorrectamente "3", no "2" :(
Jason Musgrove
1
la $'\xNfunción de interpretación parece haberse agregado en 2.01.1 ... Tendré que actualizar mi respuesta. Trabajando en ello
joH1
¿Puedo pedirte que pruebes esto? s="$'\ua\xa\n'";case ${#s} in 3)echo 4;;5)echo 3;;7)echo 2;;9)echo 1;esac
joH1
1
Es posible que pueda jugar golf a algo así s=$'\ua\xa\n';expr 5 - ${#s} / 2. Esto funciona en v3 y v4. No tengo versiones anteriores que funcionen para probar en este momento.
Trauma digital
4

R, versiones 2 y 3, puntuación: 10,5 puntos

cat(exists("cite")+2)

Este comando regresa 2para R 2.xx y 3para R 3.xx La función citese agregó en R versión 3.0.0. Por lo tanto, el comando exists("cite")vuelve FALSEpara R 2.xx y TRUEpara R 3.xx

R, todas las versiones (1, 2 y 3), puntaje: 12 puntos

e=exists;cat(e("cite")+e("eapply")+1)

La función eapplyse introdujo en R 2.0.0.

Sven Hohenstein
fuente
R.version$major. 15 caracteres No lo hago desde cuando existe.
Rui Barradas
@RuiBarradas Permítanme citar el OP: "Es posible que su programa no use indicadores incorporados, macro o compiladores personalizados para determinar la versión del idioma " .
Sven Hohenstein
Ok, lo siento, me perdí esa parte. ¿Debo eliminar el comentario?
Rui Barradas
@RuiBarradas No hay problema. No necesitas eliminar el comentario.
Sven Hohenstein
Debe manejar imprimir el resultado. Actualmente, cuando se ejecuta como un programa completo, esto no imprime nada.
JAD
4

Python , 196 bytes / 16 versiones = puntaje 12.25

Las versiones son 1.5, 1.6, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5 y 3.6
Lamentablemente tuve que dejar de lado 2.7 porque no hay ningún módulo en (por lo que puedo decir) que no están en 2.6 pero están en 3.0.

i=15
try:
 for m in'os.atexit.os.os.os.warnings.cgitb.heapq.collections._ast.abc.queue.os.os.os.importlib.argparse.lzma.asyncio.zipapp.secrets.'.split('.'):__import__(m);i=i+1
except:print(i/10.)

Recorremos un montón de módulos que se introdujeron en diferentes versiones de python, y en el primer error dejamos y devolvemos la versión. Los espacios entre las versiones principales se completan importando repetidamente os. La prueba para python 1.5 se basa en string.splitno estar presente hasta 1.6.

Gracias a la respuesta de Olivier Grégoire por la idea de probar nuevas clases / módulos en un bucle.

Ahora finalmente probé en todas las versiones relevantes de python ... que requería editar el código fuente 1.5 para que se compilara ...

g. cohete
fuente
4

Archivo por lotes de Windows , 35 bytes / 2 versiones = puntaje 17.5

@if /i Z==z @echo NT&exit
@echo DOS

Imprime DOSen MS-DOS (duh) y NTen Windows NT. (duh)

Ahora, para alguna explicación.

Windows ha tenido secuencias de comandos por lotes desde tiempos de MS-DOS y no ha cambiado mucho desde entonces. Sin embargo, cuando apareció Windows NT , Microsoft cambió el intérprete predeterminado para las secuencias de comandos por lotes, de COMMAND.COMa cmd.exe(ahora también permite la extensión .cmdcomo alternativa al original .bat).

Con eso, también implementaron algunos cambios , como la /ibandera para ignorar las mayúsculas y minúsculas en los condicionales. Es decir, si bien Z==zes falso, /i Z==zes cierto.

Explotamos que DOS no tenía mayúsculas y minúsculas y comparamos mayúsculas Zcon minúsculas z. Al usar la /ibandera, terminamos con un Z==z(falso) condicional en DOS y z==z(verdadero) en NT.

Ahora, me doy cuenta de que el desafío especifica que se debe imprimir un número de versión. Pero, hasta donde yo sé, no hay un 'número de versión' para las secuencias de comandos por lotes, por lo que esto es lo más cercano que podría obtener.


Probado en Windows 10, DOSBox y vDos:

Windows 10

Windows 10

(ejecutar con cmd /kpara evitar que la ventana se cierre exit)

DOSBox:

DOSBox

vDos:

vDos

Matheus Avellar
fuente
Windows 7es más corto que Windows NT.
user202729
2
@ user202729 Supongo, pero de nuevo, 7no es realmente una versión de idioma, ha sido la misma en todos los Windows desde 3.1. Así que no pensé que sería muy justo llamarlo un 7momento en que quizás debería serlo3.1
Matheus Avellar
3

Wolfram Language / Mathematica 10/11, 37 bytes / 2 versiones = 18.5

Considerar (Length@DateRange[{1},{1}][[1]]+27)/3, a 37 bytes y trabajar con 2 versiones, me da una puntuación de 18.5.

In[1]:= $Version

Out[1]= "10.4.1 for Microsoft Windows (64-bit) (April 11, 2016)"

In[2]:= (Length@DateRange[{1}, {1}][[1]] + 27)/3

Out[2]= 10

y

In[1]:= $Version

Out[1]= "11.1.1 for Microsoft Windows (64-bit) (April 18, 2017)"

In[2]:= (Length@DateRange[{1}, {1}][[1]] + 27)/3

Out[2]= 11

Estoy seguro de que hay una forma más eficiente, pero la discrepancia entre la salida de DateRange me mordió en el trasero recientemente, por lo que estaba configurado para usar eso.

Como seguimiento, alguien probablemente podría aprovechar la Length@DateRange[{1}, {1}][[1]]evaluación 1en las versiones de Mathematica 1- ~ 8, pero no tuve tiempo de incorporar eso.

usuario6014
fuente
2
Bastante seguro de que su respuesta no cumple con los requisitos de la solicitud, es decir, la última regla debido a que usa $Version:Your program may not use a builtin, macro, or custom compiler flags to determine the language version.
Amndeep7
77
Solo estoy usando $Versionpara demostrar que muestra el resultado correcto en la versión correcta, $Versionno es parte de mi respuesta ...
user6014
Todo buen amigo: la cosa es que estás usando algo como $VersionNumber, pero en cambio lo estás llamando $Version. En mi opinión, aunque la esencia de su programa es el Length@DateRangematerial, eso no funcionaría sin $Versionsolo proporcionar la información de la versión completa que luego procesa, lo que por lo tanto viola las reglas.
Amndeep7
44
@ Amndeep7 El envío es el código de 37 bytes incluido en el primer párrafo. Los bloques de código son solo demostraciones de salida.
PurkkaKoodari
3
Explicación: Uso de diferentes formatos de tiempo en diferentes versiones. Eso se puede jugar más a {1} Tr[1^#&@@%~DateRange~%]/3+9(31 bytes), o incluso 7+Length@Now(12 bytes)
user202729
3

Ruby 1.xy 2.x, 20 bytes, puntaje 10

p [].to_h&&2rescue 1

Basado en el to_hmétodo que se introdujo en la Arrayclase en Ruby 2.

Philipp Frank
fuente
Buena primera respuesta. No tengo 1.x a mano para probar, pero p [].to_h&&2rescue 1es un poco más corto.
manatwork
@manatwork Genial, ahorra 3 bytes y funciona de maravilla
Philipp Frank
3

Erlang, 180 bytes, 11 versiones, puntaje 16.36

20-length([A||A<-[schedulers,c_compiler_used,cpu_topology,snifs,dynamic_trace,port_count,nif_version,end_time,max_heap_size,atom_count],{'EXIT',_}<-[catch erlang:system_info(A)]]).

Con sangría y saltos de línea:

20-length([A||A<-
                  [schedulers,
                   c_compiler_used,
                   cpu_topology,
                   snifs,
                   dynamic_trace,
                   port_count,
                   nif_version,
                   end_time,
                   max_heap_size,
                   atom_count],
              {'EXIT',_}<-[catch erlang:system_info(A)]]).

Probado en una versión menor de cada versión principal desde 10:

  • R10B-9
  • R11B-5
  • R12B-5
  • R13B04
  • R14B04
  • R15B03
  • R16B03
  • 17.5.6.2
  • 18.2.1
  • 19,2
  • 20,0

La idea es que cada versión principal haya agregado al menos un nuevo argumento permitido para la función erlang:system_info, así que intentemos con los de la lista, cuente cuántos fallan y restemos el número de fallas de 20, que es la versión actual.

legoscia
fuente
3

Julia 0.4, 0.5, 46 bytes, puntaje 22

f(::ASCIIString)=.4
f(::String)=.5
f()=f("")

Julia ha cambiado el nombre de tipo de los tipos de cadena concretos y abstractos en muchas versiones.

Este código en particular aprovecha:

Julia 0.4 :

  • El hormigón es ASCIIString,
  • Resumen es oficialmente AbstractString,
  • El resumen tiene un alias en desuso String.
  • El concreto es más específico que el abstracto, por lo que gana el despacho

Julia 0.5 :

  • El hormigón es oficialmente String,
  • El hormigón tiene un alias en desuso para ASCIIString,
  • El resumen es AbstractString, (aunque eso no importa aquí)
  • Como se han definido dos métodos para el tipo de cadena concreta, este último sobrescribe al primero.

Vea también mi nueva solución más efectiva basada en diferentes principios

Lyndon White
fuente
3

Japt (1 y 2), 8 6/2 = 4 3

'1r\S2

Prueba v1  |   Prueba v2

  • 2 bytes guardados gracias a Oliver

Explicación

Antes de v2, Japt usaba una sintaxis RegEx personalizada, por lo que podemos aprovechar eso.

'1

El número 1 como una cadena.

 r  2

Reemplace ( r) el siguiente con a 2.

\S

Japt 2 ve esto como el RegEx /\S/g, que coincide con el 1. Japt 1 ignora el \carácter de escape y solo ve el S, que es la constante de Japt para un personaje espacial y, obviamente, no coincide con el 1.

Lanudo
fuente
3

Befunge, puntuación = 3.5

7 bytes, 2 versiones

"]"'b.@

Pruébelo en línea en Befunge-93
Pruébelo en línea en Befunge-98

"]"es un literal de cadena en ambas versiones, que empuja 93 (el valor ASCII de [) en la pila. 'bes un carácter literal en Befunge-98, empujando 98 (el valor ASCII de b), pero esas son instrucciones no válidas en Befunge-93, por lo que simplemente se ignoran. Así terminamos con 93 en la parte superior de la pila en Befunge-93 y 98 en Befunge-98. .@escribe el valor en la parte superior de la pila y luego sale.

James Holderness
fuente
]"[email protected]'o ][email protected]'también trabajar
MildlyMilquetoast
3

Ruby 1.x (<1.9) y 2.x, 10 8 bytes, puntaje = 4

$><<?2%7

Intentalo:

Esto funciona explotando los diferentes comportamientos ?xentre Ruby 1.xy 2.x. En Ruby 1.x, ?A(por ejemplo) devuelve 65(el valor ASCII del carácter A), pero en Ruby 2.0 devuelve la cadena de un carácter "A".

El código anterior es equivalente a esto:

val = ?2
$> << val % 7

En Ruby 1.x (<1.9), el valor de vales 50(el valor ASCII del personaje 2), un Fixnum. Fixnum#%es el operador de módulo, por lo que 50 % 7devuelve 1.

En Ruby 2.x, vales la cadena "2". String#%es una versión infija de sprintf, por lo que "2" % 7es equivalente a sprintf("2", 7), donde "2"está la cadena de formato. Como la cadena de formato no contiene ninguna secuencia de formato (por ejemplo %d), los argumentos posteriores se descartan y "2"se devuelven.

Finalmente, $>es un alias para $stdout, por lo que $> << ...imprime el resultado.

Jordán
fuente
1
¡Ooh genial! Estaba tratando de hacer algo como ?A==66?1:2antes de encontrar tu respuesta
Piccolo
3

Python 2 y Python 3 , 36 34 bytes, puntaje 18 17

print(str(hash(float('-inf')))[1])

En Python 2 , el hash de infinito negativo es -271828 pero en Python 3 es -314159. Editar: Guardado 2 bytes, 1 punto de puntuación, gracias a @ArBo.

Neil
fuente
entrecerrar los ojos ¿Es esto una cosa deliberada de e vs pi?
Jo King
@JoKing Sí; aparentemente cuando hashse corrigió por primera vez para trabajar en infinitos de punto flotante, el desarrollador relevante usó pi * 1e5 y e * -1e5 como valores hash. En algún momento en Python 3, el valor de has para el infinito negativo se cambió para ser la negación del valor de hash para el infinito.
Neil
2

Python 3 , Python 2 , puntaje 17.5

(35 bytes, 2 versiones)

try:exec("print 2")
except:print(3)

Python 2 , 35 bytes

Pruébalo en línea!

Python 3 , 35 bytes

Pruébalo en línea!

Guardado 5 bytes gracias a ETHproductions

¡No es una buena respuesta de código de golf, pero es un cambio masivo!

jferard
fuente
Hmm, ¿puedes poner cada declaración en la línea anterior? Es decirtry:exec("print 2")\nexcept:print(3)
ETHproductions
@ETHproductions gracias! No esperaba ganar, así que estaba un poco distraído. Principalmente quería centrarme en el cambio masivo entre Python 2 y 3.
jferard