Определите версию вашего языка


51

Ваша задача - написать полиглот, который работает на разных версиях вашего языка. При запуске он всегда выводит языковую версию.

правила

  • Ваша программа должна работать как минимум в двух версиях вашего языка.
  • Вывод вашей программы должен быть только номером версии. Никаких посторонних данных.
  • Ваша программа может использовать любой метод для определения номера версии. Однако выходные данные должны соответствовать правилу 2; однако вы определяете номер версии, вывод должен быть только номер.
  • Ваша программа должна выводить только основную версию языка. Например, в FooBar 12.3.456789-beta вашей программе нужно будет только вывести 12.
  • Если ваш язык помещает слова или символы до или после номера версии, вам не нужно выводить их, а только номер. Например, в C89 ваша программа должна только печатать 89, а в C ++ 0x ваша программа должна только печатать 0.
  • Если вы решите напечатать полное имя или вспомогательные номера версий, например, C89, а не C99, он должен печатать только имя. C89 build 32действует, пока error in C89 build 32: foo barнет.
  • Ваша программа не может использовать встроенные, макро или пользовательские флаги компилятора для определения языковой версии.

счет

Ваша оценка будет равна длине кода, деленной на количество версий, в которых он работает. Победа с наименьшим количеством очков, удачи!


4
Что такое номер языковой версии? Кто это определяет?
Пшеничный волшебник

9
Я думаю, что обратно-линейный по количеству версий не приветствует ответы с большим количеством версий.
user202729

6
@ user202729 Согласен. Универсальный принтер Integer сделал это хорошо - оценка была (number of languages)^3 / (byte count).
Mego

6
Какая версия для языка ? Разве мы не определяем язык как его интерпретаторы / компиляторы здесь? Допустим, есть версия gcc, в которой есть ошибка, при которой с некоторыми кодами C89 он создает исполняемый файл, поведение которого нарушает спецификацию C89, и это было исправлено в следующей версии gcc. Должно ли это считаться правильным решением, если мы напишем фрагмент кода на основе этого поведения ошибки, чтобы сказать, какую версию gcc использует? Это нацеливание на другую версию компилятора , но НЕ на другую версию языка .
TSH

6
Я не понимаю этого. Сначала вы говорите: «Вывод вашей программы должен быть только номером версии». , Затем вы говорите: «Если вы решите напечатать полное имя или вспомогательные номера версий, например, C89, а не C99, он должен печатать только имя». То есть первое правило не является обязательным требованием?
труба

Ответы:


16

Серьезно и актуально , 3 байта, оценка 1,5

'1u

Попробуйте онлайн: на самом деле , серьезно

Объяснение:

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

uи Dналичие функциональности в строках было добавлено только в Actually (который является Серьезно v2).


3
На самом деле README.md говорит, что на самом деле является духовным преемником всерьез. Для меня это не похоже на изменение версии.
Адам

7
@ Adám Если вы посмотрите на ветви в хранилище, серьезно находится в v1ветви. До того, как серьезно осуждается, фактически проживал в v2филиале. Кроме того, серьезно используются 1.xномера версий в выпусках , а на самом деле используются 2.x(как там, так и на PyPI ).
Mego

115

Python 3.0 и Python 2, оценка 6

(12 байт, 2 версии)

print(3/2*2)

Попробуйте онлайн:

Полагается на тот факт, что Python 3+ по умолчанию использует деление с плавающей запятой, в отличие от Python 2, который использует деление по полу.


@MaltySen Your program should work in at least two versions of your language.Работает как минимум в двух версиях 2.7 и 3.0. Я выбрал to print the full name or minor version numbers.
fireflame241

О, я вижу, мой плохой.
Maltysen

4
О, МОЙ БОГ! Бедные разработчики Python
Реджис Порталез

4
@RegisPortalez from __future__ import division, проблема решена :)
Лукаш Рогальский

62

Java, 189 байт, 10 версий, оценка = 18,9

Поддерживаемые версии: 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8и9

(Для предыдущих оценок, проверьте историю !)

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

Запустите его на Java 8
Запустите его на Java 9 или новее

Ungolfed

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

Обратите внимание, что часть кода return v<9?"1."+v:v;(ранее return(v<9?"1.":"")+v;) необходимо проверять на соответствие любой версии между Java 1.0 и Java 1.3. У меня нет установки Java 1.3 или более ранней версии для тестирования этого синтаксиса.

