[Question]
  [
Your challenge is to write a polyglot that works in different versions of your language. When run, it will always output the language version.
# Rules
* Your program should work in at least two versions of your language.
* Your program's output should *only* be the version number. No extraneous data.
* Your program may use whatever method you like to determine the version number. However, the output must follow rule 2; however you determine the version number, the output must only be the number.
* Your program only needs to output the major version of the language. For example, in FooBar 12.3.456789-beta, your program would only need to output 12.
* If your language puts words or symbols before or after the version number, you do not need to output those, and only the number. For example, in C89, your program only needs to print `89`, and in C++0x, your program only needs to print `0`.
* If you choose to print the full name or minor version numbers, e.g. C89 as opposed to C99, it must *only* print the name. `C89 build 32` is valid, while `error in C89 build 32: foo bar` is not.
* Your program may not use a builtin, macro, or custom compiler flags to determine the language version.
# Scoring
Your score will be the code length divided by the number of versions it works in. Lowest score wins, good luck!
  
[Answer]
# Python 3.0 and Python 2, score 6
(12 bytes, 2 versions)
```
print(3/2*2)
```
Try it Online:
* [Python 2](https://tio.run/##K6gsycjPM/r/v6AoM69Ew1jfSMtI8/9/AA "Python 2 – Try It Online")
* [Python 3](https://tio.run/##K6gsycjPM/7/v6AoM69Ew1jfSMtI8/9/AA "Python 3 – Try It Online")
Relies on the fact that Python 3+ uses float division by default, unlike Python 2, which uses floor division.
[Answer]
# [Java](https://en.wikipedia.org/wiki/Java_(programming_language)), 400 bytes, 17 versions, score = 23,52
Supported versions: `1.0`, `1.1`, `1.2`, `1.3`, `1.4`, `1.5`, `1.6`, `1.7`, `1.8`, `9`, `11`, `12`, `14`, `15`, `16`, `17` and `18`.
Unsupported vesions: `10` and `13` since they have no new classes at all.
(For previous scores, [check the history](https://codegolf.stackexchange.com/posts/139274/revisions)!)
```
Object v(){int i=0;try{for(String[]s={"Locale","Map","Timer","Currency","UUID","Deque","Objects","Base64","zip.CRC32C","Map","java.security.interfaces.XECKey","java.lang.Enum$EnumDesc","Map","java.io.Serial","java.security.spec.EdECPoint","java.lang.Record","HexFormat","java.net.spi.InetAddressResolver"};;i++)Class.forName(s[i].charAt(0)=='j'?s[i]:"java.util."+s[i]);}finally{return i<9?"1."+i:i;}}
```
[Attempt This Online!](https://ato.pxeger.com/run?1=ZZHPbtQwEMbFtU9hRUhNtGCVP0LQsKpKNogKCmiXSkhVkVxndjsrxw4ee2mI8g7cuewB3oIXgadhopSVKi6eTzPjz-P5ff-xVhu1_dXES4NaaKOIxKlCK7o9ISiogPpnDMv7T__c-fbucg06iE2adWiDwOlBHnzbLZ1PF8GjXZ1f0LRL3jitDCT3klPV8PkBa_Aci-g9WN2yPDs7mXGYwec49I2-xOqFInjymMVXbGQxLx49LHY-w6CSQEePoZU8APil0kDyY1m8hvZfh1F2JUsb67vDMQPStx3QyQV4VOY_S2pAy7Iqi_eO3W_5zUE7X3HqFVy_dL5Wu7KFwBdRnrA4rioPRHMgZzb85z7PcTLJimGpkrf0VtWQ0jleSH2l_HFID7LpdH-9fzTkDke_GNDIZDJksrxfolXGtJ2HEL0V-PzZUfKAy3iIed-PYH5_EuIG38hLbBxWomaIOyxC-RVlIlx594VEea2hCehGyEIsWgpQSxeDbLg_GJsy4yznYr9388p2O8a_)
### 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
        "Map",             // 10 is unsupported so use the smallest name possible.
        "java.security.interfaces.XECKey",   // 11
        "Enum$EnumDesc",                     // 12
        "Map",             // 13 is unsupported so use the smallest name possible.
        "java.io.Serial",  // 14
        "java.security.spec.EdECPoint",      // 15
        "java.lang.Record",                  // 16
        "HexFormat",                         // 17
        "java.net.spi.InetAddressResolver"   // 18
      };;v++)
      Class.forName(
        s[i].charAt(0)=='j'     // If the package name is referenced,
          ? s[i]                // Use it
          : "java.util."+s[i]); // Else, prepend "java.util".
  } 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
  }
}
```
Please note that the code part `return v<9?"1."+v:v;` (previously `return(v<9?"1.":"")+v;`) needs to be checked against any version between Java 1.0 and Java 1.3 included. I don't have any Java 1.3 or earlier installation at my disposal to actually test this syntax.
### Introduction
The Java versioning has a special history. All versions have historically been `1.x` including `1.0`. But... from Java 9 onwards and the [JEP223](http://openjdk.java.net/jeps/223), the version scheming has changed from using `1.x` to `x`. That is the version as internally known. So we have the following table (put together with the Javadoc and [Wikipedia](https://en.wikipedia.org/wiki/Java_version_history)):
| `java.version` property | Release name | Product name |
| --- | --- | --- |
| 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 |
| ... | ... | ... |
| 18 | Java SE 18 | Java 18 |
This challenge entry matches the version column in the table above, which is what is contained in the system property `"java.version"`.
### Explanation
The goal is to check from which version a class starts to exist, because Java deprecates code but never removes it. The code has been specifically written in Java 1.0 to be compatible with all the versions, again, because [the JDK is (mostly) source forward compatible](https://stackoverflow.com/questions/4692626/is-jdk-upward-or-backward-compatible).
The implementation tries to find the shortest class names that each version introduced. Though, to gain bytes, it's needed to try and pick a common subpackage. So far I found the most efficient package is `java.util` because it contains several really short-named classes spread across all versions of Java.
Now, to find the actual version number, the class names are sorted by introducing version. Then I try to instanciate each class sequentially, and increment the array index. If the class exists, we skip to the next, otherwise we let the exception be caught by the `try`-block. When done, another exception is thrown because there are no more classes whose existence we need to check.
In any case, the thread will leave the `try`-block with an exception. That exception is not caught, but simply put on hold thanks to the `finally`-block, which in turn overrides the on-hold exception by actually returning a value which is `"1."+v` where `v` is the index used before. It also happens we made this index match the minor version number of Java.
Note: what is below needs to be updated.
An important part of the golf was to find the shortest new class name in the package `java.util` (or any children package) for each version. Here is the table I used to compute that cost.
| Version | Full 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] |
|  | Full name (cost in chars) | Reduced name (cost in chars) |
| --- | --- | --- |
| Subtotal | 144 chars | 54 chars |
| Base | 0 chars | 10 chars (`java.util.`) |
| Total | 144 chars | 64 chars |
### Credits
* 30 bytes saved thanks to Kevin Cruijssen (although I was doing it before I read his comment, I promise!).
* 26 further bytes saved thanks to Neil (nope, I wasn't thinking about doing that)
* 12 bytes thanks to Nevay and the nice out-of-the~~-box~~-try-catch thinking!
* 11 more bytes by Neil again and the nice portable `finally` trick.
* 2 more bytes thanks to Kevin Cruijssen by replacing `return(i<9?"1.":"")+i;` with `return i<9?"1."+i:i;` (this needs to be validated against 1.0 or at most 1.3 since no syntax changes happened before 1.4)
### With builtins
If builtins were allowed:
```
String v(){return System.getProperty("java.version");}
```
54 bytes for 19 versions (from 1.0 to 18), so the score would be 2,84.
[Answer]
# [Python](https://docs.python.org/), 606 bytes / 15 versions = score 40.4
*-67 bytes (lol) thanks to NoOneIsHere.*
The versions are 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 aaand 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)  
```
All credit to [Sp3000's amazing answer](https://codegolf.stackexchange.com/a/94834). The trailing newline is necessary.
Whee, that was fun to golf. This should work (yes, I installed every one of these versions), but I might've accidentally borked something. If anybody finds a bug, please let me know.
[Answer]
# EcmaScript 3 / 5 / 2015 / 2016 / 2017 in Browser, 59 bytes / 5 versions = 11.8 points
```
alert(2017-2*![].map-2010*![].fill-![].includes-!"".padEnd)
```
[![NetScape 7 report 3, and Opera 12 report 5](https://i.stack.imgur.com/bxlqv.png)](https://i.stack.imgur.com/bxlqv.png)
Save 1 byte thanks to GOTO 0
[Answer]
# C++ 11/14/17, score = 147/3 = 49
To distinguish between C++11 and C++14/17, it uses the change in the default `const`ness of `constexpr` member functions in C++14 (with credit to the example at <https://stackoverflow.com/questions/23980929/what-changes-introduced-in-c14-can-potentially-break-a-program-written-in-c1>). To distinguish between C++14 and C++17, it uses the fact that C++17 disabled trigraphs.
```
#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);
}
```
(Tested with Debian gcc 7.1.0 using `-std=c++{11,14,17}`.)
[Answer]
# [Seriously](https://github.com/Mego/Seriously/tree/v1) and [Actually](https://github.com/Mego/Seriously), 3 bytes, score 1.5
```
'1u
```
Try it online: [Actually](https://tio.run/##S0wuKU3Myan8/1/dsPT/fwA "Actually – Try It Online"), [Seriously](https://tio.run/##K04tyswvLc6p/P9f3bD0/38A)
Explanation:
```
'1u
'1   both versions: push "1"
  u  Actually: increment character to "2"; Seriously: NOP
     (both versions: implicit print)
```
`u` and `D` having functionality on strings was only added in Actually (which is Seriously v2).
[Answer]
## JavaScript (ES5 & ES6), 14 bytes / 2 versions = 7
```
alert(5^"0o3")
```
`0o`-style octal constants are new in ES6; ES5 casts the string to `NaN` which doesn't affect the result of the bitwise XOR.
[Answer]
# JavaScript (ES 2, 3 & 5 - ~~8 9~~ 11), ~~59 / 6 = 9.833 75 / 7 = 10.714~~ 98 / 9 = 10.889
May as well submit the solution with more versions, even if it does score slightly higher than the 2-version solution.
```
alert(11-!"".matchAll-![].flat-(/./.dotAll!=0)-!"".padEnd-![].includes-![].keys-2*![].map-![].pop)
```
[Try it online](https://tio.run/##y0osSyxOLsosKNHNy09J/Z@Yk1pUYpucn1ecn5Oql5OfDhHRsNTV0NfT10vJL3HMyVG0NdDUVVRS0itITHHNS9FVjI7Vy8xLzilNSS0Gc7JTK4t1jbRAzNzEArBQQX6B5v//AA)
Checks for the presence of various methods in the Array, RegExp & String prototypes, negates them, giving a boolean, and subtracts that boolean from an initial value of 11. The multiplication of `![].map` accounts for the fact that ES4 was abandoned.
* The [`matchAll`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/string/matchAll) String method was introduced in [ES2019](https://262.ecma-international.org/11.0/#sec-string.prototype.matchall) (v11).
* The [`flat`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/flat) Array method was introduced in [ES2020](https://262.ecma-international.org/10.0/#sec-array.prototype.flat) (v10).
* The [`dotAll`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/dotAll) property (and related `s` flag) for Regular Expressions was introduced in [ES2018](http://www.ecma-international.org/ecma-262/9.0/#sec-get-regexp.prototype.dotAll) (v9).
* The [`padEnd`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/padEnd) String method was introduced in [ES2017](http://www.ecma-international.org/ecma-262/8.0/#sec-string.prototype.padend) (v8).
* The [`includes`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/includes) Array method was introduced in [ES2016](http://www.ecma-international.org/ecma-262/7.0/#sec-array.prototype.includes) (v7).
* The [`keys`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/keys) Array method was introduced in [ES2015](http://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.keys) (v6).
* The [`map`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/map) Array method was introduced in [ES5.1](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.19) (v5).
* The [`pop`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/pop) Array method was introduced in [ES3](http://www.ecma-international.org/publications/files/ECMA-ST-ARCH/ECMA-262,%203rd%20edition,%20December%201999.pdf) (v3).
[Answer]
# PHP 5/7, score 5.5
```
<?=7-"0x2";
```
[3V4L it online!](https://3v4l.org/Y378M)
# PHP 5.3.9/5.3.11, score 10
```
<?='5.3.'.(9-0x0+2);
```
[3V4L it online!](https://3v4l.org/4GaUL)
The online version is longer because old PHP versions on the sandbox don't have short tags enabled.
[Answer]
# x86 16/32/64-bit machine code: 11 bytes, score= 3.66
This function returns the [current mode](https://en.wikipedia.org/wiki/X86-64#Operating_modes) (default address-size) as an integer in AL. Call it from C with signature `uint8_t modedetect(void);`. (Or more realistically, from machine code that's going to branch on the result using instruction encodings that decode the same in all modes.)
NASM machine-code + source listing (showing how it works in 16-bit mode, since `BITS 16` tells NASM to assemble the source mnemonics for 16-bit mode.)
```
 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
```
**Justification**:
x86 machine code doesn't officially have version numbers, but I think this satisfies the intent of the question by having to produce specific numbers, rather than choosing what's most convenient (that only takes 7 bytes, see below).
Another interesting way to interpret the question would be to write 16-bit code to detect 8086 vs. 186 vs. 286 vs. 386, etc, [as in this example](https://reverseengineering.stackexchange.com/questions/19394/how-did-this-80286-detection-code-work), based on FLAGS and other behaviour, because each new "version" added new features (including instruction opcodes). But that's not what this answer does.
The original x86 CPU, Intel's 8086, only supported 16-bit machine code. 80386 introduced 32-bit machine code (usable in 32-bit protected mode, and later in compat mode under a 64-bit OS). AMD introduced 64-bit machine code, usable in long mode. These are versions of x86 machine language in the same sense that Python2 and Python3 are different language versions. They're mostly compatible, but with intentional changes. You can run 32 or 64-bit executables directly under a 64-bit OS kernel the same way you could run Python2 and Python3 programs.
### How it works:
Start with `al=64`. Shift it right by 1 (32-bit mode) or 2 (16-bit mode).
* 16/32 vs. 64-bit: The 1-byte `inc`/`dec` encodings are REX prefixes in 64-bit (<http://wiki.osdev.org/X86-64_Instruction_Encoding#REX_prefix>). REX.W doesn't affect some instructions at all (e.g. a `jmp` or `jcc`), but in this case to get 16/32/64 I wanted to inc or dec `ecx` rather than `eax`. That also sets `REX.B`, which changes the destination register. But fortunately we can make that work but setting things up so 64-bit doesn't need to shift `al`.
The instruction(s) that run only in 16-bit mode could include a `ret`, but I didn't find that necessary or helpful. (And would make it impossible to inline as a code-fragment, in case you wanted to do that). It could also be a `jmp` within the function.
* 16-bit vs. 32/64: immediates are 16-bit instead of 32-bit. Changing modes can change the length of an instruction, so 32/64 bit modes decode the next two bytes as part of the immediate, rather than a separate instruction. I kept things simple by using a 2-byte instruction here, instead of getting decode out of sync so 16-bit mode would decode from different instruction boundaries than 32/64.
Related: The operand-size prefix changes the length of the immediate (unless it's a sign-extended 8-bit immediate), just like the difference between 16-bit and 32/64-bit modes. This makes instruction-length decoding difficult to do in parallel; [Intel CPUs have LCP decoding stalls](https://software.intel.com/en-us/forums/intel-performance-bottleneck-analyzer/topic/328256).
---
Most calling conventions (including the i386 and x86-64 System V ABIs) allow narrow return values to have garbage in the high bits of the register. They also allow clobbering CX/ECX/RCX (and R8 for 64-bit). IDK if that was common in 16-bit calling conventions, but this is code golf so I can always just say it's a custom calling convention anyway.
**32-bit disassembly**:
```
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-bit disassembly** ([Try it online!](https://tio.run/##VVA7b8IwEN79K24rSIGGQCMU1KFIHSp1ahm6oUtyAat@VLEpSf88vRhCwIPP9/m@h43Okc5VOzHo9GmnbI4Kts5j7cW5ZAJ4FagUF21LKslT4QOq7e9fA0B5EwGqHuoKIUOzgEjjuxI3yxguawWudVtqpB8NiqPxeCUEKrkzMEtFH@bGcjhmYv22@ezGbjxRRZAubpGCQ8RXz/maszBnkks/BXgK7Tx5TBcRFNa4g5ZmBwmTa4K89eQAHfg9gdSaSomeLg8qgrgCGB6E6oitY3YgsvyGeckayBS27HRtFYhFA0d7UCXv9XcE3tqpEGeJIxqfXfKx@vOMVThf12ZdH9@5N1frdHEe@Xj9gp@aKtmEQbev@18JUYfB7qZe5gEvLTnz4AGriv8VXt4BuVFq2lv3SYZcSZCvyYvT6R8 "Assembly (nasm, x64, Linux) – Try It Online")):
```
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    
```
Related: my [x86-32 / x86-64 polyglot machine-code](https://stackoverflow.com/questions/38063529/x86-32-x86-64-polyglot-machine-code-fragment-that-detects-64bit-mode-at-run-ti) Q&A on SO.
Another difference between 16-bit and 32/64 is that addressing modes are encoded differently. e.g. `lea eax, [rax+2]` (`8D 40 02`) decodes as `lea ax, [bx+si+0x2]` in 16-bit mode. This is obviously difficult to use for code-golf, especially since `e/rbx` and `e/rsi` are call-preserved in many calling conventions.
I also considered using the 10-byte `mov r64, imm64`, which is REX + `mov r32,imm32`. But since I already had an 11 byte solution, this would be at best equal (10 bytes + 1 for `ret`).
---
Test code for 32 and 64-bit mode. (I haven't actually executed it in 16-bit mode, but the disassembly tells you how it will decode. I don't have a 16-bit emulator set up.)
```
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
```
This Linux program exits with exit-status = `modedetect()`, so run it as `./a.out; echo $?`. Assemble and link it into a static binary, e.g.
```
$ 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, e.g. in a bootloader, if you want.
```
---
# 7 bytes (score=2.33) if I can number the versions 1, 2, 3
There are no official version numbers for different x86 modes. I just like writing asm answers. I think it would violate the question's intent if I just called the modes 1,2,3, or 0,1,2, because the point is to force you to generate an inconvenient number. But if that was allowed:
```
 # 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
```
Which decodes in 32-bit mode as
```
08048080 <detect123>:
 8048080:       b8 03 00 fe c8          mov    eax,0xc8fe0003
 8048085:       48                      dec    eax
 8048086:       c3                      ret    
```
and 64-bit as
```
00000000004000a0 <detect123>:
  4000a0:       b8 03 00 fe c8          mov    eax,0xc8fe0003
  4000a5:       48 c3                   rex.W ret 
```
[Answer]
# Pyth 4/5 - 6 bytes/2 versions = 3
```
  5 ;4
```
In Pyth 5, an even amount of spaces at the start of the line is ignored for use in indenting, while in Pyth 4, it just acts like a single space and prevents printing the `5`. In Pyth 4, semicolons just finish statements, which allows the `4` to be printed, while in Pyth 5, a space and semicolon makes the rest of the line a comment.
[Answer]
# Befunge : ~~15~~ 11 bytes / 2 versions = 5.5
4 bytes shaved off by @Pietu1998 
```
"89",;5-;,@  
```
Try it online :  
[Befunge 93](https://tio.run/##S0pNK81LT/3/X8nCUknH2lTXWsfh/38A "Befunge – Try It Online")  
[Befunge 98](https://tio.run/##S0pNK81LT9W1tNAtqAQz//9XsrBU0rE21bXWcfj/HwA "Befunge-98 (PyFunge) – Try It Online")  
Uses the Befunge 98-exclusive semicolon operator ("skip to next semicolon") to differentiate versions. Both will print "9". Befunge 93 will ignore the semicolons, subtract 5 from "8" (value left on top of the stack), print the resulting "3" and terminate. Befunge 98 on the other hand, will skip over, print "8" and terminate.
[Answer]
# Cubically, 4 bytes, score 4/∞
```
B3%0
```
Works in every version your system has enough memory to run. **Non-competing because it's lame.** Valid per [this meta post](https://codegolf.meta.stackexchange.com/q/13660/61563).
Basically, B3 rotates one row from the left face into the top face. F3 would work just as well, as would F₁3 or B₁3. As one row in Cubically 3x3x3 is three cubelets by one cubelet, this puts three `1`'s into the top face, giving it a face sum of 3. `%0` prints that top face sum, printing 3 for Cubically **3**x3x3.
In Cubically 4x4x4, rows are 4x1 cubies. Puts 4 1's into the top face, yielding a sum of 4.
[Answer]
# [Python](https://docs.python.org/), 196 bytes / 16 versions = score 12.25
The versions are 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, and 3.6  
Unfortunately I had to leave out 2.7 because there aren't any modules in it (as far as I can tell) that aren't in 2.6 but are in 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.)
```
We loop through a bunch of modules that were introduced in different versions of python, and at the first error we quit and return the version.
The gaps between major versions are filled in by repeatedly importing `os`.
The test for python 1.5 relies on `string.split` not being present until 1.6.
Credit to [Olivier Grégoire's answer](https://codegolf.stackexchange.com/a/139274/10894) for the idea of testing for new classes/modules in a loop.
I've now finally tested on all relevant versions of python...which required editing the 1.5 source code to get it to compile...
[Answer]
# [Brachylog](https://github.com/JCumin/Brachylog) / [Brachylog v1](https://github.com/JCumin/Brachylog/releases), 5 / 2 = 2.5
```
2,1hw
```
[Try it online!](https://tio.run/##SypKTM6ozMlPN/r/30jHMKP8/38A "Brachylog – Try It Online") (Brachylog)
[Try it online!](https://tio.run/##SypKTM6ozMlP///fSMcwo/z/fwA "Brachylog v1 – Try It Online") (Brachylog v1)
Explanation for 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)
```
Explanation for 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)
```
[Answer]
# Python 3 and Python 2.0, 18 bytes, score 18 / 2 = 9
```
print(3-round(.5))
```
Banker's rounding in Python 3, standard rounding in Python 2.
[Try it online - Python 3!](https://tio.run/##K6gsycjPM/7/v6AoM69Ew1i3KL80L0VDz1RT8/9/AA "Python 3 – Try It Online")
[Try it online - Python 2!](https://tio.run/##K6gsycjPM/r/v6AoM69Ew1i3KL80L0VDz1RT8/9/AA "Python 2 – Try It Online")
[Answer]
# Python 1,2,3, score 10.6667
```
print(len("a a\x20a".split()))
```
This only works if you feed it in as a command line argument instead of putting it in a file, as older versions of python won't default to utf-8 in a file but will in a command line argument.
Basically, the string consists of an 'a', an ogham space (3 bytes), an 'a', an escaped space character, and another 'a', and we just split it on whitespace, count how many strings we got, and print that.
* Python 3 correctly recognises the ogham space and the escaped space as whitespace, and so the string has 3 words.
* Python 2 incorrectly assumes all unicode characters are not whitespace, so it only counts the escaped space and gets 2 words.
* Python 1 fails to parse the escaped whitespace, I think because of the a after it, so it sees no spaces and gets 1 word.
[Answer]
# C89/C99, 25 bytes, 2 versions, score = 12.5
```
#include <stdio.h>
int main() {
    int v = 11 //**/ 11
            + 88;
    printf("C%d\n", v);
    return 0;
}
```
`//` style comments aren't recognized in C89.
Golfed version:
```
v(){return 20//**/2
+79;}
```
Try it online: [C89](https://tio.run/##S9ZNT07@/79MQ7O6KLWktChPwchAX19LS9@IS9vc0rr2v3JmXnJOaUqqgk1xSUpmvl6GHRdXZl6JQm5iZp6GpkI1lwIQFBQBhdI0lJxVU2LylHQUgMZpWoNloIYaWHPVcv3/l5yWk5he/F8XaJRtsoUlAA), [C99](https://tio.run/##S9ZNT07@/79MQ7O6KLWktChPwchAX19LS9@IS9vc0rr2v3JmXnJOaUqqgk1xSUpmvl6GHRdXZl6JQm5iZp6GpkI1lwIQFBQBhdI0lJxVU2LylHQUgMZpWoNloIYaWHPVcv3/l5yWk5he/F8XaJRtsqUlAA)
[Answer]
## Perl 5 and Perl 6, 23 bytes 19 bytes, score 9.5
```
print 6-grep '.',''
```
Perl 5 `grep` first op is always treated as a regex, not so in Perl 6.
[Answer]
## Bash, all 4 versions, ~~72~~ ~~71~~ 32 bytes ⇒ score = 8
```
s=$'\ua\xa\n';expr 5 - ${#s} / 2
```
This piece of code makes use of different interpretations of `$'...'` strings in each version of Bash.  
Outputs the major version number -- and that's it.
Doc found [here](http://wiki.bash-hackers.org/scripting/bashchanges).
### 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
```
This answer is halfly a guess; I only tested it in bash 4 and 3, but it should work on other versions too.
Let me know if it does / does not, I will try with other versions as soon as I have them available.
-1 char thanks to Jens.  
-29 bytes thanks to Digital Trauma (the whole `expr` idea)!
[Answer]
## R, versions 2 and 3, score: 10.5 points
```
cat(exists("cite")+2)
```
This command returns `2` for R 2.x.x and `3` for R 3.x.x. The function `cite` was added in R version 3.0.0. Therefore, the command `exists("cite")` returns `FALSE` for R 2.x.x and `TRUE` for R 3.x.x.
## R, all versions (1, 2, and 3), score: 12⅓ points
```
e=exists;cat(e("cite")+e("eapply")+1)
```
The function `eapply` was introduced in R 2.0.0.
[Answer]
# Erlang, 180 bytes, 11 versions, score 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)]]).
```
With indentation and line breaks:
```
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)]]).
```
Tested on one minor release of each major version since 10:
* R10B-9
* R11B-5
* R12B-5
* R13B04
* R14B04
* R15B03
* R16B03
* 17.5.6.2
* 18.2.1
* 19.2
* 20.0
The idea is that every major release has added at least one new allowable argument for the function `erlang:system_info`, so let's try the ones in the list, count how many of them fail, and subtract the number of failures from 20, which is the current version.
[Answer]
# [Windows' Batch File](https://en.wikipedia.org/wiki/Batch_file), 35 bytes / 2 versions = score 17.5
```
@if /i Z==z @echo NT&exit
@echo DOS
```
Prints `DOS` on MS-DOS (duh) and `NT` on Windows NT. (duh)
Now, for some explanation.
Windows has had batch scripting since MS-DOS times and it hasn't changed much since then. However, when [Windows NT](https://en.wikipedia.org/wiki/Batch_file#Windows_NT) came along, Microsoft changed the default interpreter for batch scripts, from `COMMAND.COM` to `cmd.exe` (now also allowing the extension `.cmd` as an alternative to the original `.bat`).
With that, they also implemented a [few changes](https://en.wikipedia.org/wiki/Cmd.exe#Comparison_with_MS-DOS_Prompt), such as the `/i` flag for ignoring string case on conditionals. That is, while `Z==z` is false, `/i Z==z` is true.
We exploit that DOS didn't have case insensitivy and compare uppercase `Z` with lowercase `z`. By using the `/i` flag, we end up with a `Z==z` (false) conditional on DOS and `z==z` (true) on NT.
Now, I realize that the challenge specifies that a version number should be printed. But, as far as I know, there is no 'version number' to batch scripting, so this is the closest I could get.
---
Tested on Windows 10, DOSBox and vDos:
**Windows 10:**
[![Windows 10](https://i.stack.imgur.com/Y45u3.png)](https://i.stack.imgur.com/Y45u3.png)
(run with `cmd /k` to prevend window closing on `exit`)
**DOSBox:**
[![DOSBox](https://i.stack.imgur.com/8hwdW.png)](https://i.stack.imgur.com/8hwdW.png)
**vDos:**
[![vDos](https://i.stack.imgur.com/jkcg0.png)](https://i.stack.imgur.com/jkcg0.png)
[Answer]
# Julia 0.4, 0.5, 46 bytes, score 22
```
f(::ASCIIString)=.4
f(::String)=.5
f()=f("")
```
Julia has changed the type name of the concrete and abstract String types in many versions.
This code in particular take advantage of:
**Julia 0.4**: 
* Concrete is `ASCIIString`,
* Abstract is officially `AbstractString`,
* Abstract has deprecated alias to `String`.
* Concrete is most specific than abstract so it wins dispatch
**Julia 0.5**: 
* Concrete is officially `String`,
* Concrete has deprecated alias to `ASCIIString`,
* Abstract is `AbstractString`, (though that doesn't matter here)
* As two methods have been defined for the concrete string type, the latter over-writes the former.
See also my [newer more effective solution based on different principles](https://codegolf.stackexchange.com/a/139537/4397)
[Answer]
# [Japt](https://github.com/ethproductions/japt/) (1 & 2), ~~8~~ 6 / 2 = ~~4~~ 3
```
'1r\S2
```
[Test v1](https://ethproductions.github.io/japt/?v=1.4.5&code=JzFyXFMy&input=)  **|**  [Test v2](https://ethproductions.github.io/japt/?v=2.0&code=JzFyXFMy&input=)
* 2 bytes saved thanks to [Oliver](https://codegolf.stackexchange.com/users/61613/oliver)
---
## Explanation
Prior to v2, Japt used a customised RegEx syntax, so we can take advantage of that.
```
'1
```
The number 1 as a string.
```
 r  2
```
Replace (`r`) the below with a `2`.
```
\S
```
Japt 2 sees this as the RegEx `/\S/g`, which matches the `1`. Japt 1 ignores the `\` escape character and just sees the `S`, which is the Japt constant for a space character and, obviously, doesn't match the `1`.
[Answer]
# [One and Two Star Programmer](https://esolangs.org/wiki/Three_Star_Programmer), 3 bytes/2, score 1.5
```
0 1
```
In One Star Programmer, the left most cell will point to cell 1,
in Two Star Programmer, it will point to cell 2
[Answer]
# Wolfram Language/Mathematica 10/11, 37 bytes / 2 versions = 18.5
Consider `(Length@DateRange[{1},{1}][[1]]+27)/3`, at 37 bytes and working with 2 versions, gives me a score of 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
```
and
```
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
```
I'm sure there is a more efficient way, but the discrepancy between the DateRange output bit me in the butt recently, so I was set on using that.
As a follow up, someone could probably take advantage of `Length@DateRange[{1}, {1}][[1]]` evaluating to `1` in Mathematica versions 1-~8, but I didn't have time to incorporate that.
[Answer]
# Ruby 1.x and 2.x, 20 bytes, score 10
```
p [].to_h&&2rescue 1
```
Based on the `to_h` method which was introduced on the `Array` class in Ruby 2.
[Answer]
# [APL (Dyalog)](https://www.dyalog.com/), score 7.3 or 3
### 51 bytes for 7 versions or 6 bytes for 2 versions
For the lowest score, distinguish versions 12 and 13 with:
```
12+≡⍳0
```
Twelve plus the depth of the first zero integers. Until version 12, `⍳0` (wrongly) returned the index origin as a scalar, i.e. depth 0. In version 13 and up, `⍳0` returns an empty list, i.e. depth 1.
---
Much more interesting is the following anonymous function which distinguishes all major versions 10 through 16 (the current). It needs a dummy argument (which is ignored) to run.
```
{2::10⋄⌷2::11⋄_←⎕XML⋄0::+/12⎕ML,≡⍳0⋄≡,/⍬::15⋄16@~0}
```
`{`…`}` an anonymous function which allows setting error guards `::` with a numeric error code (determining which type of error to catch) on the left, and on the right, the result to be returned in case of error.
 `2::10` if SYNTAX ERROR, return 10
 `⌷2::11` materialise (introduced in version 11) 2 (SYNTAX ERROR) which if happens, yields 11
 `⋄_←⎕XML` try: assign XML system function (introduced in version 12) to a dummy name
 `0::`…`⋄` if any error happens;
  `⍳0` first zero integers (gives 1 until version 12 and empty list from version 13)
  `≡` depth of that (0 until 12, 1 from 13)
  `12⎕ML,` prepend 12 and the **M**igration **L**evel (0 until 13, 1 from 14)
  `+/` sum (12 until 12, 13 in 13, 14 from 14)
 `≡,/⍬::15` try: concatenate the elements of an empty list (introduced in version 15) and get its depth, 2 (SYNTAX ERROR) which if happens, yields 15
 `⋄16@~0` try: amend with a 16 at (introduced in version 16) positions where logical NOT yields truth, applied to 0
Try it on [TryAPL](http://tryapl.org/?a=%7B2%3A%3A10%u22C4%u23372%3A%3A11%u22C4_%u2190%u2395XML%u22C40%3A%3A+/12%281%29%2C%u2261%u23730%u22C4%u2261%2C/%u236C%3A%3A15%u22C416a%7E0%7D%u236C&run) (slightly modified to pass security) and [Try it Online](https://tio.run/##SyzI0U2pTMzJT///v@xR24RqIysrQ4NH3S2PeraDmIZAZjxQ/FHf1AhfHyDHwMpKW9/QCMj39dF51LnwUe9msPLOhTr6j3rXALWYArmGZg51BrVAIxWAYgA "APL (Dyalog Unicode) – Try It Online")!
[Answer]
# Julia 0.2-0.7, bytes = 59, versions = 6, score = 9.833
```
f()=[4,0,3,0,5,2,6,7][endof(subtypes(AbstractArray))-16]/10
```
Turns out each version of julia has had a different number of abstract array subtypes. So we use the number of subtypes to index into an array that contains the version number.
The current nightly (0.7), currently has 25, but it is the fallback case anyway.
Julia 0.1 also has a different number of AbstractArray subtypes I would guess.
However, julia 0.1 does not have the `subtypes` function.
So I can't trivially retrieve them.
A significant improvement over [my previous answer.](https://codegolf.stackexchange.com/a/139523/4397)
(Thanks @one-minute-more for almost halving the bytecount)
]