text:
Determine your language's version
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!

Sandbox post. Related.

Language version built-in allowed?

@user202729 Your program may not use a builtin macro or custom compiler flags to determine the language version.

So you must use some function that behave differently in versions to determine version number? LogoVersion in LOGO (11 byte) fail. --- Is usage of bugs in previous versions which is fixed in newer versions allowed?

Can we output 3.0 for Python 3?

@fireflame241 on Python 3.0, not on Python 3.1 or anything else.

What is a language version number?  Who determines it?

@WheatWizard The author of the language determines this. It should be marked on some corresponding webpage or document.

@user202729 Yes, you must use some functionality that differs between language versions. Usage of bugs in previous versions is allowed, but if they don't work in newer versions they don't count toward your score.

I think that inverse-linear in the number of version does not welcome answers with high number of versions.

@user202729 I agree. Versatile Integer Printer did it well - score was (number of languages)^3 / (byte count).

Related.

Related

What is the version for a language? Isn't we define a language as its  interpreters / compilers here? Let we say, there is a version of gcc which has a bug that with certain C89 codes it produce an executable which behavior violate the C89 specification, and it was fixed on the next version of gcc. Should this count a valid solution if we write a piece of code base on this bug behavior to tell which gcc version is using? It targeting on different version of compiler, but NOT different version of language.

I don't get this. First you say "Your program's output should only be the version number.". Then you say "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." So the first rule is not actually a requirement?

Your program may not use a builtin, macro, or custom compiler flags to determine the language version. So... no way to complete this challenge in C++ ? In my knowledge, the only way to programmatically detect the C++ language version is by using the __cplusplus macro...

@HatsuPointerKun Try using differences between versions.

This was a fun question, I really enjoyed reading the answers. Thanks for asking!

Your program may use whatever method you like to determine the version number. Then: Your program may not use a builtin, macro, or custom compiler flags to determine the language version. Please don't condradict yourself in the spec.

@HatsuPointerKun That's to prevent "Python 2 --version and Python 3 --version, 0 bytes", which is no fun at all.

hmm... what's correct output if the program is written in x86 machine code?

Your score will be the code length divided by the number of versions it works in. Versions as in the number of releases it works on?

Seriously and Actually, 3 bytes, score 1.5
'1u

Try it online: Actually, Seriously
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).

Actually's README.md says that Actually is the spiritual successor to Seriously. Doesn't sound like a mere version change to me.

@Adám If you look at the branches in the repository, Seriously resides in the v1 branch. Prior to Seriously being deprecated, Actually resided in the v2 branch. Additionally, Seriously used 1.x version numbers in releases, while Actually uses 2.x (both there and on PyPI).

Python 3.0 and Python 2, score 6
(12 bytes, 2 versions)
print(3/2*2)

Try it Online:

Python 2
Python 3

Relies on the fact that Python 3+ uses float division by default, unlike Python 2, which uses floor division.

@MaltySen Your program should work in at least two versions of your language. It works in the at-least-two versions 2.7 and 3.0. I chose to print the full name or minor version numbers.

Oh I see, my bad.

OMG! Poor python developers

@RegisPortalez   from __future__ import division, problem solved :)

Java, 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!)
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!
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, 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):

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

Would you not score better with just 2 versions?

Ah, you beat me to it. Was currently writing this exact answer, and was looking at which classes were new in which versions. :) +1 from me. Also, you can golf some bytes by doing return"1."+(...);

@Shaggy I'm running for the most versions. Be my guest for a 2 versions solution ;)

Out of curiosity, where did you find which classes were new in which versions? Was trying to find an overview site for it, but couldn't find it 1-2-3.

@KevinCruijssen I opened the javadoc and ran classes with short names 1 by 1. But... I was helped a bit by this page: http://docs.oracle.com/javase/8/docs/technotes/guides/lang/enhancements.html

260 bytes Or maybe 1 more, don't know if return"... without space is possible in all versions tbh.)

@KevinCruijssen I was just doing it! Stop reading my mind X( Really, thanks anyways. ;) Also, I don't know if return"... works everywhere as well. I can test on 1.3 at the lowest and it's ok there.

@OlivierGrégoire We Java golfers always read each others mind. ;p

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

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 When I just finished incorporating your first changes, I saw you edited it... and made it even shorter than what I improved on your try! Good job to you, golfing so much! :)

Ooh, I did wonder about iterating an array and catching an exception, but you can go one better with finally{return"1."+i;}.

Seems to work even on 1.3, so I'll take it. Thanks @Neil ! :)

Doesn't javax.lang.model.SourceVersion work?

@MagicOctopusUrn it shows the version with which a class was compiled, not run. Also, it's only available since 1.6.

Not sure if it works in all versions, but I think you can save a byte by having Object instead of String as return-type, and change the ternary to return i<9?"1."+i:i;. Also, 2 (almost 3) more Java versions are available now. ;D

@KevinCruijssen I'm checking this answer from time to time and actually, I've found out, strangely, that none of Java 10, 11 or 12 added any new classes in java.util and its subpackages, and so far there are still no new classes planned in Java 13's java.util package. If I must support more versions, I'll probably fall back on java.lang. Until then, I stick to this answer. Regarding the golf, I don't have any versions < 7 available anymore so I cannot test it, unfortunately... So I'll adapt, with a warning.

@KevinCruijssen I took the time to update this answer with Java up to 18. Versions 10 and 13 have absolutely no new classes. I now check new classes directly on GitHub

New classes: Java 19 = java.lang.WrongThreadException, Java 20 = java.lang.foreign.Linker.Option, Java 21 = FormatItem (or SequencedSet if ever removed as part of preview).

Python, 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. 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.

Doesn't run on Python 3 (on TIO at least) due to print'0.9.1' being invalid syntax.

...Oh, no wonder. I was wondering why Sp3000 has put parentheses in every print call... Thanks for letting me know!

You can save 68 bytes by removing the specific types of errors (replace all excepts with except:).

Would this still work if you did x=<string inside eval> instead of just evaling the code manually?

@NoOneIsHere I thought, at first, that you couldn't because of all the 1/0's, but then I realized. Thanks!

@Blue Ah, no. SyntaxErrors thrown by regular code cannot be caught. They can only be caught when using eval or exec.

Can you take the whole code, swap out all those "except"s for "x", then call eval on that string.replace('x','except')? E.g. instead of try:from email import _Parser;print(2.2);1/0 except:0 do eval('try:from email import _Parser;print(2.2);1/0 xt:0'.replace('x','except')

I thought I was amazing for differentiating python 1 and 2 but wow, this is much more amazing.

We need python 3.7 and 3.8 now!

How about something like this: 496 bytes
Didn't try all the versions, but the concept should save a lot of bytes.

EcmaScript 3 / 5 / 2015 / 2016 / 2017 in Browser, 59 bytes / 5 versions = 11.8 points

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

Save 1 byte thanks to GOTO 0

Ninjaed! ;)

Netscape 7 only supported ES3? Wow, it's older than I thought...

You could save a few bytes using -! instead of +!! where it makes sense (and change the numeric constants accordingly).

Maybe some explanation? :)

@Derek: see my solution (linked above) for an explanation.

C++ 11/14/17, score = 147/3 = 49
To distinguish between C++11 and C++14/17, it uses the change in the default constness 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}.)

Cool answer! Welcome to the site :)

Great first answer! Note that you can golf the spaces between the include and the < in the include statements, for example #include<iostream>.

@MDXF Thanks, edited accordingly.

Hmm... if the rules were revised to forbid using standard library differences (which in this case indirectly uses the __cplusplus macro) - then to distinguish C++17 from C++14 I'd lean toward using the change in range-based for semantics.  Maybe create minimal iterator/sentinel classes along the lines of boost::integer_iterator such that converting sentinel to iterator has "surprising" behavior.

return 0; is implicit for main so you can save 9 bytes there. Also according to wc -c your solution is using 251 bytes and not 252 (your editor may have inserted a newline at the end).

@nwp Thanks, I wasn't aware of the implicit return 0. And you were also right about the newline at the end (I wonder when Emacs started doing that). Edited accordingly.

It is probably shorter to use  the lack of trigraphs to separate c++17 from c++14

@Potato44 Yes, that did indeed shorten the code drastically, thanks!

Would this work? return *=>return*

@Zachary Ah yes, of course, how silly of me. :) Will edit, thanks.