Введение

У версий Java есть особая история. Все версии исторически были в 1.xтом числе 1.0. Но ... начиная с Java 9 и JEP223 , схема версий изменилась с использования 1.xна x. Это версия как внутренне известная. Итак, у нас есть следующая таблица (вместе с Javadoc и 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

Эта запись вызова соответствует столбцу версии в таблице выше, которая содержится в системном свойстве "java.version".

объяснение

Цель состоит в том, чтобы проверить, с какой версии класс начинает существовать, потому что Java не поддерживает код, но никогда не удаляет его. Код был специально написан на Java 1.0, чтобы быть совместимым со всеми версиями, опять же, потому что JDK (в основном) совместим с исходным кодом .

Реализация пытается найти кратчайшие имена классов, представленные в каждой версии. Однако, чтобы получить байты, нужно попытаться выбрать общий подпакет. До сих пор я обнаружил, что наиболее эффективный пакет состоит в том, java.utilчто он содержит несколько действительно коротко названных классов, распределенных по всем версиям Java.

Теперь, чтобы найти фактический номер версии, имена классов отсортированы по версии. Затем я пытаюсь последовательно создавать каждый класс и увеличивать индекс массива. Если класс существует, мы переходим к следующему, в противном случае мы позволяем исключению быть пойманным try-блоком. Когда это сделано, выдается еще одно исключение, потому что больше нет классов, существование которых мы должны проверить.

В любом случае поток покинет try-блок с исключением. Это исключение не перехвачено, а просто поставить на удержание благодаря finally-блоку, который , в свою очередь , переопределяет исключение на удержании на самом деле возвращает значение , которое "1."+vгде vнаходится индекс , используемый ранее. Также бывает, что мы сделали этот индекс соответствующим младшему номеру версии Java.

Важной частью игры в гольф было нахождение кратчайшего нового имени класса в пакете java.util(или любом детском пакете) для каждой версии. Вот таблица, которую я использовал для расчета этой стоимости.

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

кредиты

  • 30 байтов сэкономлено благодаря Кевину Круйссену (хотя я делал это прежде, чем прочитал его комментарий, обещаю!).
  • 26 дополнительных байтов сохранены благодаря Нейлу (нет, я не думал об этом)
  • 12 байтов благодаря Nevay и хорошему мышлению "из коробки"!
  • Еще 11 байтов от Нила и хороший переносной finallyтрюк.
  • 2 более байт благодаря Kevin Cruijssen путем замены return(i<9?"1.":"")+i;с return i<9?"1."+i:i;(это должно быть подтверждено против 1,0 или максимум 1,3 , поскольку каких - либо изменений синтаксиса произошло до 1.4)

Со встроенными

Если встроенные были разрешены:

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

54 байта для 13 версий (от 1,0 до 12), поэтому оценка будет 4,1538.


1
@KevinCruijssen Я открыл javadoc и провел классы с короткими именами 1 на 1. Но ... мне немного помогла эта страница: docs.oracle.com/javase/8/docs/technotes/guides/lang/…
Olivier Грегуар

1
260 байт или, может быть, еще 1, не знаю, возможно ли return"...без пробела во всех версиях tbh.)
Кевин Круйссен

1
235 байтов: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;}}
Нил

3
216 байт: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
Ох, я действительно задумывался об итерации массива и перехвате исключения, но вы можете сделать это лучше finally{return"1."+i;}.
Нил

22

Python , 606 байт / 15 версий = оценка 40,4

-67 байт (смеется) благодаря NoOneIsHere.

Версии: 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 и 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)

Все заслуги в удивительном ответе Sp3000 . Конечный перевод строки необходим.

Ух, это было весело для гольфа. Это должно работать (да, я установил каждую из этих версий), но я мог случайно что-то испортить. Если кто-нибудь найдет ошибку, пожалуйста, дайте мне знать.



... О, не удивительно. Мне было интересно, почему Sp3000 ставит скобки в каждом printвызове ... Спасибо, что сообщили мне знать!
полностью человек

2
Вы можете сэкономить 68 байт, удалив определенные типы ошибок (замените все excepts на except:).
NoOneIsHere

Будет ли это работать, если вы сделали x=<string inside eval>вместо того, чтобы просто проверить код вручную?
Blue

@NoOneIsHere Сначала я думал, что ты не можешь из-за всего этого 1/0, но потом я понял. Спасибо!
полностью человек

21

С ++ 14.11.17, оценка = 147/3 = 49

Для того, чтобы различать C ++ 11 и C ++ 14/17, он использует изменение по умолчанию constности constexprфункций членов в C ++ 14 (с кредитом к примеру на https://stackoverflow.com/questions/23980929/ что-изменения-введенные-в-c14-могут-потенциально-сломать-программу-написано-в-c1 ). Чтобы различать C ++ 14 и C ++ 17, он использует тот факт, что C ++ 17 отключил триграфы.

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

Ungolfed:

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

(Протестировано с использованием Debian gcc 7.1.0 -std=c++{11,14,17}.)


1
Отличный первый ответ! Обратите внимание, что вы можете поиграть в пробелы между includeи <, например, в операторах включения #include<iostream>.
MD XF

1
Хм ... если бы правила были пересмотрены, чтобы запретить использование стандартных различий в библиотеках (которые в данном случае косвенно используют __cplusplusмакрос) - тогда, чтобы отличить C ++ 17 от C ++ 14, я бы склонялся к использованию изменений в диапазоне для семантики. Возможно, создайте минимальные классы итераторов / стражей по аналогии с тем boost::integer_iterator, чтобы преобразование часового в итератор имело «удивительное» поведение.
Даниэль Шеплер

4
return 0;неявно для, mainтак что вы можете сохранить 9 байтов там. Также в соответствии с wc -cвашим решением используется 251 байт, а не 252 (ваш редактор, возможно, вставил новую строку в конце).
ЧПП

1
Вероятно, короче использовать отсутствие триграфов для отделения с ++ 17 от с ++ 14
Potato44

1
Будет ли это работать? return *=>return*
Захари

19

EcmaScript 3/5/2015/2016/2017 в браузере, 59 байт / 5 версий = 11,8 балла

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

NetScape 7, отчет 3 и Opera 12, отчет 5

Сэкономьте 1 байт благодаря GOTO 0



Netscape 7 поддерживает только ES3? Вау, это старше, чем я думал ...
Нил

1
Вы можете сохранить несколько байтов -!вместо того, +!!где это имеет смысл (и соответственно изменить числовые константы).
GOTO 0

3
Может быть, какое-то объяснение? :)
Дерек 朕 會

@Derek: см. Мое решение (ссылка выше) для объяснения.
Лохматый

18

JavaScript (ES5 & ES6), 14 байтов / 2 версии = 7

alert(5^"0o3")

0o-стильные восьмеричные константы являются новыми в ES6; ES5 приводит строку, к NaNкоторой не влияет результат побитового XOR.


13

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

Можно также представить решение с большим количеством версий, даже если оно имеет оценку несколько выше, чем у решения с 2 версиями.

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

Попробуйте онлайн

Проверяет наличие различных методов в прототипах Array, RegExp и String, отменяет их, давая логическое значение, и вычитает логическое значение от начального значения 9. Умножение ![].mapучитывает тот факт, что ES4 был оставлен.

  • dotAllСобственности (и связанный с ними sфлаг) для регулярных выражений были введены в ES2018 (v9).
  • Метод padEndString был представлен в ES2017 (v8).
  • Метод includesArray был представлен в ES2016 (v7).
  • Метод keysArray был представлен в ES2015 (v6).
  • Метод mapArray был введен в ES5.1 (v5).
  • Метод popArray был введен в ES3 (v3).

Является ли ES 7 или ES 8 верным номером версии? Может быть, это следует называть ES 201x?
TSH

1
@tsh: Да, они все еще используют номера версий; они просто используют годы для повторных имен .
Лохматый


9

Befunge: 15 11 байт / 2 версии = 5.5

@ Pietu1998 сбрил 4 байта

"89",;5-;,@  

Попробуйте онлайн:
Befunge 93
Befunge 98
Использует эксклюзивный оператор точки с запятой Befunge 98 («перейти к следующей точке с запятой») для различения версий. Оба напечатают «9». Befunge 93 проигнорирует точки с запятой, вычтет 5 из «8» (значение осталось в верхней части стека), выведет получившуюся «3» и завершится. Befunge 98, с другой стороны, пропустит, напечатает «8» и завершит работу.


"89",;5-;,@для 11 байтов
PurkkaKoodari

@ Pietu1998 Отлично! Если вы хотите опубликовать это как ответ, я с радостью приветствую :)
karhell