If you want to go for C++03, A<B<C>>::D>::E>::F can be valid in C++03 and C++11 with different meanings. Probably not easy to reduce score with this, though.

@aschepler Also probably not easy to keep the code using constexpr either. :)

You could write this as a function that returns the version as an int, instead of a program that prints it as a string. That lets you drop iostream.  You can also move the struct A declaration inside your function like int V(){struct A {...}const a; return 11 + a.v(0);}.  You can use long instead of float, because integer literals are int unless they're too large for an int.  (I tested that this works even when int and long are both 32-bit types, on gcc/clang with -m32).  Anyway, see https://godbolt.org/g/zRjHxt for my golfed version, with asm output showing that it works.

You don't need to specify the return type of main - it will default to int. This will save another 4 bytes.

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.

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
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 String method was introduced in ES2019 (v11).
The flat Array method was introduced in ES2020 (v10).
The dotAll property (and related s flag) for Regular Expressions was introduced in ES2018 (v9).
The padEnd String method was introduced in ES2017 (v8).
The includes Array method was introduced in ES2016 (v7).
The keys Array method was introduced in ES2015 (v6).
The map Array method was introduced in ES5.1 (v5).
The pop Array method was introduced in ES3 (v3).

Is ES 7 or ES 8 a valid version number? Maybe it should be called as ES 201x?

@tsh: Yes, they still use version numbers; they just use years for realese names.

PHP 5/7, score 5.5
<?=7-"0x2";

3V4L it online!
PHP 5.3.9/5.3.11, score 10
<?='5.3.'.(9-0x0+2);

3V4L it online!
The online version is longer because old PHP versions on the sandbox don't have short tags enabled.

x86 16/32/64-bit machine code: 11 bytes, score= 3.66
This function returns the current mode (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, 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.

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!):
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 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

I'm not sure these counts as different versions. Don't they just correlate to different system configurations.?

@Uriel: Running a block of machine code with the CPU in 16-bit mode, 32-bit mode, or 64-bit mode is the machine-code equivalent of running python2 vs. python3 interpreters on the same Python program.  New x86 CPUs always include a mode that's compatible with older CPUs (this is their only excuse for using such a convoluted hard-to-decode machine-code format!), but 386's 32-bit protected mode and x86-64's long mode really are new versions of x86 machine code.  Long mode even removed some opcodes, making them invalid.

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.

Who knew Pyth had versions?

Befunge : 15 11 bytes / 2 versions = 5.5
4 bytes shaved off by @Pietu1998
"89",;5-;,@

Try it online :
Befunge 93
Befunge 98
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.

"89",;5-;,@ for 11 bytes

@Pietu1998 Nice! If you want to post that as an answer, I'll gladly upvote :)

Go ahead and take it if you'd like, you figured out the ; part.

@Pietu1998 Edited in. Many thanks!

FYI, I managed to get it down to 7 bytes, taking a different approach. Link

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.
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 3x3x3.
In Cubically 4x4x4, rows are 4x1 cubies. Puts 4 1's into the top face, yielding a sum of 4.

Shouldn't the score be 4/∞?

Python, 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 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...

How about replacing the dots by spaces and use split() instead, saving three bytes? Also, i=i+1 can be i+=1.

any chance of adding 3.8, 3.9, 3.10, 3.11, 3.12?

Brachylog / Brachylog v1, 5 / 2 = 2.5
2,1hw

Try it online! (Brachylog)
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)