Продолжай и возьми, если хочешь, ты разобрался со своей ;частью.
PurkkaKoodari

@ Pietu1998 Отредактировано в. Большое спасибо!
karhell

К вашему сведению, мне удалось уменьшить его до 7 байт, применяя другой подход. Ссылка
Джеймс Холдернесс

7

Pyth 4/5 - 6 байт / 2 версии = 3

  5 ;4

В Pyth 5 четное количество пробелов в начале строки игнорируется для использования в отступе, в то время как в Pyth 4 он действует как один пробел и предотвращает печать 5. В Pyth 4 точки с запятой просто заканчивают операторы, что позволяет 4печатать, а в Pyth 5 пробел и точка с запятой делают оставшуюся часть строки комментарием.


11
Кто знал, что у Пита есть версии?
Эрик Outgolfer

7

Python 3 и Python 2.0, 18 байт, оценка 18/2 = 9

print(3-round(.5))

Банковское округление в Python 3, стандартное округление в Python 2.

Попробуйте онлайн - Python 3!

Попробуйте онлайн - Python 2!


вау, я всегда видел, как люди различают Python 2 и 3 по подразделению
phuclv

@ LưuVĩnhPhúc хорошо разбирается в колодце, поэтому: P
Стивен

7

Кубически, 4 байта, оценка 4 / ∞

B3%0

Работает в каждой версии вашей системы имеет достаточно памяти для запуска. Не конкурирует, потому что это хромает. Действительно для этого мета-поста .

По сути, B3 вращается на один ряд от левой грани в верхнюю границу. F3 будет работать так же хорошо, как F3 или B3. Так как один ряд в Cubically 3x3x3 представляет собой три кублета на один кубет, это помещает три 1в верхнюю грань, что дает ему сумму %0граней, равную 3., печатает эту верхнюю грань, печатая 3 для Cubically 3 x3x3.

В кубическом 4x4x4 строки - 4x1 кубы. Ставит 4 1 в верхнюю грань, получая сумму 4.


9
Разве счет не должен быть 4 / ∞?
ЧПП

7

16/32/64-битный машинный код x86: 11 байт, оценка = 3,66

Эта функция возвращает текущий режим (размер операнда по умолчанию) как целое число в AL. Звони из Си с подписьюuint8_t modedetect(void);

Машинный код NASM + список исходных кодов (показывающий, как это работает в 16-битном режиме, поскольку BITS 16говорит NASM собирать мнемонику источника для 16-битного режима.)

 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

Обоснование :

В машинном коде x86 официально нет номеров версий, но я думаю, что это удовлетворяет цели вопроса, так как приходится создавать конкретные числа, а не выбирать то, что наиболее удобно (это занимает всего 7 байтов, см. ниже).

Исходный процессор x86, Intel 8086, поддерживал только 16-битный машинный код. 80386 представил 32-битный машинный код (можно использовать в 32-битном защищенном режиме, а затем в режиме Compat под 64-битной ОС). AMD представила 64-битный машинный код, который можно использовать в длинном режиме. Это версии машинного языка x86 в том же смысле, что Python2 и Python3 - это разные языковые версии. Они в основном совместимы, но с преднамеренными изменениями. Вы можете запускать 32- или 64-разрядные исполняемые файлы непосредственно под ядром 64-разрядной ОС, так же, как и программы Python2 и Python3.

Как это устроено:

Начните с al=64. Сдвиньте его вправо на 1 (32-разрядный режим) или 2 (16-разрядный режим).

  • 16/32 против 64-битных: 1-байты inc/ decкодировки являются префиксами REX в 64-битных ( http://wiki.osdev.org/X86-64_Instruction_Encoding#REX_prefix ). REX.W совсем не влияет на некоторые инструкции (например, a jmpили jcc), но в этом случае, чтобы получить 16/32/64, я хотел бы включить или dec, ecxа не eax. Это также устанавливает REX.B, который изменяет регистр назначения. Но, к счастью, мы можем сделать это, но настройку так, чтобы 64-битная версия не менялась al.

    Инструкции, которые выполняются только в 16-битном режиме, могут включать в себя ret, но я не нашел это необходимым или полезным. (И сделает невозможным встроенный фрагмент кода, если вы захотите это сделать). Это также может быть jmpвнутри функции.

  • 16-битные и 32/64: немедленные 16-битные, а не 32-битные. Изменение режимов может изменить длину инструкции, поэтому 32/64 битные режимы декодируют следующие два байта как часть немедленной, а не отдельной инструкции. Я упростил задачу, используя 2-байтовую инструкцию здесь, вместо того, чтобы не синхронизировать декодирование, чтобы 16-битный режим декодировал с границ команд, отличных от 32/64.

    Связанный: Префикс размера операнда изменяет длину непосредственного (если это не 8-разрядный немедленный знак), так же как разница между 16-битным и 32/64-битным режимами. Это затрудняет параллельное декодирование длины команды; Процессоры Intel имеют киоски декодирования LCP .


Большинство соглашений о вызовах (включая psABI x86-32 и x86-64 System V) позволяют узким возвращаемым значениям иметь мусор в старших битах регистра. Они также допускают удары CX / ECX / RCX (и R8 для 64-битных). IDK, если это было распространено в 16-битных соглашениях о вызовах, но это кодовый гольф, так что я всегда могу просто сказать, что это пользовательское соглашение о вызовах.

32-разрядная разборка :

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    

64-разрядная разборка ( попробуйте онлайн! ):

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    

Связанный: мой машинный код полигона x86-32 / x86-64 Q & A на SO.

Другое различие между 16-битным и 32/64 заключается в том, что режимы адресации кодируются по-разному. eg lea eax, [rax+2]( 8D 40 02) декодирует как lea ax, [bx+si+0x2]в 16-битном режиме. Это, очевидно , трудно использовать для кода-гольфа, особенно с тех пор e/rbxи e/rsiявляется вызовом сохранившегося во многих соглашениях о вызовах.

Я также рассмотрел использование 10-байт mov r64, imm64, который является REX + mov r32,imm32. Но так как у меня уже было 11-байтовое решение, это было бы в лучшем случае равным (10 байт + 1 для ret).


Тестовый код для 32 и 64-битного режима. (На самом деле я не выполнял его в 16-битном режиме, но разборка говорит вам, как он будет декодироваться. У меня не настроен 16-битный эмулятор.)

; 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

Эта программа Linux завершает работу с exit-status = modedetect(), поэтому запустите ее как ./a.out; echo $?. Соберите и свяжите его в статический бинарный файл, например

$ 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 байт (оценка = 2,33), если я могу нумеровать версии 1, 2, 3

Официальных номеров версий для разных режимов x86 нет. Мне просто нравится писать ответы на вопросы. Я думаю, что это нарушило бы намерение вопроса, если бы я просто назвал режимы 1,2,3 или 0,1,2, потому что дело в том, чтобы заставить вас генерировать неудобное число. Но если это было разрешено:

 # 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

Который декодирует в 32-битном режиме как

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

и 64-битный как

00000000004000a0 <detect123>:
  4000a0:       b8 03 00 fe c8          mov    eax,0xc8fe0003
  4000a5:       48 c3                   rex.W ret 

Я не уверен, что это считается разными версиями . Разве они не просто соотносятся с различными конфигурациями системы?
Уриэль

1
@Uriel: Выполнение блока машинного кода с процессором в 16-битном, 32-битном или 64-битном режиме - это машинный код, эквивалентный работе python2с python3интерпретаторами в одной и той же программе Python. Новые процессоры x86 всегда включают режим, совместимый со старыми процессорами (это их единственное оправдание для использования такого сложного, трудно декодируемого формата машинного кода!), Но 32-битный защищенный режим 386 и длинный режим x86-64 действительно новые версии машинного кода x86. В длинном режиме даже удалены некоторые коды операций, что делает их недействительными.
Питер Кордес

5

Brachylog / Brachylog v1 , 5/2 = 2,5

2,1hw

Попробуйте онлайн! (Brachylog)

Попробуйте онлайн! (Brachylog v1)

Пояснение к брахилогу:

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

Объяснение для 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)

Большой! Как примечание, 2,1в Brachylog v2 строится не список [2,1]( 2;1будет), а номер 21(который не меняет способ, которым вы хотели, чтобы ваш ответ работал).
Роковая

@Fatalize Ооо, спасибо, я перепутал это с Желе ...
Эрик Outgolfer

@Fatalize BTW 2;1не работал бы в Brachylog v1 как ;средство логического ИЛИ там.
Эрик Outgolfer

5