Great! As a sidenote, 2,1 in Brachylog v2 does not construct the list [2,1] (2;1 would), but rather the number 21 (which doesn't change the way you intended your answer to work).

@Fatalize Ooh thanks I confused that with Jelly...

@Fatalize BTW 2;1 wouldn't have worked in Brachylog v1 as ; means logical OR there.

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!
Try it online - Python 2!

wow I've always seen people differentiating python 2 and 3 by division

@LưuVĩnhPhúc well division is golfier, so that's why :P

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.

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.

score is 19/2 = 9.5

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

The shell grammar does not require a ;; in the last alternative. Use ; to shave off a byte.

I've just tried this on bash-2.05a (compiled just now for Cygwin), and it incorrectly reports "3", not "2" :(

the interpret-$'\xN feature seems to have been added in 2.01.1... I will have to update my answer. Working on it

can I ask you to try this? s="$'\ua\xa\n'";case ${#s} in 3)echo 4;;5)echo 3;;7)echo 2;;9)echo 1;esac

Sorry for delay. Nothing is returned. The length of $s appears to be 11 - the literal content of the quoted string. This also appears to be the case in bash  4.4.12

You might be able to golf this to something like s=$'\ua\xa\n';expr 5 - ${#s} / 2.  This works on v3 and v4.  I don't have working older versions to try right now.

@DigitalTrauma nice! the only new mechanism here is expr, so unless it was upgraded between Bash versions, this should work as well as mine (which I still haven't tested on v1 and v2)

why not replace expr with exit $[5-${#s}/2] to output via exit code to golf off?

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, C99

replace int v() with main(), it's shorter and will actually compile as a complete program!

@Andrea Thanks. AFAIK, it's allowed to post either functions or whole programs.

You're correct.

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.

R.version$major. 15 characters. I don't since when it exists.

@RuiBarradas Let me cite the OP: "Your program may not use a builtin, macro, or custom compiler flags to determine the language version."

Ok, sorry, I've missed that part. Should I delete the comment?

@RuiBarradas No problem. You don't need to delete the comment.

You should handle printing the result. Currently, when run as a full program this doesn't print anything.

Also e=exists;cat(e("cite")+e("eapply")+1) is 1 byte shorter (after you handle printing).

@JarkoDubbeldam Thanks for pointing out and the improvement hint.

No problem. Also take a look at the scoring, its not supposed to be in bytes. These would be 10.5 and 12.333 points respectively.

@JarkoDubbeldam Thanks for pointing this out too.

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

Windows' 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 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, 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:

(run with cmd /k to prevend window closing on exit)
DOSBox:

vDos:

Windows 7 is shorter than Windows NT.

@user202729 I suppose, but then again, 7 isn't really a language version, it has been the same on all Windows' since 3.1. So I didn't think it would be very fair to call it a 7 when it should maybe even be 3.1

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.

Japt (1 & 2), 8 6 / 2 = 4 3
'1r\S2

Test v1  |  Test v2

2 bytes saved thanks to 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.

One and Two 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

Welcome to Code Golf! Nice 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.

Fairly sure that your answer doesn't meet the requirements of the prompt, namely the last rule due to you using $Version: Your program may not use a builtin, macro, or custom compiler flags to determine the language version.

I'm only using $Version to demonstrate that it outputs the correct result in the correct version, $Version is not part of my answer...

All good friend - the thing is, you are using something like $VersionNumber, but instead you're calling it $Version.  To my mind, while the meat of your program is the Length@DateRange stuff, that wouldn't work without $Version just providing the full version information that you then process, which therefore violates the rules.

@Amndeep7 I see. I think there was some confusion, I edited my previous comment to try and clarify. $Version is not in any way required for my actual line of code to operate.

@Amndeep7 The submission is the 37 byte code inlined in the first paragraph. The code blocks are only output demonstrations.

Ahh I see, my bad - it's been a while since I've looked at Matlab code.  I guess I mistakenly thought the {1} stuff was how Matlab allowed one to access the results of a previous line in its REPL.

@Amndeep7 No problem! This isn't even Matlab though, which may have been your first mistake ;)

Now I feel like an even bigger dunce haha

Explanation: Using different format of time in different versions. That can be golfed more to {1} Tr[1^#&@@%~DateRange~%]/3+9 (31 bytes), or even 7+Length@Now (12 bytes)

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.

Nice first answer. I have no 1.x handy to test, but p [].to_h&&2rescue 1 is a bit shorter.

@manatwork Great, saves 3 bytes and works like a charm

APL (Dyalog), 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 Migration Level (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 (slightly modified to pass security) and Try it Online!

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.
(Thanks @one-minute-more for almost halving the bytecount)

Golfing this to 52 bytes, for a score of 8.7: [4,0,3,0,5,2,6,7][endof(subtypes(AbstractArray))-16].

@one-more-minute thanks. I do need to add some boilerplate, but that is still quiet a saving.

Befunge, score = 3.5
7 bytes, 2 versions
"]"'b.@

Try it online in Befunge-93
Try it online in Befunge-98
"]" is a string literal in both versions, pushing 93 (the ASCII value of [) onto the stack. 'b is a character literal in Befunge-98, pushing 98 (the ASCII value of b), but those are invalid instructions in Befunge-93, so they are simply ignored. We thus end with 93 on the top of the stack in Befunge-93 and 98 in Befunge-98. .@ writes out the value at the top of the stack and then exits.

]".@.b' or ]g.@.b' also work

Ruby 1.x (<1.9) and 2.x, 10 8 bytes, score = 4
$><<?2%7

Try it:

Ruby 1.8.7
Ruby 2.0.0

This works by exploiting the different behaviors of ?x between Ruby 1.x and 2.x. In Ruby 1.x, ?A (for example) returns 65 (the ASCII value of the character A), but in Ruby 2.0 it returns the one-character string "A".
The code above is equivalent to this:
val = ?2
$> << val % 7

In Ruby 1.x (<1.9), the value of val is 50 (the ASCII value of the character 2), a Fixnum. Fixnum#% is the modulo operator, so 50 % 7 returns 1.
In Ruby 2.x, val is the string "2". String#% is an infix version of sprintf, so "2" % 7 is equivalent to sprintf("2", 7), where "2" is the format string. Since the format string doesn't contain any format sequences (e.g. %d), subsequent arguments are discarded and "2" is returned.
Finally, $> is an alias for $stdout, so $> << ... prints the result.

Ooh, nice! I was trying to do something like ?A==66?1:2 before I came across your answer

Python 2 and Python 3, 36 34 bytes, score 18 17
print(str(hash(float('-inf')))[1])

In Python 2, the hash of negative infinity is -271828 but in Python 3 it's -314159. Edit: Saved 2 bytes, 1 point of score, thanks to @ArBo.

squints Is this a deliberate e vs pi thing?

@JoKing Yes; apparently when hash was first fixed to work on floating-point infinities the relevant developer used pi1e5 and e-1e5 as the hash values. At some point in Python 3 the has value for negative infinity got changed to be the negation of the hash value for infinity.

05AB1E/05AB1E (legacy)/2sable, score 9 8⅔ (26 bytes with 3 versions)
•äƵí•hR®di’ÿ (»Š)’ë’2sˆ¢’r

Try it online in 2sable
Try it online in 05AB1E (legacy)
Try it online in 05AB1E
Explanation:
Let's start with a bit of history of these three versions. The development of 05AB1E started at the start of 2016 (or actually, the very first git-commit was on December 21st, 2015). This new codegolf language was being built in Python as backend. Mid 2016 2sable was branched of that current 05AB1E version (July 7th, 2016 to be exact), and the strength of 2sable in comparison to that old 05AB1E version was added: implicit inputs. Later on implicit input was also added to 05AB1E, and 2sable became obsolete and basically a forgotten version right after it was created on that day July 7th, 2016.
Then in mid-2018, a new 05AB1E version was being started, this time completely rewritten in Elixir instead of Python, with loads of new builtins added and some builtins changed or even removed.
So, let's go over the code and see what it does in each of the three versions:
•äƵí•              # Legacy 05AB1E / new 05AB1E: push compressed integer 14793296
                   # 2sable: no-op (compressed integers didn't exist yet,
                   #         so nothing is pushed to the stack)
     h             # Convert this from an integer to a hexadecimal string: "E1BA50"
      R            # Reverse this string: "05AB1E"
                   # (2sable: the stack remains empty for `h` and `R`)
       ®           # Push -1
        d          # 2sable: check if -1 only consist of digits (falsey)
                   # 05AB1E (legacy): check if -1 is an integer (truthy)
                   # New 05AB1E: check if -1 is a non-negative (≥0) integer (falsey)
         i         # If it is truthy:
          ’ÿ (»Š)’ #  Push dictionary string "ÿ (legacy)",
                   #  where the `ÿ` is automatically filled with the top of the stack
         ë         # Else:
          ’2sˆ¢’   #  Push dictionary string "2sable"
                r  #  And reverse the stack
                   #  (05AB1E: stack changes from "05AB1E","2sable" to "2sable","05AB1E"
                   #   2sable: stack stays the same "2sable")
                   # (after which the top of the stack is output implicitly as result)

See this 05AB1E tip of mine (sections How to use the dictionary? and How to compress large integers?) to understand why ’ÿ (»Š)’ is "ÿ (legacy)", ’2sˆ¢’ is "2sable", and •äƵí• is 14793296.

Out of curiosity, is there a name for this sort of table/explanation method? Where the lines are ordered by English logic, but commands are padded to their place in the code.

@GezaKerecsenyi I to be honest have no idea. I kinda made it up for my answers tbh. I know some other people do their comments similarly, but no idea if it's a known convention and it has a name.

OK, thanks anyway!

Scratch (Squeak 1.x, 2.0, and 3.0) (scratchblocks3 syntax), 92 bytes, score 30.666...
when gf clicked
if<<[cos v]of(90)>=(0
say[3
else
add<not<>>to[l v
if<(l)=(1
say[1
else
say[2

Ungolfed, with explanation:
when gf clicked
if<<[cos v] of (90)> = (0) // cos 90 is 0 in Scratch 3, and some nonsense number in other versions
    say [3]
else
    add<not <> > to [list v] // "add <true> to a list" - this adds "1" to the list in 1.x, and the string "true" to the list in later versions
if<(list) = (1)> // all versions of Scratch automatically typecast everything to everything, including lists to strings, allowing for comparisons like this to be done seamlessly
    say[1]
else
    say[2]
end
end

Python 3, Python 2, score 17.5
(35 bytes, 2 versions)
try:exec("print 2")
except:print(3)

Python 2, 35 bytes
Try it online!
Python 3, 35 bytes
Try it online!
Saved 5 bytes thanks to ETHproductions
Not a good code golf answer, but a massive change!

Hmm, can you put each statement on the previous line? I.e try:exec("print 2")\nexcept:print(3)

@ETHproductions thanks! I didn't expect to win, thus I was a bit distracted. I mainly wanted to focus on the massive change between Python 2 and 3.

PHP 4, 5, & 7: 59 bytes, score 19.67
<?list($a[],$a[])=array(5-strrpos('112','11'),7);echo$a[1];

It's way long but it does 3 versions!
list() assigns in backwards order in PHP 4 & 5, strrpos() only searches for a single character in PHP 4.

C++11 and C++14, 96 bytes, score 48
#include<iostream>
#define M(x,...)__VA_ARGS__
int main(){std::cout<<(int[]){M(1'2,1'4,11)}[0];}

The code is based on the digit separator proposal which has very similar example code at the end.
online version

Braingolf, 4 bytes, 2 versions, score = 2
0n6+

Try it online!
n (negate) was added in braingolf v0.7, meaning this will output 7 in v0.7 and newer, and 6 in v0.6 and older
In v0.7, n "negates" the 0 to a 1, then adds it to 6 to make 7, but in v0.6, the n does nothing, and so 0 is added to 6, resulting in 6. Both versions have implicit output.
This is technically the minor version, however there is only 1 major version of Braingolf, as Braingolf v1.0 isn't a thing yet, so this is about as major as the version numbers get.

Idea of the solution
Each version hava added a new syntax features, so code vith them will cause a syntax error in smaller versions of the language.

ES5: Octal constants 03 are disallowd in strict mode (unused in actual solutions)
ES6: Octal constants 0o6 are introduced
ES7: Pow operator is introduced: 7**1
ES8: Trailing comma in function call is allowed: f(8,)
ES9: Tagging of invalid strings is allowed: f`\u9`

So evaluating
eval('9;'+s)

on one of the examples will either return the the value, or throw a SyntaxError. But what value would it return? For all ES6-ES8 snippets the last calculated value will be the version. In ES9 snippet the 9 from 9; is return. So if we place a minimal supported version into catch block like
eval(`try{eval('9;'+s)}catch(e){6}`)

we'll get the behaviour we want.

Ecmascript 5+ (for 5, 6, 7, 8, 9); 124 / 5 = 24.8 points

alert(Math.max.apply(0,'0o6~7**1~f(8,)~f`\\u9`'.split('~').map(function f(s){return eval("try{eval('9;'+s)}catch(e){5}")})))

Tested in:

IE8: Error (Object doesn't support property or method 'map')
IE 11: 5
Edge 14: 8
Chrome 60: 8
Firefox 55: 9

Ecmascript 6+ (for 6, 7, 8, 9); 96 / 4 = 24 points

alert(Math.max(...'7**1~f(8,)~f`\\u9`'.split`~`.map(f=s=>eval(`try{eval('9;'+s)}catch(e){6}`))))

Tested in:

Edge 14: 8
Chrome 60: 8
Firefox 55: 9

Oh, now this is very nice :) I'm not sure about the inclusion of ES9, though, seeing as the official spec doesn't exist yet. I'd suggest including an explanation to help those unfamiliar with JS to understand what's going on here. Also, could you save any bytes using reduce instead of max? Oh, and this outputs 8 for both in Edge 14, if you want to include it.

@Shaggy, here is a single feature for ES 2018 which already got out of ES next and I used it.

Ah, I wasn't aware that that had made it out.

@Shaggy, added a description.

Lua 5.3.3 / 5.2.4, 32 bytes / 2 = 16 points
print(54-#("a"):gsub("a?$","a"))

This actually abuses a bug in Lua 5.2's string.gsub function: In Lua 5.2, "a?$" would first match "a{endOfString}" and then "{endOfString}" a second time, which is obviously incorrect, because gsub may only match each character/anchor in the string once. This results in "a" being substituted into the string twice, giving a final string length of 2.
In Lua 5.3, the bug is fixed, so "a?$" only matches "a{endOfString}", thus matching the end of the string only once, which is the correct behavior. Therefore, "a" is substituted into the string just once, resulting in a string length of 1.
The difference between the string length and 54 then gives the major/minor version number of the Lua interpreter, which is printed as follows:
Lua 5.2.4: 52
Lua 5.3.3: 53
(I could only test on these two specific versions, but it should work on more)

Japt, 4 bytes / 2 versions = 2
J\+2

Japt | Japt 2.0
Alternative:
2\/2

Japt | Japt 2.0

Wolfram Language (Mathematica), 30 bytes (5<= Score <=10)
Floor[.8+Length@Names@"*"/615]

I tested this on Mathematica 10.2, which has 5683 named symbols and 11.3, which has 6280 names symbols.  I used cloud.wolfram.com to test it on Mathematica 12.0 which has 6914 named symbols.  With possibly some slight tweaking to the numbers, this could work for as many as 6 versions (see the graph at https://blog.wolfram.com/2018/06/21/weve-come-a-long-way-in-30-years-but-you-havent-seen-anything-yet/) which shows that the function count has grown pretty much linearly since v6.)
Try it online!

27 bytes

Python 1, 2, and 3, 43 33 bytes, score 14.333 11
-10 bytes by using and and or instead of an if/else statement
print(1and str(1<2)=="1"or 3/2*2)

Yes, there are already submissions for Python, but this one also differentiates Python 1 and 2.
The difference between Python 3 and 2 are pretty well known, but with Python 1? It's very similar to Python 2.
But I found something.
In Python 1, a true statement evaluates to 1. In Python 2 and 3, it evaluates to True. By turning a true statement into a string, you can differentiate Python 1 and the later versions.

You can save 6 bytes by getting rid of the 1and and switching the condition to <"2". But you'll also need to add 5 bytes (unless there's a golfier way) to convert 3/2*2 to an int, since Python 3 computes it as a float 3.0, which isn't a valid output format for this challenge.

Whispers, 35 bytes / 3 versions = 11.66
>> R2
>> -1
> 3
> 2
> 1
>> Output 3

Try it online! (Whispers v1)
Try it online! (Whispers v2)
Unfortunately, Whispers v3 isn't currently on TIO, so you'll have to download it from the repo to try it.
How they work
This relies on the feature in Whispers which removes lines that contain (among other things) invalid instructions from the code before numbering the lines for execution.
All three programs work by calling line 3 and outputting the number on that line. However, by removing lines that contain invalid instructions, we change which line line 3 actually is. As they all just output line 3's result, I'll focus the explanations on which line is line 3 and why.
v1
In version 1, neither of the first two lines are valid instructions. Therefore, the code passes to the executor is
> 3
> 2
> 1
>> Output 3

and line 3 simply returns \$1\$
v2
In version 2, the first line >> R2 is now a valid instruction: it takes a vector and outputs its polar form (i.e. magnitude and angle). However, the second line >> -1 is not yet valid, so the interpreter sees
>> R2
> 3
> 2
> 1
>> Output 3

The first line shifts line 3 to refer to > 2, which just returns \$2\$.
v3
The entire program is valid in the latest version Whispers, which includes a massive expansion of builtins, but the shortest new addition is the negate command: >> -1, which does not return \$-1\$, rather it takes in an argument and negates in. Therefore, the interpreter sees
>> R2
>> -1
> 3
> 2
> 1
>> Output 3

Meaning that line 3 is now > 3, which, you guessed it, returns \$3\$.

Nim, 28 bytes / 2 versions = score 14
echo int compiles uint64.low

Try it online! (TIO only supports one version)
In version 1.0, uint64 was made a proper ordinal type, so it's now possible to determine its lower bound. The program simply checks if the expression uint64.low compiles and converts the bool to an integer.

Vyxal 3 G, 4 bytes, 2 versions = Score 2
2#[3

Vyxal 3
Vyxal 2
Lists in Vyxal 3 start with #[ which is commented out in Vyxal 2.

2 bytes using the Ṫ flag, for a score of 1.

VBA, 51 Bytes / 2 Codes = 25.5
Anonymous VBE immediate window function that outputs the VBA program version - works only in Excel 2011 and later. Outputs Version 7 for windows and Version 6 for Mac, as mac has yet to get version 7 of VBA
Uses conditional compilation constant Mac to determine the VBA  language version
Sub a()
o=7
#If Mac Then
o=6
#End If
Debug.?o
End Sub

@Shaggy, missed that, corrected

Lua 5.0, 5.1, 5.2, 5.3, score: 17.75
print("5."..(table.getn or load'return #...'){math.fmod,_ENV,math.ult})

math.fmod was math.mod before 5.1
_ENV was introduced in 5.2 for new environment system
math.ult was introduced in 5.3
There was a problem: lua 5.0 don't know # for tables, but lua >= 5.2 don't have function table.getn, so I keep # isolated in string for lua 5.0, and loads in instead of table.getn for lua >= 5.2.

K/Kona, 6 bytes, 2 versions - score 3
-4+@,0

Version 3 defaults to long numeric types, whereas 2 defaults to integer numerics. We enlist (,) to get a positively typed number (atoms are negative), we get its type (@), and we add that to -4.

RProgN 1/2, 4 bytes / 2 versions. Score = 2
1 1+

RProgN1 requires commands to be split into words, where as RProgN2 reads byte by byte by default. As such, RProgN1 can't do anything with 1+, so it just outputs 1, but RProgN2 can execute it, so it adds 1 to the 1, giving 2.
Try RProgN1
Try RProgn2

T-SQL, 41 bytes / 11 versions = 3.7 score
SELECT MAX(cmptlevel)/10FROM sysdatabases

Note that this does not use a SQL "builtin, macro, or custom compiler flag"; that would be something like SELECT @@VERSION or SELECT SERVERPROPERTY('productversion').
Instead, this looks up the highest "compatibility level" for all databases on the server. Existing databases on a server might have older compatibility levels, but the system database tempdb is recreated each time the server is restarted, so will always have the compatibility level of the actual current version. (Using MAX is shorter than including WHERE name='tempdb').
I divide by 10 so it returns the actual SQL version number.
I've successfully tested this on all versions between SQL 2005 and 2017, but I believe this will ultimately work in 11 distinct versions:
Version Number    Release Name
6                 SQL Server 6.0
6.5               SQL Server 6.5
7                 SQL Server 7.0
8                 SQL Server 2000
9                 SQL Server 2005
10                SQL Server 2008 (or SQL Server 2008 R2)
11                SQL Server 2012
12                SQL Server 2014
13                SQL Server 2016
14                SQL Server 2017
15                SQL Server 2019 (Pre-release)

Let me know if anyone has SQL 2000 or older still running to see if this works as expected.
Note that my code uses a deprecated system table for widest compatibility, I'd normally use the newer sys.databases system view introduced in SQL 2005.

SmileBASIC (2 and 3), 4.5 bytes
Thank you 12Me21 for helping out.
?3+CANCEL

In SB, variable declaration rules are lazy by default; if a variable name is not declared or assigned anywhere in scope, it is assumed to be 0. There's also a handful of reserved system variables and constants which varies between version and platform.
In SB v2, CANCEL was a reserved variable that represented -1; this was intended for use with RESULT to check the state of a dialog box or other action. In SB v3, this variable is not present.
Thus, when this program is run on a standard SB v2 environment it prints 2, and on a v3 environment it prints 3.

Whitespace, 43 bytes, 2 versions, score 21.5
Version 0.3 of Whitespace added the copy and slide instructions. Of those two, slide is exploited here. Slide removes the top n elements of the stack, keeping the top element. The code for version 0.3 slides 2 and version 0.2 ignores the slide and keeps the 2.
SS
T
STSSSTT
SSSTS
SSSTSTTTS
ST
ST
T
SST
ST

Written as more readable Whitespace assembly:
push 0   # Push 0 to the stack
printi   # Print 0 as an integer
push 3   # Push 3 to the stack
push 2   # Push 2 to the stack
push '.' # Push 46 ('.') to the stack
slide 1  # Pop 2 if version 0.3 or skip instruction
printc   # Print 46 as character '.'
printi   # Print 2 or 3 as integer

PHP (42 chars, 4 versions) - score 10.5
echo max('$',0)?@(date(c)==c?4:7-"0x2"):8;

With the @ error control operator you shouldn't see the “Use of undefined constant” notice.
PHP (59 chars, 4 versions)
This 15 chars per version attempt is based on fdiv, ereg and idate existence.
The line must be runnable through the codes from the years 2000 to 2022.
$a='is_callable';echo$a('fdiv')+6-2*$a('ereg')+$a('idate');

Both write a single character to stdout among 4,5,7 and 8, checked with 3v4l.org.
Interesting change between 7 and 8 :
echo max('$', 0) === max(0, '$') ? 8 : 7 ; // custom version detector

PostScript, 36 bytes/3 versions = score of 12
00000000: 92aa 9238 283c 3c29 9260 7b28 7368 6669  ...8(<<).`{(shfi
00000010: 6c6c 2992 607b 337d 7b32 7d92 557d 7b31  ll).`{3}{2}.U}{1
00000020: 7d92 553d                                }.U=

Un-tokenized:
systemdict dup(<<)known{(shfill)known{3}{2}ifelse}{1}ifelse =

Tests for operators introduced in PostScript Levels 2 and 3.
<< was introduced in PS level 2. If this isn't present, it's PS level 1.
shfill was introduced in PS level 3. If this isn't present, it's PS level 2. (xpost currently prints 2, as shfill isn't implemented: Try it online!)
Ghostscript prints 3.

Julia: 21 bytes, score: 10.5
(length([1:2])+V)/10   # where V takes value critical version minus 1

I cannot quite remember which version of julia this changed in (stuff gets deprecated very often), but there was some point in the language where this:
julia> [1:2]
2-element Array{Int64,1}:
 1
 2

became this:
julia> [1:2]
1-element Array{UnitRange{Int64},1}:
 1:2

from one version* to the next. I think it was probably from v0.3 to v0.4? (in which case V = 2)

* julia is still in major version 0

Mathematica 10/11 20 Bytes, Score=10
Since Echo was introduced in version 11
10+Echo@1/.Echo@1->0

Can extend to version 9 as well (since AbsArg was intro'd in V10) with
10-Last@AbsArg@1+Echo@1/.Echo@1:>0

but the score goes up to 34/3 or 11.33

Python 2/3 REPL, 36 33 bytes, 36 33/2=38 16.5 score
[3,2]['cmp' in dir(__builtins__)]

Try it in a Python shell. It (ab)uses removed builtins in Python 3. cmp was a builtin in Python 2, but was removed in Python 3, and it would result a truthy value in Python 2 and falsey in Python 3, and use it to index the [3,2] list, if it is 0, then it would output 3 and for 1 it would output 2.
To make this solution, first I took the bulitins list from Python 2, made it a set, and subtracted set of Python 3 builtins from it
s={'ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BufferError', 'BytesWarning', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'ReferenceError', 'RuntimeError', 'RuntimeWarning', 'StandardError', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '_', '__debug__', '__doc__', '__import__', '__name__', '__package__', 'abs', 'all', 'any', 'apply', 'basestring', 'bin', 'bool', 'buffer', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'cmp', 'coerce', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'execfile', 'exit', 'file', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'intern', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'long', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'raw_input', 'reduce', 'reload', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip'}-(set(dir(__builtins__)))

Which is
{'reduce', 'cmp', 'basestring', 'reload', 'file', 'unicode', 'buffer', 'execfile', 'apply', 'raw_input', 'unichr', 'coerce', 'StandardError', 'xrange', 'intern', 'long'}

And for good sort from smallest to largest
sorted(s,key=lambda x:len(x))

So we could use these builtins, amongst them, cmp is the shortest:
'cmp', 'file', 'long', 'apply', 'reduce', 'reload', 'buffer', 'unichr', 'coerce', 'xrange', 'intern', 'unicode', 'execfile', 'raw_input', 'basestring', 'StandardError'

extra whitespace following 'cmp'

You can also save 3 bytes by subtracting from 3 instead of indexing into a list.

q, 4 bytes / 13 major versions: score 0.3077
.z.K

Built-in: https://code.kx.com/q/ref/dotz/#zk-version
Same for k4.


text:
Palindromic numbers with a binary twist
Warning : this is NOT a "hey, let's draw a cake in ASCII-art" challenge! Please keep reading ;)
Some time ago it was my birthday, I'm 33 now.
So there is this awkward social tradition consisting in inviting family and friends, putting number-like candles on a cake, sing songs and open gifts.
   33
--------

Instead of numbers, I can use the binary system to put standard candles: I place 6 of them on the cake and light two of them.
 100001
--------

I can see that both decimal and binary numbers of my age are palindromic!
Challenge
I want to know if any other number can be put on a cake with candles and be palindromic, decimal and binary.
Write a program/function to test if a number is palindromic in both decimal and binary. But wait, there's more : in binary, leading zeros count for the test!
Input
A decimal number x that I want to test if it is birthday palindromic with 0 < x < 232-1 (yes, the people in my dimension live very long)
Output
Truthy if it meets exactly these two conditions, Falsey else:

The decimal representation of the number is a standard palindrome
The binary representation of the number is a standard palindrome, and adding leading zeros may help with this

Test cases
1 > 1 => Truthy
6 > 110 (0110) => Truthy
9 > 1001 => Truthy
10 > 1010 (01010) => Falsey, 10 is not palindromic
12 => 1100 (001100) => Falsey, 12 is not palindromic
13 => 1101 (...01101) => Falsey, neither 13 nor 1101 are palindromic
14 => 1110 (01110) => Falsey, 14 is not palindromic
33 > 100001 => Truthy
44 > 101100 (..0101100) => Falsey, 101100 is not palindromic
1342177280 > 1010000000000000000000000000000 (00000000000000000000000000001010000000000000000000000000000) => Falsey, 1342177280 is not palindromic (but the binary representation is)
297515792 > 10001101110111011101100010000 (000010001101110111011101100010000) => Truthy

Rules

Standard loopholes are disallowed
Built-in library conversions and tests are allowed
This is code-golf, the shortest code win!

Good luck, and eventually happy birthday!

Sandbox

Might want to change the title as the birthday part is irrelavent.

@NoOneIsHere well the challenge is about candles on a birthday cake. Also there's the twist on the binary representation so it's not "generic palindromic numbers". If your comment is upvoted I'll come up with another title.

So, according to the rules, 0b01010000000000000000000000000000 is not palindromic since it would require more zeroes to be added and thus exceed 2^32-1? In this case it would help to add something like 1342177280 as a falsey test case.

@w0lf I didn't write a limit for adding zeros but I understand your stack overflow problem ;) Furthermore, 1342177280 is not decimal palindromic so Falsey. Editing

@Goufalite You are right, of course. A better example would be 297515792 (10001101110111011101100010000 in binary)

Ok, adding the test case. I suppose it is no more a problem since everyone here trim the trailing zeros instead of appending them for the test ;)

05AB1E, 7 bytes
b0Ü‚DíQ

Try it online!
or as a Test Suite
Explanation
b         # convert input to binary
 0Ü       # remove trailing zeroes
   ‚      # pair with input
    D     # duplicate
     í    # reverse each (in the copy)
      Q   # check for equality

Bifurcate didn't help?

@MagicOctopusUrn: Unfortunately not, as I want to reverse each number in the list and not the list itself.

Python 3, 59 bytes
lambda a:all(c==c[::-1]for c in[str(a),bin(a).strip('0b')])

Try it online!
-3 bytes thanks to Rod
-3 bytes thanks to Connor Johnston

you can swap the double lambda with list comprehension

using strip with strings will remove single characters: bin(a)[2:].strip('0') => bin(a).strip('0b')

@ConnerJohnston o cool, thanks!

JavaScript (ES6), 65 bytes
Returns 0 or 1.
n=>(g=b=>[...s=n.toString(b)].reverse().join``==s)()&g(2,n/=n&-n)

How?
The helper function g() takes an integer b as input and tests whether n is a palindrome in base b. If b is not specified, it just converts n to a string before testing it.
We get rid of the trailing zeros in the binary representation of n by isolating the least significant 1 with n&-n and dividing n by the resulting quantity.
Fun fact: it's truthy for 0 because (0/0).toString(2) equals "NaN", which is a palindrome. (But 0 is not a valid input anyway.)
Test cases

let f =

n=>(g=b=>[...s=n.toString(b)].reverse().join``==s)()&g(2,n/=n&-n)

console.log(f(1 )) // Truthy
console.log(f(6 )) // Truthy
console.log(f(9 )) // Truthy
console.log(f(10)) // Falsey
console.log(f(12)) // Falsey
console.log(f(13)) // Falsey
console.log(f(14)) // Falsey
console.log(f(33)) // Truthy
console.log(f(44)) // Falsey

Mathematica, 52 49 bytes
i=IntegerReverse;i@#==#&&!i[#,2,Range@#]~FreeQ~#&

Try it on Wolfram Sandbox
Usage
f = (i=IntegerReverse;i@#==#&&!i[#,2,Range@#]~FreeQ~#&);

f[6]

True

f /@ {9, 14, 33, 44}

{True, False, True, False}

Explanation
i=IntegerReverse;i@#==#&&!i[#,2,Range@#]~FreeQ~#&

i=IntegerReverse                                   (* Set i to the integer reversing function. *)
                 i@#==#                            (* Check whether the input reversed is equal to input. *)
                       &&                          (* Logical AND *)
                          i[#,2,Range@#]           (* Generate the binary-reversed versions of input, whose lengths *)
                                                   (* (in binary) are `{1..<input>}` *)
                                                   (* trim or pad 0s to match length *)
                                        ~FreeQ~#   (* Check whether the result is free of the original input *)
                         !                         (* Logical NOT *)

Version with builtin PalindromeQ
PalindromeQ@#&&!IntegerReverse[#,2,Range@#]~FreeQ~#&

Pyth - 13 bytes
&_I.s.BQ`Z_I`

Test Suite.

You can use _MI and jQ2 to save 2 bytes: `_MI,.sjQ2Z``

Jelly, 8 bytes
Bt0ŒḂaŒḂ

Try it online!

You probably want ȧ or a instead of µ because otherwise this will always be truthy.

@EriktheOutgolfer whoops thanks

Japt, 14 bytes
s ê¬©¢w n2 ¤ê¬

Test it online!
Explanation
 s ê¬ © ¢   w n2 ¤  ê¬
Us êq &&Us2 w n2 s2 êq   Ungolfed
                         Implicit: U = input integer
Us êq                    Convert U to a string and check if it's a palindrome.
        Us2 w            Convert U to binary and reverse.
              n2 s2      Convert to a number, then back to binary, to remove extra 0s.
                    êq   Check if this is a palindrome.
      &&                 Return whether both of these conditions were met.

Came up with a couple of similar solutions for 13 bytes: sêQ *(Â¢w)sêQ and sêQ &¢w n sêQ

@Shaggy Thanks, but unfortunately those both fail on 297515792 (the reversed binary converted to decimal is just too big for JS to handle)...

Proton, 57 bytes
a=>(b=c=>c==c[to by-1])(str(a))*b(bin(a)[2to].strip('0'))

Try it online!

APL, 27 31 Bytes
∧/(⌽≡⊢)∘⍕¨{⍵,⊂{⍵/⍨∨\⍵}⌽2⊥⍣¯1⊢⍵}

How's it work?  Using 6 as the argument...
      2⊥⍣¯1⊢6 ⍝ get the bit representation
1 1 0

      ⌽2⊥⍣¯1⊢6 ⍝ reverse it (if it's a palindrome, it doesn't matter)
0 1 1

      {⍵/⍨∨\⍵}⌽2⊥⍣¯1⊢6 ⍝ drop off the trailing (now leading 0's)
1 1

      6,⊂{⍵/⍨∨\⍵}⌽2⊥⍣¯1⊢6 ⍝ enclose and concatenate the bits to the original number
┌─┬───┐
│6│1 1│
└─┴───┘

      (⌽≡⊢)∘⍕ ⍝ is a composition of
      ⍕ ⍝ convert to string and
      (⌽≡⊢) ⍝ palindrome test

      (⌽≡⊢)∘⍕¨6,⊂{⍵/⍨∨\⍵}⌽2⊥⍣¯1⊢6 ⍝ apply it to each of the original argument and the bit representation
  1 1

      ∧/(⌽≡⊢)∘⍕¨6,⊂{⍵/⍨∨\⍵}⌽2⊥⍣¯1⊢6  ⍝ ∧/ tests for all 1's (truth)
  1

Try it on TryAPL.org

According to the specs, 6 is supposed to be a good input, but the expression provided return false.

Ah, rats!  That's what I get for not reading the problem in its entirety.  Good catch. thank you!  I've amended with a slightly longer, but hopefully more correct, solution.

Welcome to PPCG. Nice first post! Unfortunately, your submission in its current form is neither a program, nor a function. No worries though, you can make it into a function but letting the outer braces enclose the entire code.

Save three bytes: {(⌽¨≡⊢)⍕¨⍵,⊂(⌽↓⍨~⊥~)2⊥⍣¯1⊢⍵} (it is good form to provide a link to run the entire test suite)

Brachylog, 7 bytes
↔?ḃc↔.↔

Try it online!
That's a lot of ↔'s…
Explanation
With the implicit input and output, the code is: ?↔?ḃc↔.↔.
?↔?        The Input is a palindrome
   ḃ       Convert it to the list of its digits in binary
    c      Concatenate it into an integer
     ↔     Reverse it: this causes to remove the trailing 0's
      .↔.  The resulting number is also a palindrome

Perl, 53 +3 (-pal) bytes
$_=sprintf"%b",$_;s/0+$//;$_="$_/@F"eq reverse"@F/$_"

try it online

APL (Dyalog Classic), 26 bytes
{≡∘⌽⍨⍕⍵,⍵,⍨(<\⊂⊢)⌽2⊥⍣¯1⊢⍵}

Explanation
                  2⊥⍣¯1⊢⍵  encode ⍵ as binary
                 ⌽         reverse
           (<\⊂⊢)          partition from first 1
      ⍵,⍵,⍨                prepend and append ⍵
    ⍕                     turn into text string
≡∘⌽⍨                       match text with its reverse (f⍨X is XfX, where f is a composed function that reverses its right argument and matches with left)

Try it online!

Ooh, you out-golfed BB!

Octave, 68 66 bytes
@(x)all([d=num2str(x) b=deblank(['' dec2bin(x)-48])]==flip([b d]))

Try it online!
Initial offering from Octave.
We basically create an array containing the number as a decimal string and the number as a binary string with trailing 0's removed. Then we create an array with the same to strings but with the binary and decimal numbers flipped. Finally both arrays are compared and the result is either true if they match (both palindromes) or false if they don't (one or both not palindromes).

Save 2 bytes using flip instead of fliplr.

Pyt, 10 bytes
Returns [1] if true, [0] if false
ĐɓƖ₫áĐ₫=ʁ∧

Try it online!
Explanation:
              Implicit input
Đ             Duplicate input
ɓ             Get input in binary (as string)
Ɩ             Cast to integer
₫             Reverse the digits (this removes any trailing zeroes)
á             Push the stack into a list
Đ             Duplicate the list
₫             Reverse the digits of each element of the list
=             Are the two lists equal element-wise
ʁ∧            Reduce the list by bitwise AND

C# (.NET Core), 130 129 179 173 + 23 bytes

a few things, thank you to  Ed Marty for pointing out that i need to check for as many 0's padded in front for a palindrome. And i need to make sure that i can check up to x^32-1.
x=>{var a=Convert.ToString(x,2);var b=x+"";Func<string,bool>p=z=>z.SequenceEqual(z.Reverse());return new int[a.Length].Select((_,z)=>p(new string('0',z)+a)).Any(z=>z)&p(b);}

Try it online!

You can remove the space between return and ( for 129 bytes

This only works when adding at most one leading 0, but the problem specifies multiple leading zeros are allowed.

@EdMarty that has been handle, as well as the stack overflow bug.

you are missing a using System; and using System.Linq

or is that the +23 bytes?

@LiefdeWen my namespace is System.linq, and that's the +23 bytes.

Retina, 72 bytes
.+
$*_;$&
+`(_+)\1
$+0
0_
_
0+;
;
+`\b(\w)((\w*)\1)?\b
$3
(\B;\B)|.*
$.1

Try it online! Link includes test cases. Works by creating a unary duplicate of the original number, but using _s so that it's not confused by e.g. an input of 11. The unary number is then converted to "binary" and trailing zeros stripped. Palindromes then get successively truncated and the last stage tests whether there is anything left.

Mathematica, 70 bytes
(P=PalindromeQ)[PadRight[#~IntegerDigits~2,#~IntegerExponent~2]]&&P@#&

Husk, 14 bytes
¤&S=↔ȯ↓=0↔ḋ⁰d⁰

Try it online!
Ungolfed/Explanation
             d⁰  -- digits of input in decimal
          ḋ⁰)    -- digits of input in binary
         ↔       --   reverse
     (↓=0        --   and drop all leading zeros
¤&               -- test the two lists if
  S=↔            --   they're equal to their own reverse

Gaia, 10 bytes
ṙṭ@ḍ2⁻Πbṭ∧

Try it online!
Explanation
Instead of checking with leading zeroes in binary, I check without without the trailing zeros.
ṙ           String representation of number
 ṭ          Is palindromic?
  @         Push input again
   ḍ        Prime factors
    2⁻      Remove all 2s
      Π     Product
       b    Convert to binary
        ṭ   Is palindromic?
         ∧  Logical and

C (gcc), 105 bytes
r(n,b){int s=0,c=n;for(;n;n/=b)s=s*b+n%b;return s==c;}
c;f(n){for(c=n;c%2<1;c/=2);return r(n,10)&r(c,2);}

Try it online!

You can replace both occurrences of return  with n=. (95 bytes.)

And you can remove the new line for an additional byte saved.

Pyth, 25 22 19 18 17 bytes
-3 6 7 8 bytes by learning the language further
Ks_.Bsz&_IzqKs_`K

Explanation:
Ks        Set K to the integer version of...
 _.BsJ    Reverse string of the binary input
&         And
 _Iz      Is the input equal to the reverse of itself?
 qKs_`K   Is K equal to int(the reverse of basically string(K))

I am sure that this can be golfed down, I'll be working on that.
Test Suite

Python 2, 56 bytes
lambda n:all(s==s[::-1]for s in(`n`,bin(n).strip("0b")))

Try it online!
Uses Python's strip method to both remove the bin(..)'s output's leading 0b and the binary number's trailing zeros (as they will always have a matching bit).

Java 8, 105 104 bytes
n->{String t=n+n.toString(n,2).replaceAll("0*$","")+n;return t.contains(new StringBuffer(t).reverse());}

Explanation:
Try it here.
n->{                         // Method with Integer parameter and boolean return-type
  String t=n                 //  Create a String `t` starting with the input Integer
    +n.toString(n,2)         //  Append the binary representation of the input Integer,
      .replaceAll("0*$","")  //   with all trailing zeroes removed
    +n;                      //  Append the input Integer again
  return t.contains(new StringBuffer(t).reverse());
                             //  Return true if `t` is a palindrome
}                            // End of method

PHP, 69+1 bytes
$q=trim(decbin($p=$argn),0);if(strrev($p)==$p&&strrev($q)==$q)echo$p;

Run as pipe with -nR
Echoes the original input for truthy / nothing for falsey
Try it online!

APL2 (not Dyalog), 36 bytes
(N≡⌽N←⍕N)^∨/(((⌽B)⍳1)↓B)⍷B←(32⍴2)⊤N←

First let B be the 32-bit representation of N:
B←(32⍴2)⊤N

Then mirror B and find the position of the 1st 1:
(⌽B)⍳1

Then drop that many positions from B. This will preserve the correct number of leading 0s.
Then perform FIND and an OR-REDUCTION to see if the cropped B contains its own mirror.
Now let's look at N, the decimal. The left-most bracketed expression converts N to a character vector and checks if it MATCHes its own mirror.
Finally, an AND joins the two checks.

In APL2 I can't make a neat lambda so I wrote a one-liner and included the assignment arrow. Hope this isn't cheating.

Welcome to PPCG!

Welcome to PPCG! For a less cheating version, are you able to append a quad (⎕) to make it a full program instead? Also, are you able to shorten to (N≡⌽N←⍕N)^∨/(B↓⍨1⍳⍨⌽B)⍷B←(32⍴2)⊤N←⎕?

Erik, thanks for checking! I'm sure this could be improved, but I don't have the ⍨ squiggle in APL2.

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/

sort: votes


text:
Fold the integer to save space!
The crazy mathematician owns a wide collection of numbers, and therefore the space he has left is quite limited. To save some, he must fold his integers, but unfortunately he is really lazy. Your task, if you wish to help him, is to create a function / program that folds a given positive integer for our number maniac.
How to fold an integer?
If it is evenly divisible by the sum of its digits, divide it by the sum of its digits. If it doesn't meet that requirement, take its remainder when divided by the sum of its digits. Repeat the process until the result reaches 1. The folded integer is the number of operations you had to perform. Let's take an example (say 1782):

Get the sum of its digits: 1 + 7 + 8 + 2 = 18. 1782 is evenly divisible by 18, so the next number is 1782 / 18 = 99.

99 is not evenly divisible by 9 + 9 = 18, hence we take the remainder: 99 % 18 = 9.

9 is obviously divisible by 9, so we divide it and obtain 1.

The result is 3, because 3 operations were required in order to reach 1.
Rules and Specs

Some integers might have the sum of digits equal to 1, such as 10 or 100. Your program doesn't need to handle such cases. That means, you will be guaranteed that the integer given as input doesn't have the sum of digits equal to 1, and no operation with the given integer will result in a number whose sum of digits is 1 (except for 1 itself, which is the "target"). For example, you will never receive 10 or 20 as input.

The input will be a positive integer higher than 1.

Default Loopholes apply.

You can take input and provide output by any standard mean.

Test Cases

Input     -> Output

2         -> 1
5         -> 1
9         -> 1
18        -> 2
72        -> 2
152790    -> 2
152       -> 3
666       -> 3
777       -> 3
2010      -> 3
898786854 -> 4

Here is a program that lets you visualize the process and try more test cases.

This is code-golf, so the shortest code in each language (scored in bytes) wins!

Inspired by this challenge, although it might not seem related at first.

This will work as a stopgap solution, but in the long term, the mathematician should really consider purchasing one of Hilbert's Hotels.  You can always find some unused room in one of those.

while 8987868546 is a valid input, it will break your test tool, and also many (if not all) of the answers...

@MischaBehrend Your example is not a valid input. I think you miscopied my last test case. The valid input was 898786854, not 8987868546 (you have added a 6 at the end)

nvm... should read the whole first rule ... leaving this here so you know why i thought it is valid: it was not a mistake... I changed it intentional to test these scripts... and reading the rules it is a valid input. The sum of all the digits in 8987868546  is not 1 (Rule 1 met) and 8987868546 is a positive integer higher than 1 (Rule 2 met).

@MischaBehrend That means, you will be guaranteed that the integer given as input doesn't have the sum of digits equal to 1, and no operation with the given integer will result in a number whose sum of digits is 1 - I believe this is the part you missed.

yes, I exactly missed that part.

05AB1E, 13 12 bytes
[¼DSO‰0Kθ©#®

Try it online!
Explanation
[               # start loop
 ¼              # increment counter
  D             # duplicate current value
   SO           # sum the digits in the copy
     ‰          # divmod the current value by its digit-sum
      0K        # remove 0 from the resulting list
        θ       # pop the last element
         ©      # store a copy in register
          #     # if the current value is 1, break
           ®    # push the copy from register
                # implicitly output counter

Python 2, 63 57 bytes
-1 thanks to totallyhuman
-1 thanks to Mr. Xcoder
-4 thanks to reffu
def f(n):a=sum(map(int,`n`));return n>1and-~f(n%a or n/a)

Try it online!

62 bytes, although this approach isn't usually the shortest...

61 bytes, using bitwise tricks

57 bytes Also my apologies for making this my own answer at first. It makes more sense as a comment

JavaScript (ES6), 66 58 51 49 bytes
Takes input as an integer. Returns false for 0 or 1 and throws an overflow error when it encounters any number whose digits add up to 1.
f=n=>n>1&&f(n%(x=eval([...""+n].join`+`))||n/x)+1

8 bytes saved with help from Justin.

Test it

o.innerText=(

f=n=>n>1&&f(n%(x=eval([...""+n].join`+`))||n/x)+1

)(i.value=898786854);oninput=_=>o.innerText=f(+i.value)
<input id=i type=number><pre id=o>

Could you save some bytes by summing the digits using eval(array.join`+`)?

I could indeed, @JustinMariner - you ninjaed me to it! Thanks :)

Haskell, 85 78 bytes
f 1=0
f n|r<1=1+f(n`div`s)|1<2=1+f r where s=sum(read.pure<$>show n);r=n`rem`s

Saved 7 bytes thanks to Bruce Forte.
Try it online.

Save some more bytes by using divMod and dropping the where: Try it online!

@Laikoni Wow, that's quite an improvement! Please post it as a different answer; it's different enough from mine. BTW: I was looking for a trick to get rid of the where. I will use this in the future. :)

sum[read[d]|d<-show n] saves a byte

Husk, 12 bytes
←€1¡Ṡ§|÷%oΣd

Try it online!
Explanation
←€1¡Ṡ§|÷%oΣd  Implicit input, e.g. n=1782
    Ṡ§|÷%oΣd  This part defines the transformation.
         oΣ   Sum of
           d  digits: s=18
    Ṡ   %     n mod s: 0
     §|       or (take this branch if last result was 0)
       ÷      n divided by s: 99
   ¡          Iterate the transformation: [1782,99,9,1,1,1,...
 €1           Index of 1 (1-based): 4
←             Decrement: 3
              Print implicitly.

Japt, 22 19 17 bytes
-3 bytes thanks to @Shaggy.
-2 bytes thanks to @ETHproductions

ìx
>1©1+ßU%VªU/V

Try it online!

20 bytes 19 bytes

Actually, you can change s_¬ to ì to save another two bytes :-)

@ETHproductions Oh, that's really cool, thanks!

C# (.NET Core), 87 bytes
n=>{int i=0,k,l;for(;n>1;++i){for(l=n,k=0;l>0;l/=10)k+=l%10;n=n%k>0?n%k:n/k;}return i;}

Try it online!
Lambda function that takes and returns an integer.

Retina, 100 bytes
$
;
{`(.+);
$1$*1;$&
(?<=;.*)\d(?=.*;)
$*
.*;1;(.*)
$.1
r`(1)*(\3)*;(1+);
$#1;$#2;1
0;(.*);|;.*;
$1;

Try it online! Link only includes smaller test cases as the larger ones take too long.

Mathematica, 73 bytes
(t=#;For[r=0,t>1,r++,If[(s=Mod[t,g=Tr@IntegerDigits@t])<1,t=t/g,t=s]];r)&

Can ==0 be replaced with <1?

@Mr.Xcoder yes, of course! I made a sorter version...

PHP, 68+1 bytes
unary output:
for($n=$argn;$n>1;$n=$n%($s=array_sum(str_split($n)))?:$n/$s)echo 1;

decimal output, 73+1 bytes:
for($n=$argn;$n>1;$i++)$n=$n%($s=array_sum(str_split($n)))?:$n/$s;echo$i;

Run as pipe with -nR or try it online.

The Elvis operator requires PHP 5.3 or later. For older PHP, replace ?: with ?$n%$s: (+5 bytes).

Haskell, 94 93 89 88 bytes
This feels really long..
length.fst.span(/=1).iterate g
g x|(d,m)<-x`divMod`sum[read[d]|d<-show x]=last$m:[d|m<1]

Try it online!
Thanks @Laikoni & @nimi for golfing off 1 byte each!

C (gcc), 83 81 76 73 bytes
i,k,s;f(n){k=n;for(i=0;k>1;i++,n=k=k%s?:k/s)for(s=0;n;n/=10)s+=n%10;n=i;}

Try it online!

Ruby, 46 bytes
f=->n{s=n.digits.sum;n<2?0:1+f[n%s<1?n/s:n%s]}

Jelly, 12 bytes
dDS$Ṛȯ/µÐĿL’

Try it online!

Interesting approach! Now we're waiting for Jonathan :P

@Mr.Xcoder I don't think so this time :)

Nor do I, that was a joke :)

Perl, 71 bytes, 64 bytes, 63 bytes
-pl

$c=0;while($_>1){$s=0;$s+=$_ for/./g;$_=$_%$s?$_%$s:$_/$s;++$c};$_=$c

Try it online
EDIT: saved 7 bytes, thanks to Xcali's comment
-p

while($_>1){$s=0;$s+=$_ for/./g;$_=$_%$s?$_%$s:$_/$s;++$c}$_=$c

EDIT: since 5.14 non destructive substitution s///r
-pl

while($_>1){$s=eval s/\B/+/gr;$_=$_%$s?$_%$s:$_/$s;++$c}$_=$c

Is the -pl on top supposed to be a command-line flag instead?

yes they are perl options

You should be counting the -pl flag according to this post.

I counted 69 bytes +2 for pl options, is it correct?

You can golf this down a bit.  $c doesn't need to be initialized.  It will start at undef which is 0.  The semicolon after the while closure can go.  Also, you don't need -l.  It's not required to take multiple inputs in one run.

thank-you for the tips, i though it should take multiple input

Pyth, 20 14 bytes
tl.ue-.DNsjNT0

Try it here.

Dyalog APL, 36 bytes
{x←+/⍎¨⍕⍵⋄1=⍵:0⋄0=x|⍵:1+∇⍵÷x⋄1+∇x|⍵}

Try it online!
How?
{
   x←+/⍎¨⍕⍵      ⍝ x = digit sum
   1=⍵:0         ⍝ if arg = 1: bye
   0=x|⍵:1+∇⍵÷x  ⍝ if arg divisible by x: recurse with arg/x
   1+∇x|⍵        ⍝ recurse with arg mod x
}

Gaia, 13 bytes
-@{:ΣZ¤∨)‡}°\

Try it online!
Explanation
-              Push -1 (this will be the counter)
 @             Push input (the starting number)
  {:ΣZ¤∨)‡}°   Repeat this block until the results of 2 consecutive runs are the same:
   :            Copy the number
    Σ           Digital sum
     Z          Divmod number by digital sum
      ¤         Swap
       ∨        Logical or: left-most non-zero out of (number mod sum, number div sum)
        )‡      Increment the counter
            \  Delete the final 1, implicitly print the counter

Matlab, 150 bytes
function[d]=X(x)
d=0;while ~strcmp(x,'1')z='sum(str2num(x(:)))';a=eval(['rem(',x,',',z,')']);y=num2str(a*(a>0)+eval([x,'/',z])*(a==0));x=y;d=d+1;end

Inputs should be given to the function as a string, such as X('152').
The function works by while looping and incrementing d. The x=y; line was necessary to avoid an error of Matlab trying to read and overwrite a variable value at the same time, apparently, which was a new one on me.
Ungolfed:
function[d]=X(x)
d=0;
while ~strcmp(x,'1')
    z='sum(str2num(x(:)))';
    a=eval(['rem(',x,',',z,')']);
    y=num2str(a*(a>0)+eval([x,'/',z])*(a==0));
    x=y;
    d=d+1;
end

Haskell, 68 bytes
f 1=0
f n=1+[f x|x<-[mod n,div n]<*>[sum$read.pure<$>show n],x>0]!!0

Try it online! Based on w0lf's answer.

R, 85 bytes
function(n){while(n>1){n="if"(x<-n%%(d=sum(n%/%10^(nchar(n):0)%%10)),x,n/d)
F=F+1}
F}

Anonymous function that returns the required output.
Verify all test cases!

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/