C89 / C99, 25 байтов, 2 версии, оценка = 12,5

#include <stdio.h>

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

// комментарии стиля не распознаются в C89.

Гольф версия:

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

Попробуйте онлайн: C89 , C99


заменить int v()на main(), он короче и фактически скомпилируется как полная программа!
Андреа

@ Андреа Спасибо. AFAIK, разрешено размещать либо функции, либо целые программы.
nwellnhof

Ты прав.
Андреа

5

Perl 5 и Perl 6, 23 байта 19 байтов, оценка 9,5

print 6-grep '.',''

grepПервая операция Perl 5 всегда рассматривается как регулярное выражение, а не в Perl 6.


счет 19/2 = 9,5
Даниэль Вестёль

5

Bash, все 4 версии, 72 71 32 байта ⇒ оценка = 8

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

Этот фрагмент кода использует различные интерпретации $'...'строк в каждой версии Bash.
Выводит основной номер версии - и все.

Док нашел здесь .

Ungolfed:

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

Этот ответ наполовину предположение; Я тестировал только в bash 4 и 3, но он должен работать и на других версиях.

Дайте мне знать, если это произойдет / нет, я постараюсь с другими версиями, как только они будут доступны.

-1 символ благодаря Йенсу.
-29 байт благодаря Digital Trauma (вся exprидея)!


Грамматика оболочки не требуется ;;в последней альтернативе. Используйте, ;чтобы сбрить байт.
Дженс

1
Я только что попробовал это на bash-2.05a (скомпилирован только сейчас для Cygwin), и он некорректно сообщает «3», а не «2» :(
Джейсон Масгроув

1
$'\xNПохоже, что функция интерпретации была добавлена ​​в 2.01.1 ... Мне придется обновить свой ответ. Работа над этим
joH1

могу я попросить вас попробовать это? s="$'\ua\xa\n'";case ${#s} in 3)echo 4;;5)echo 3;;7)echo 2;;9)echo 1;esac
joH1

1
Вы могли бы быть в состоянии сыграть в гольф что-то вроде s=$'\ua\xa\n';expr 5 - ${#s} / 2. Это работает на v3 и v4. У меня нет работающих старых версий, чтобы попробовать прямо сейчас.
Цифровая травма

4

R, версии 2 и 3, оценка: 10,5 балла

cat(exists("cite")+2)

Эта команда возвращается 2для R 2.xx и 3для R 3.xx Функция citeбыла добавлена ​​в R версии 3.0.0. Следовательно, команда exists("cite")возвращается FALSEдля R 2.xx и TRUEдля R 3.xx

R, все версии (1, 2 и 3), оценка: 12⅓ баллов

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

Функция eapplyбыла введена в R 2.0.0.


R.version$major, 15 символов. Я не с тех пор, когда это существует.
Руи Баррадас

@RuiBarradas Позвольте мне привести OP: « Ваша программа не может использовать встроенную команду, макро, или флаги пользовательского компилятора , чтобы определить версию языка. »
Свен Hohenstein

Хорошо, извини, я пропустил эту часть. Должен ли я удалить комментарий?
Руи Баррадас

@RuiBarradas Нет проблем. Вам не нужно удалять комментарий.
Свен

Вы должны справиться с печатью результата. В настоящее время при запуске в качестве полной программы это ничего не печатает.
JAD

4

Python , 196 байт / 16 версий = оценка 12,25

Версии: 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 и 3.6.
К сожалению, мне пришлось опустить 2.7, потому что в это (насколько я могу судить), которые не в 2.6, но в 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.)

Мы перебираем несколько модулей, представленных в разных версиях Python, и при первой ошибке завершаем работу и возвращаем версию. Пробелы между основными версиями заполняются путем многократного импорта os. Тест для Python 1.5 полагается на string.splitотсутствие до 1.6.

Благодарим Оливье Грегуара за ответ на идею тестирования новых классов / модулей в цикле.

Теперь я наконец-то протестировал все соответствующие версии python ... которые требовали редактирования исходного кода 1.5, чтобы заставить его скомпилировать ...


4

Пакетный файл Windows , 35 байт / 2 версии = оценка 17,5

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

Печать DOSна MS-DOS (Дух) и NTна Windows NT. (Дух)

Теперь для некоторого объяснения.

Со времен MS-DOS в Windows был пакетный сценарий, и с тех пор он практически не изменился. Однако, когда появилась Windows NT , Microsoft изменила интерпретатор по умолчанию для пакетных скриптов с COMMAND.COMна cmd.exe(теперь также разрешает расширение .cmdв качестве альтернативы оригиналу .bat).

При этом они также реализовали несколько изменений , таких как /iфлаг игнорирования строкового регистра в условных выражениях. То есть, пока Z==zложно, /i Z==zверно.

Мы эксплуатируем, что DOS не имеет нечувствительности к регистру, и сравниваем прописные Zи строчные буквы z. Используя /iфлаг, мы получаем Z==z(ложное) условие для DOS и z==z(истинное) для NT.

Теперь я понимаю, что в задании указывается номер версии. Но, насколько я знаю, нет «номера версии» для пакетного скриптинга, так что это самое близкое, что я мог получить.


Протестировано на Windows 10, DOSBox и vDos:

Windows 10:

Windows 10

(запустить, cmd /kчтобы предотвратить закрытие окна exit)

DOSBox:

DOSBox

пКС:

пКС


Windows 7короче, чем Windows NT.
user202729

2
@ user202729 Полагаю, но опять же, на 7самом деле это не языковая версия, она была одинаковой на всех Windows с 3.1. Так что я не думаю, что было бы очень справедливо называть это, 7когда, возможно, даже должно быть3.1
Матеус

3

Wolfram Language / Mathematica 10/11, 37 байт / 2 версии = 18,5

Рассмотрим (Length@DateRange[{1},{1}][[1]]+27)/3, при 37 байтах и ​​работе с 2 версиями, я получаю оценку 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

а также

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

Я уверен, что есть более эффективный способ, но расхождение между выходными данными DateRange в последнее время немного затронуло меня, поэтому я решил использовать это.

Как следствие, кто-то, возможно, мог бы воспользоваться Length@DateRange[{1}, {1}][[1]]оценками 1в Mathematica версии 1-8, но у меня не было времени, чтобы включить это.


2
Совершенно уверен, что ваш ответ не соответствует требованиям приглашения, а именно последнему правилу, которое вы используете $Version:Your program may not use a builtin, macro, or custom compiler flags to determine the language version.
Amndeep7

7
Я только использую, $Versionчтобы продемонстрировать, что он выводит правильный результат в правильной версии, $Versionне является частью моего ответа ...
user6014

Все, хороший друг, дело в том, что вы используете что-то подобное $VersionNumber, но вместо этого вы называете это $Version. На мой взгляд, хотя ядро ​​вашей программы - это Length@DateRangeто, что не сработает, если вы не $Versionпредоставите полную информацию о версии, которую вы затем обрабатываете, что, следовательно, нарушает правила.
Amndeep7

4
@ Amndeep7 Представление представляет собой 37-байтовый код, встроенный в первый абзац. Блоки кода являются только выходными демонстрациями.
PurkkaKoodari

3
Объяснение: Использование разных форматов времени в разных версиях. Это может быть больше {1} Tr[1^#&@@%~DateRange~%]/3+9(31 байт) или даже 7+Length@Now(12 байт)
user202729

3

Ruby 1.x и 2.x, 20 байт, оценка 10

p [].to_h&&2rescue 1

На основе to_hметода, который был введен в Arrayклассе в Ruby 2.


Хороший первый ответ. У меня нет 1.x под рукой, чтобы проверить, но p [].to_h&&2rescue 1немного короче.
manatwork

@manatwork Отлично, экономит 3 байта и работает как шарм
Филипп Франк

3

Erlang, 180 байт, 11 версий, оценка 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)]]).

С отступом и переносом строки:

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)]]).

Протестировано на одном дополнительном выпуске каждой основной версии начиная с 10:

  • R10b-9
  • R11b-5
  • R12b-5
  • R13B04
  • R14B04
  • R15B03
  • R16B03
  • 17.5.6.2
  • 18.2.1
  • 19,2
  • 20,0

Идея состоит в том, что в каждом основном выпуске добавляется по крайней мере один новый допустимый аргумент для функции erlang:system_info, поэтому давайте попробуем те из списка, подсчитаем, сколько из них вышло из строя, и вычтем количество отказов из 20, что является текущей версией.


3

Юлия 0,4, 0,5, 46 байт, оценка 22

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

Юлия изменила имя типа конкретного и абстрактного типов String во многих версиях.

Этот код, в частности, использует преимущества:

Юлия 0,4 :

  • Бетон есть ASCIIString,
  • Аннотация официально AbstractString,
  • Аннотация устарела псевдоним для String.
  • Бетон более специфичен, чем абстрактный, поэтому выигрывает

Юлия 0.5 :

  • Бетон официально String,
  • Бетон устарел псевдоним ASCIIString,
  • Аннотация есть AbstractString, (хотя это не имеет значения здесь)
  • Поскольку для конкретного типа строки определены два метода, последний перезаписывает первый.

Смотрите также мое новое, более эффективное решение, основанное на разных принципах.


3

Джапт (1 и 2), 8 6/2 = 4 3

'1r\S2

Тест v1  |   Тест v2


объяснение

До версии v2 Japt использовал настраиваемый синтаксис RegEx, поэтому мы можем воспользоваться этим.

'1

Число 1 в виде строки.

 r  2

Замените ( r) ниже на 2.

\S

Japt 2 видит это как RegEx /\S/g, который соответствует 1. Japt 1 игнорирует \escape-символ и просто видит S, который является константой Japt для пробела и, очевидно, не совпадает с 1.


3

Befunge, оценка = 3,5

7 байтов, 2 версии

"]"'b.@

Попробуйте онлайн в Befunge-93
Попробуйте онлайн в Befunge-98

"]"является строковым литералом в обеих версиях, помещая 93 (значение ASCII [) в стек. 'bэто символьный литерал в Befunge-98, нажимающий 98 (значение ASCII b), но это недопустимые инструкции в Befunge-93, поэтому они просто игнорируются. Таким образом, мы заканчиваем с 93 на вершине стека в Befunge-93 и 98 в Befunge-98. .@записывает значение в верхней части стека и затем выходит.


]".@.b'или ]g.@.b'тоже работа
MildlyMilquetoast

3

Ruby 1.x (<1.9) и 2.x, 10 8 байт, оценка = 4

$><<?2%7

Попробуй:

Это работает, используя различные способы поведения ?xмежду Ruby 1.x и 2.x. В Ruby 1.x ?A(например) возвращает 65(значение ASCII символа A), но в Ruby 2.0 он возвращает односимвольную строку "A".

Код выше эквивалентен этому:

val = ?2
$> << val % 7

В Ruby 1.x (<1.9) значением valявляется 50(значение ASCII символа 2) Fixnum. Fixnum#%является оператором по модулю, поэтому 50 % 7возвращает 1.

В Ruby 2.x valесть строка "2". String#%является инфиксной версией sprintf, поэтому "2" % 7эквивалентно sprintf("2", 7), где "2"это строка формата. Поскольку строка формата не содержит никаких последовательностей формата (например %d), последующие аргументы отбрасываются и "2"возвращаются.

Наконец, $>это псевдоним для $stdout, поэтому $> << ...печатает результат.


1
О, здорово! Я пытался сделать что-то вроде, ?A==66?1:2прежде чем я наткнулся на ваш ответ
Piccolo

3

Python 2 и Python 3 , 36 34 байта, оценка 18 17

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

В Python 2 хэш отрицательной бесконечности равен -271828, но в Python 3 это -314159. Редактировать: 2 байта, 1 балл, благодаря @ArBo.


косит взгляды Это преднамеренная вещь против Пи?
Джо Кинг

@ JoKing Да; по-видимому, когда hashвпервые была установлена ​​работа с бесконечными числами с плавающей точкой, соответствующий разработчик использовал pi * 1e5 и e * -1e5 в качестве хеш-значений. В какой-то момент в Python 3 значение has для отрицательной бесконечности изменилось и стало отрицанием значения хеш-функции для бесконечности.
Нейл

2

Питон 3 , Питон 2 , оценка 17,5

(35 байт, 2 версии)

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

Python 2 , 35 байт

Попробуйте онлайн!

Python 3 , 35 байт

Попробуйте онлайн!

Сохранено 5 байт благодаря ETHproductions

Не хороший код гольф-ответа, но масштабное изменение!


Хм, вы можете поместить каждое утверждение в предыдущую строку? Т.е.try:exec("print 2")\nexcept:print(3)
ETHпродукция

@ETHproductions спасибо! Я не ожидал победы, поэтому был немного отвлечен. В основном я хотел бы сосредоточиться на на массивное изменение между Python 2 и 3.
jferard
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.