g | x | w | all
Bytes Lang Time Link
nanJavaScript > Halfwit250924T124159Zemanresu
nanR > Nibbles250924T120612ZDominic
607C++ → C++250914T145543ZToby Spe
94305AB1E → 05AB1E250915T141434ZKevin Cr
nanExcel VBA → Excel250915T141505ZEngineer
526JavaScript → JavaScript250913T125808ZArnauld
nanVyxal 3 > Vyxal 3250913T180801Zpacman25
nanPython 3 → !@#$%^&*_+250915T125901ZFmbalbue
nanPython 3 → Charcoal250913T154011ZNeil
000Python → Brainfuck 500250912T181645ZCharles
nanThis is a trivial example which generates250912T181429ZCharles

JavaScript -> Halfwit, score 3210403

let compress = int => {

  if (int == 0) return ''

  if (r = {
    1000: 'kkN',
    256: 'kkM',
    1e6: 'kkN:*',
    65536: 'kkM:*'
  }[int]) return r

  int = BigInt(int)
  let res = '';
  do {
    res = '[M{;+*JNfb:$?k'[int % 14n] + res
  } while (int /= 14n)
  return '>' + res
}

for (let i = 0; i <= 1e6; i++) {
  console.log(compress(i))
}

Try it online!

Halfwit is an absolutely terrible half-byte language I made almost three years ago. To represent integers, it (almost entirely) uses a compressed base-14 representation prefixed by a single >, which is mostly what the above implements. Thanks to this fairly low overhead, despite being a pretty awful golflang, Halfwit actually does quite well here!

Also, due to the difficulty of using any other method, almost all the numbers use this format - with the exception of the empty program, printing 0, and 1000, 256, and their squares, which are built-in constants. It's likely there's more numbers that can be expressed more succinctly, but even pushing e.g. 2 is already 1.5 bytes due to how integers are stored, and the output for 999999, >M?[J[N, is only 3.5 bytes.

R -> Nibbles, 3465021 bytes

answer=sapply(0:1000000,function(n){
	if(n==0)"-"
	else if(n==1)"/"
	else if(n<64)n
	else if(n==100)"@"
	else paste0("$~",intToBaseN(n,16))
})

Attempt This Online!

Uses R to calculate 1000001 Nibbles programs, whose output corresponds to normal decimal representations of 0-1000000, directly readable in R.
The output is in human-readable Nibbles notation. Use nibbles -c to compactify each program into individual nibbles (with a final 6 nibble in the saved file, not part of the code snippet.
Here is a link to test each Nibbles program (and verify its length in nibbles/bytes).

Explanation:
for zero: - = current variable minus itself = always zero.
for 1: / = current variable divided by itself = always 1.
for 2-64: = simple representation of each number, uses 1 nibble plus size in octal.
(except that 7 and 10 are exchanged).
for 100: @ = pre-defined variable for 100.
for all other numbers:

$           read number from end-of-program data
 ~          delimiter for end-of-program data
  f423f     data: any number in hexadecimal format 
                  (encoded directly as nibbles)

C++ → C++, 5,887,608 5,887,607 bytes

We use scientific notation for multiples of powers of ten¹ (and for small offsets from those) and shift-left operator for multiples of powers of two.

#include <algorithm>
#include <concepts>
#include <bit>
#include <format>
#include <string>
#include <vector>

template<std::unsigned_integral T>
std::string shortest_repr(T i)
{
    std::vector<std::string> candidates{std::to_string(i)};
    if (i) {
        // can we use scientific notation?
        for (T e = 3u, m = 1000u;  i % m == 0;  ++e, m *= 10) {
            candidates.push_back(std::format("{}e{}", i/m, e));
        }
        // scientific notation with a small offset
        for (T e = 5u, m = 100'000u, a = 10u;  m < i+a;  ++e, m *= 10, a *= 10) {
            if (i % m < a) {
                candidates.push_back(std::format("{}e{}+{}", i/m, e, i % m));
            } else if (m - i%m < a) {
                candidates.push_back(std::format("{}e{}-{}", (i+a)/m, e, m - i%m));
            }
        }
        // ⅛ of large number
        for (T m = 8u;  m * i % 100'000 == 0;  m *= 2) {
            candidates.push_back(std::format("{}/{}", shortest_repr(m*i), m));
        }
        // bit shift
        if (T z = std::countr_zero(i);  z > 10) {
            candidates.push_back(std::format("{}<<{}", shortest_repr(i >> z), z));
        }
    }
    return *std::ranges::min_element(candidates, {}, &std::string::size);
}

With this function, we can create a view by transforming suitable input. So to write one item per line to standard output, we have

#include <iostream>
#include <ranges>

int main()
{
    auto const strings
        = std::views::iota(0u, 1'000'001u)
        | std::views::transform(shortest_repr<unsigned>);

    std::ranges::copy(strings, std::ostream_iterator<std::string>(std::cout, "\n"));
}

Similarly, to count the output size:

    std::locale::global(std::locale(""));
    std::println("Total: {:L}", std::ranges::fold_left(strings
                                    | std::views::transform(&std::string::size),
                                0uz, std::plus<>{}));

If we wish to do both in the same program, I recommend materialising into a collection. This one prints the values that are shorter than just writing the literal number, as well as the total size of all the strings:

#include <cmath>
#include <iostream>
#include <iterator>
#include <print>
#include <ranges>

int main()
{
    auto const strings
        = std::views::iota(0u, 1'000'001u)
        | std::views::transform(shortest_repr<unsigned>)
        | std::ranges::to<std::vector>();

    std::ranges::copy(strings | std::views::enumerate
                      | std::views::filter([](auto e){ auto& [n,s] = e; return n && s.size() <= std::log10(n);})
                      | std::views::values,
                      std::ostream_iterator<std::string>(std::cout, "\n"));

    std::locale::global(std::locale(""));
    std::println("Total: {:L}", std::ranges::fold_left(strings | std::views::transform(&std::string::size), 0uz, std::plus<>{}));
}

Selected output:

⋮
1e5+7
1e5+8
1e5+9
101e3
102e3
103e3
104e3
105e3
106e3
107e3
108e3
109e3
11e4
111e3
112e3
9e5/8
113e3
114e3
7<<14
115e3
116e3
⋮
Total: 5,887,607

¹ Although scientific notation produces a floating-point type, this will be exact for the small numbers used in this question and will therefore result in exactly-correct values when parsed in integer context.

05AB1E → 05AB1E, 3,934,943 bytes

6°Ýε
 "T₂₆₃т₅₁₄"©.V)ćkDdi®sèDˆ
 ëyg3‹iyDˆ
 ëy356‹iyт>-₅B"Ƶÿ"Dˆ
 ë"žAžBžCžDžEžFžGžH"©.V)ykDi®2ôsèDˆ
 ëy₄α3‹i"Í< >Ì"yÌè"₄"ìDˆ
 ëyg4‹iyëy₅B"•ÿ"}
  Dg¯yCè©g>›yTмõQ*i®'b«}
  Dg¯ytïè©g>›ytDïQ*i®'n«}
  Dg¯yT.nïè©g>›yT.nDïQ*i®"°"«}
  Dg¯y.Øè©g>›yp*i®"Ø"«}
  Dg¯y;è©g>›yÈ*i®"·"«}
  Dg¯yRè©g>›y›*yθĀ*i®'R«}
  Dg¯y2äнè©g>›yÂQ*i®"ûº"yÈè«}
  Dˆ

(Don't) try it online (times out after 60 seconds outputting roughly 4,500 values).

Explanation:

6°Ýε       # Push a list in the range [0,1000000] and map over it:
"T₂₆₃т₅₁₄"©.V)ćkDdi®sèDˆ
           #  If there is a single-byte constant for the value: use it
           #  ([T,₂,₆,₃,т,₅,₁,₄] = [10,26,36,95,100,255,256,1000])
ëyg3‹iyDˆ  #  Else-if the current value is just 1 or 2 digits: use it as is
ëy356‹iyт>-₅B"Ƶÿ"Dˆ
           #  Else-if the value is in the range [101,355]: use 2-bytes compression
ë"žAžBžCžDžEžFžGžH"©.V)ykDi®2ôsèDˆ
           #  Else-if there is a two-bytes constant for the value: use it
           #  ([žA,žB,žC,žD,žE,žF,žG,žH] = [512,1024,2048,4096,8192,16384,32768,65536])
ëy₄α3‹i"Í< >Ì"yÌè"₄"ìDˆ
           #  Else-if the value is in the range [998,1002]: use ₄ + de-/incrementer
ë          #  Else:
 yg4‹iy    #   If the value has 3 digits: use it as is
 ëy₅B"•ÿ"} #   Else: compress it as 3 or 4 bytes
 Dg¯yCè©g>›yTмõQ*i®'b«}
          '#   If the value is binary, and can be shortened with an earlier value + "b": use that instead
 Dg¯ytïè©g>›ytDïQ*i®'n«}
          '#  If the value is a square number, and can be shortened with an earlier value + "n": use that instead
 Dg¯y2.nïè©g>›y2.nDïQ*i®'o«}
          '#  If the value is a power of 2, and can be shortened with an earlier value + "o": use that instead
 Dg¯yT.nïè©g>›yT.nDïQ*i®"°"«}
           #  If the value is a power of 10, and can be shortened with an earlier value + "°": use that instead
 Dg¯y.Øè©g>›yp*i®"Ø"«}
           #  If the value is a prime, and can be shortened with an earlier value + "Ø": use that instead
 Dg¯y;è©g>›yÈ*i®"·"«}
           #  If the value is even, and can be shortened with an earlier value + "·": use that instead
 Dg¯yRè©g>›y›*yθĀ*i®'R«}
          '#  If the value does not end with a 0, is smaller reversed, and can be shortened with an earlier value + "R": use that instead
 Dg¯y2äнè©g>›yÂQ*i®"ûº"yÈè«}
           #  If the value is a palindrome, and can be shortened with an earlier value + "û" (odd length) or "º" (even length): use that instead
           #  Else: use the 3/4-bytes compression
 Dˆ        #  Add a copy to the global array,
           #  which we'll potentially use for the later checks if something can be shorter

Which results in:

Resulting in a total of \$18 + 291\times2 + 64425\times3 + 935267\times4 = 3934943\$ bytes.

Excel VBA → Excel, 5888896 5888673

OP clarified that the snippets need to resolve to the correct value without relying on the code that generates the snippets placing them in the correct place. With that in mind, I have an even less clever solution that nonetheless uses less bytes in the output.

Sub MillionAndOneConstants()
    
    ' Generate all the values from 0 to 1,000,000
    Range("A1").Formula2 = "=SEQUENCE(1000000,,0)"
    Application.Calculate
    If Not Application.CalculationState = xlDone Then
        DoEvents
    End If
    Range("A:A").Copy
    Range("A:A").PasteSpecial xlPasteValues
    
    ' Replace values with an equivalent exponent form if that is less bytes
    Range("A1025") = "4^5"
    Range("A1297") = "6^4"
    Range("A2188") = "3^7"
    Range("A2402") = "7^4"
    Range("A3126") = "5^5"
    Range("A4097") = "4^6"
    Range("A6562") = "3^8"
    Range("A7777") = "6^5"
    Range("A10001") = "10^4"
    Range("A10649") = "22^3"
    Range("A12168") = "23^3"
    Range("A13825") = "24^3"
    Range("A14642") = "11^4"
    Range("A15626") = "5^6"
    Range("A16385") = "4^7"
    Range("A16808") = "7^5"
    Range("A17577") = "26^3"
    Range("A19684") = "3^9"
    Range("A20737") = "12^4"
    Range("A21953") = "28^3"
    Range("A24390") = "29^3"
    Range("A27001") = "30^3"
    Range("A28562") = "13^4"
    Range("A29792") = "31^3"
    Range("A32769") = "8^5"
    Range("A35938") = "33^3"
    Range("A38417") = "14^4"
    Range("A39305") = "34^3"
    Range("A42876") = "35^3"
    Range("A46657") = "6^6"
    Range("A50626") = "15^4"
    Range("A50654") = "37^3"
    Range("A54873") = "38^3"
    Range("A59050") = "9^5"
    Range("A59320") = "39^3"
    Range("A64001") = "40^3"
    Range("A65537") = "4^8"
    Range("A68922") = "41^3"
    Range("A74089") = "42^3"
    Range("A78126") = "5^7"
    Range("A79508") = "43^3"
    Range("A83522") = "17^4"
    Range("A85185") = "44^3"
    Range("A91126") = "45^3"
    Range("A97337") = "46^3"
    Range("A100001") = "10^5"
    Range("A100490") = "317^2"
    Range("A101125") = "318^2"
    Range("A101762") = "319^2"
    Range("A102401") = "320^2"
    Range("A103042") = "321^2"
    Range("A103685") = "322^2"
    Range("A103824") = "47^3"
    Range("A104330") = "323^2"
    Range("A104977") = "18^4"
    Range("A110593") = "48^3"
    Range("A117650") = "7^6"
    Range("A125001") = "50^3"
    Range("A130322") = "19^4"
    Range("A131073") = "2^17"
    Range("A132652") = "51^3"
    Range("A140609") = "52^3"
    Range("A148878") = "53^3"
    Range("A157465") = "54^3"
    Range("A160001") = "20^4"
    Range("A161052") = "11^5"
    Range("A166376") = "55^3"
    Range("A175617") = "56^3"
    Range("A177148") = "3^11"
    Range("A185194") = "57^3"
    Range("A194482") = "21^4"
    Range("A195113") = "58^3"
    Range("A205380") = "59^3"
    Range("A216001") = "60^3"
    Range("A226982") = "61^3"
    Range("A234257") = "22^4"
    Range("A238329") = "62^3"
    Range("A248833") = "12^5"
    Range("A250048") = "63^3"
    Range("A262145") = "4^9"
    Range("A274626") = "65^3"
    Range("A279842") = "23^4"
    Range("A279937") = "6^7"
    Range("A287497") = "66^3"
    Range("A300764") = "67^3"
    Range("A314433") = "68^3"
    Range("A328510") = "69^3"
    Range("A331777") = "24^4"
    Range("A343001") = "70^3"
    Range("A357912") = "71^3"
    Range("A371294") = "13^5"
    Range("A373249") = "72^3"
    Range("A389018") = "73^3"
    Range("A390626") = "5^8"
    Range("A405225") = "74^3"
    Range("A421876") = "75^3"
    Range("A438977") = "76^3"
    Range("A456534") = "77^3"
    Range("A456977") = "26^4"
    Range("A474553") = "78^3"
    Range("A493040") = "79^3"
    Range("A512001") = "80^3"
    Range("A524289") = "2^19"
    Range("A531442") = "9^6"
    Range("A537825") = "14^5"
    Range("A551369") = "82^3"
    Range("A571788") = "83^3"
    Range("A592705") = "84^3"
    Range("A614126") = "85^3"
    Range("A614657") = "28^4"
    Range("A636057") = "86^3"
    Range("A658504") = "87^3"
    Range("A681473") = "88^3"
    Range("A704970") = "89^3"
    Range("A707282") = "29^4"
    Range("A729001") = "90^3"
    Range("A753572") = "91^3"
    Range("A759376") = "15^5"
    Range("A778689") = "92^3"
    Range("A804358") = "93^3"
    Range("A810001") = "30^4"
    Range("A823544") = "7^7"
    Range("A830585") = "94^3"
    Range("A857376") = "95^3"
    Range("A884737") = "96^3"
    Range("A912674") = "97^3"
    Range("A923522") = "31^4"
    Range("A941193") = "98^3"
    Range("A970300") = "99^3"
    Range("A1000001") = "10^6"
    
End Sub

It fills in regular integers for all the values and then replaces certain values with a exponential representation if it's shorter. This list of values could also be generated by the program but, in this case, I worked them out separately but it was easier than writing and debugging the VBA solution.

JavaScript → JavaScript, 5,887,526 bytes

Method

We use the following patterns:

Pattern description Example
exponentiation 3**9 for 19683
left-shift 7<<14 for 114688
scientific notation 123e3 for 123000
scientific notation with single-digit offset 2e5-1 for 199999
scientific notation with division by 8 9e5/8 for 112500 (*)

(*) This is actually the one and only case where this pattern saves a byte.

Source

const expr = [];

for(let n = 0; n <= 1e6; n++) {
  expr[n] = n.toString();
}

for(let p = 2; p < 100; p++) {
  for(let q = 2; q < 20; q++) {
    tryExpression(`${p}**${q}`);
    tryExpression(`${p}<<${q}`);
  }
}

for(let p = 1; p < 1000; p++) {
  for(let q = 3; q < 10; q++) {
    tryExpression(`${p}e${q}`);
    tryExpression(`${p}e${q}/8`);

    for(let o = 1; o < 10; o++) {
      tryExpression(`${p}e${q}-${o}`);
      tryExpression(`${p}e${q}+${o}`);
    }
  }
}

console.log(`Score: ${expr.reduce((t, e) => t + e.length, 0)} bytes\n`);

expr.forEach((e, n) =>
  e != n.toString() && console.log(n.toString().padEnd(7) + ': ' + e)
);

function tryExpression(e) {
  const v = eval(e);
  if(v >= 0 && v <= 1e6 && v % 1 == 0 && e.length < expr[v].length) {
    expr[v] = e;
  }
}

Try it online!

(literal numbers in their standard decimal form are omitted in the output)

Vyxal 3 -> Vyxal 3, 4868748 4791344 bytes

"①②③④⑤⑥⑦"f
"k0k1k2k3k4k①k②k③k④k⑤k⑥k⑧k⑦"²
"17E18E19E"³
Wfµᴥ]:"›‹⨥⨪d½T":2ℭ$fJX“J
⑦ k1Rƛ#c'²+]
⑤ʀ¨'³+
"kn⍢⌊""k5⍢⌊""ko⌊ᐕ"
9ƛ'!+]
"5 7*5 8*6 7*8 6*9 6*7:*"4Ϣ
Wf
⑴ᴥ☷ƛµL⎋]
ᏐUVk⑧Rƛ#c"dT"f+]ʎᴥk⑧>]fJ
ʎL5<]ʎᴥk4≤]ʎᴥ⎂L<]
ʎᴥ#c⎂L<]
Þ£
k4ƛÞw:ᴥn=:a[▲h|k1<[n|n#c]

Vyxal It Online!

Replace the last line with :ᴥ#c⎂Ŀ-∑ to see how many bytes you save compared to just compressing the numbers since it takes too long to actually print them all. This currently saves 77466 bytes over raw compression

Uses the built in compression for most numbers, except when a number is n+1, n+2, n-1, n-2, n^2, n^3, 2n, 3n, 2^n, or n/2 for any built in constant, or number less than 65536. also throw in 67890, 5,6,7,8,9 factorial, and cubes. This lets me usually get a 4 byte answer modifying a compressed two byte number compared to the 5 bytes needed to compress any number larger than 2^16. Anything more than 4 bytes is the same or worse than base 252 compression. I spent like 2 hours doing this and I had to run it all on my laptop because the server crashed once and took forever to run on there. Will output an array of strings where each the contents of each string can be directly pasted into the vyxal interpreter and when run will return the desired number.

Edit I forgot to include some values in the range in line 5 its about double the savings lol

old explanation:

"①②③④⑤⑥⑦"f
"k0k1k2k3k①k②k③k④k⑤k⑥k⑧k⑦"²
"17E18E19E"³
Wfµᴥ]:"›‹⨥⨪dT½":2ℭ$fJX“J⑴ᴥ☷ƛµL⎋]⑴ᴥu
ᏐUVk⑧Rƛ#c"dT"f+]ʎᴥk⑧>]fJ
⑦ k1Rƛ#c'²+]Ju
ʎL5<]ʎᴥ#c⎂L<]ʎᴥk4<]Þ£
k4ƛÞw:ᴥn=:a[▲h|k1<[n|n#c]
­⁡​‎‎⁢⁠⁡‏⁠‎⁢⁠⁢‏⁠‎⁢⁠⁣‏⁠‎⁢⁠⁤‏⁠‎⁢⁠⁢⁡‏⁠‎⁢⁠⁢⁢‏⁠‎⁢⁠⁢⁣‏⁠‎⁢⁠⁢⁤‏⁠‎⁢⁠⁣⁡‏⁠‎⁢⁠⁣⁢‏‏​⁡⁠⁡‌⁢​‎‎⁣⁠⁡‏⁠‎⁣⁠⁢‏⁠‎⁣⁠⁣‏⁠‎⁣⁠⁤‏⁠‎⁣⁠⁢⁡‏⁠‎⁣⁠⁢⁢‏⁠‎⁣⁠⁢⁣‏⁠‎⁣⁠⁢⁤‏⁠‎⁣⁠⁣⁡‏⁠‎⁣⁠⁣⁢‏⁠‎⁣⁠⁣⁣‏⁠‎⁣⁠⁣⁤‏⁠‎⁣⁠⁤⁡‏⁠‎⁣⁠⁤⁢‏⁠‎⁣⁠⁤⁣‏⁠‎⁣⁠⁤⁤‏⁠‎⁣⁠⁢⁡⁡‏⁠‎⁣⁠⁢⁡⁢‏⁠‎⁣⁠⁢⁡⁣‏⁠‎⁣⁠⁢⁡⁤‏⁠‎⁣⁠⁢⁢⁡‏⁠‎⁣⁠⁢⁢⁢‏⁠‎⁣⁠⁢⁢⁣‏⁠‎⁣⁠⁢⁢⁤‏⁠‎⁣⁠⁢⁣⁡‏⁠‎⁣⁠⁢⁣⁢‏⁠‎⁣⁠⁢⁣⁣‏‏​⁡⁠⁡‌⁣​‎‎⁤⁠⁡‏⁠‎⁤⁠⁢‏⁠‎⁤⁠⁣‏⁠‎⁤⁠⁤‏⁠‎⁤⁠⁢⁡‏⁠‎⁤⁠⁢⁢‏⁠‎⁤⁠⁢⁣‏⁠‎⁤⁠⁢⁤‏⁠‎⁤⁠⁣⁡‏⁠‎⁤⁠⁣⁢‏⁠‎⁤⁠⁣⁣‏⁠‎⁤⁠⁣⁤‏‏​⁡⁠⁡‌⁤​‎‎⁢⁡⁠⁡‏⁠‎⁢⁡⁠⁢‏⁠‎⁢⁡⁠⁣‏⁠‎⁢⁡⁠⁤‏⁠‎⁢⁡⁠⁢⁡‏⁠‎⁢⁡⁠⁢⁢‏‏​⁡⁠⁡‌⁢⁡​‎⁠‎⁢⁡⁠⁢⁣‏⁠‎⁢⁡⁠⁢⁤‏⁠‎⁢⁡⁠⁣⁡‏⁠‎⁢⁡⁠⁣⁢‏⁠‎⁢⁡⁠⁣⁣‏⁠‎⁢⁡⁠⁣⁤‏⁠‎⁢⁡⁠⁤⁡‏⁠‎⁢⁡⁠⁤⁢‏⁠‎⁢⁡⁠⁤⁣‏⁠‎⁢⁡⁠⁤⁤‏‏​⁡⁠⁡‌⁢⁢​‎⁠‎⁢⁡⁠⁢⁡⁡‏⁠‎⁢⁡⁠⁢⁡⁢‏⁠‎⁢⁡⁠⁢⁡⁣‏⁠‎⁢⁡⁠⁢⁡⁤‏⁠‎⁢⁡⁠⁢⁢⁡‏‏​⁡⁠⁡‌⁢⁣​‎‎⁢⁡⁠⁢⁢⁢‏⁠‎⁢⁡⁠⁢⁢⁣‏⁠‎⁢⁡⁠⁢⁢⁤‏‏​⁡⁠⁡‌⁢⁤​‎‏​⁢⁠⁡‌⁣⁡​‎‎⁢⁡⁠⁢⁣⁡‏⁠‎⁢⁡⁠⁢⁣⁢‏⁠‎⁢⁡⁠⁢⁣⁣‏⁠‎⁢⁡⁠⁢⁣⁤‏⁠‎⁢⁡⁠⁢⁤⁡‏⁠‎⁢⁡⁠⁢⁤⁢‏⁠‎⁢⁡⁠⁢⁤⁣‏⁠‎⁢⁡⁠⁢⁤⁤‏⁠‎⁢⁡⁠⁣⁡⁡‏⁠‎⁢⁡⁠⁣⁡⁢‏⁠‎⁢⁡⁠⁣⁡⁣‏‏​⁡⁠⁡‌⁣⁢​‎‎⁢⁢⁠⁡‏⁠‎⁢⁢⁠⁢‏⁠‎⁢⁢⁠⁣‏⁠‎⁢⁢⁠⁤‏⁠‎⁢⁢⁠⁢⁡‏⁠‎⁢⁢⁠⁢⁢‏⁠‎⁢⁢⁠⁢⁣‏⁠‎⁢⁢⁠⁢⁤‏⁠‎⁢⁢⁠⁣⁡‏⁠⁠⁠⁠⁠⁠⁠‎⁢⁢⁠⁤⁤‏⁠⁠⁠⁠⁠⁠⁠⁠‏​⁡⁠⁡‌⁣⁣​‎⁠⁠‎⁢⁢⁠⁣⁢‏⁠‎⁢⁢⁠⁣⁣‏⁠‎⁢⁢⁠⁣⁤‏⁠‎⁢⁢⁠⁤⁡‏⁠‎⁢⁢⁠⁤⁢‏⁠‎⁢⁢⁠⁤⁣‏⁠‎⁢⁢⁠⁤⁤‏‏​⁡⁠⁡‌⁣⁤​‎‎⁢⁢⁠⁢⁡⁡‏⁠‎⁢⁢⁠⁢⁡⁢‏⁠‎⁢⁢⁠⁢⁡⁣‏⁠‎⁢⁢⁠⁢⁡⁤‏⁠‎⁢⁢⁠⁢⁢⁡‏⁠‎⁢⁢⁠⁢⁢⁢‏⁠‎⁢⁢⁠⁢⁢⁣‏⁠‎⁢⁢⁠⁢⁢⁤‏‏​⁡⁠⁡‌⁤⁡​‎‎⁢⁣⁠⁡‏⁠‎⁢⁣⁠⁢‏⁠‎⁢⁣⁠⁣‏⁠‎⁢⁣⁠⁤‏⁠‎⁢⁣⁠⁢⁡‏⁠‎⁢⁣⁠⁢⁢‏⁠‎⁢⁣⁠⁢⁣‏⁠‎⁢⁣⁠⁢⁤‏⁠‎⁢⁣⁠⁣⁡‏⁠‎⁢⁣⁠⁣⁢‏⁠‎⁢⁣⁠⁣⁣‏⁠‎⁢⁣⁠⁣⁤‏⁠‎⁢⁣⁠⁤⁡‏⁠‎⁢⁣⁠⁤⁢‏‏​⁡⁠⁡‌⁤⁢​‎‎⁢⁤⁠⁡‏⁠‎⁢⁤⁠⁢‏⁠‎⁢⁤⁠⁣‏⁠‎⁢⁤⁠⁤‏⁠‎⁢⁤⁠⁢⁡‏⁠‎⁢⁤⁠⁢⁢‏⁠‎⁢⁤⁠⁢⁣‏⁠‎⁢⁤⁠⁢⁤‏⁠‎⁢⁤⁠⁣⁡‏⁠‎⁢⁤⁠⁣⁢‏⁠‎⁢⁤⁠⁣⁣‏⁠‎⁢⁤⁠⁣⁤‏⁠‎⁢⁤⁠⁤⁡‏⁠‎⁢⁤⁠⁤⁢‏⁠‎⁢⁤⁠⁤⁣‏⁠‎⁢⁤⁠⁤⁤‏⁠‎⁢⁤⁠⁢⁡⁡‏⁠‎⁢⁤⁠⁢⁡⁢‏⁠‎⁢⁤⁠⁢⁡⁣‏⁠‎⁢⁤⁠⁢⁡⁤‏⁠‎⁢⁤⁠⁢⁢⁡‏‏​⁡⁠⁡‌⁤⁣​‎‎⁣⁡⁠⁡‏⁠‎⁣⁡⁠⁢‏⁠‎⁣⁡⁠⁣‏⁠‎⁣⁡⁠⁤‏⁠‎⁣⁡⁠⁢⁡‏⁠‎⁣⁡⁠⁢⁢‏⁠‎⁣⁡⁠⁢⁣‏⁠‎⁣⁡⁠⁢⁤‏⁠‎⁣⁡⁠⁣⁡‏⁠‎⁣⁡⁠⁣⁢‏⁠‎⁣⁡⁠⁣⁣‏⁠‎⁣⁡⁠⁣⁤‏⁠‎⁣⁡⁠⁤⁡‏⁠‎⁣⁡⁠⁤⁢‏⁠‎⁣⁡⁠⁤⁣‏⁠‎⁣⁡⁠⁤⁤‏⁠‎⁣⁡⁠⁢⁡⁡‏⁠‎⁣⁡⁠⁢⁡⁢‏⁠‎⁣⁡⁠⁢⁡⁣‏⁠‎⁣⁡⁠⁢⁡⁤‏⁠‎⁣⁡⁠⁢⁢⁡‏⁠‎⁣⁡⁠⁢⁢⁢‏⁠‎⁣⁡⁠⁢⁢⁣‏⁠‎⁣⁡⁠⁢⁢⁤‏⁠‎⁣⁡⁠⁢⁣⁡‏‏​⁡⁠⁡‌­

"①②③④⑤⑥⑦"f                           # ‎⁡one byte built ins
"k0k1k2k3k①k②k③k④k⑤k⑥k⑧k⑦"²          # ‎⁢two byte constants
"17E18E19E"³                         # ‎⁣2 powers for 17,18,19
Wfµᴥ]:                               # ‎⁤all of those sorted by their value and copied
      "›‹⨥⨪dT½":                     # ‎⁢⁡+1, -1, +2, -2, double, triple, halve and copy
                2ℭ$fJ                # ‎⁢⁢get all combinations of length 2 and 1
                     X“J             # ‎⁢⁣cartesian product with the constants and joined to the list of constants unmodified. 
# ‎⁢⁤We now have a list of built in constants with one byte allowed for modification as well, however there are duplicates as n+1-1 is the same as n
                        ⑴ᴥ☷ƛµL⎋]⑴ᴥu  # ‎⁣⁡get the shortest combination for each number generated by at least one combo
ᏐUVk⑧Rƛ#c      ]                     # ‎⁣⁢all 3 byte compressed numbers between 65536/3 and 65536
         "dT"f+]                     # ‎⁣⁣doubled and tripled
                ʎᴥk⑧>]fJ             # ‎⁣⁤keep only the ones greater than 65536 and join those to the list of constants
⑦ k1Rƛ#c'²+]Ju                       # ‎⁤⁡all squares less than one million
ʎL5<]ʎᴥ#c⎂L<]ʎᴥk4<]Þ£                # ‎⁤⁢get rid of ones that are greater than 5 bytes long, save no bytes over raw compression, or are greater than one million and push the remaining ones to the register (now a stack!)
k4ƛÞw:ᴥn=:a[▲h|k1<[n|n#c]            # ‎⁤⁣if the number is in the list of generated constants, use that, otherwise if it is less than 1000 just print it, otherwise print it as a compressed number
💎

Created with the help of Luminespire.

Python 3!@#$%^&*()_+, 3932313 bytes

for i in range(1000001):
	# print(str(i) + ":", end = "") # This is used for indicating which number to print for the code snippet
	if chr(i) in "@$%&*)_+":
		print(chr(i//2)+chr((i//2) + (i%2)) + "+", end = "")
	elif chr(i) in "!#(?^":
		print(chr(i-1)+"^", end = "")
	else:
		print(chr(i), end = "")
	# print("#") # to print the number, uncomment this line.

Try it online!

There are 128 1-byte characters, 1920 2-byte characters, 61440 3-byte characters, and at least one million 4-byte characters. There are 8 special numbers that take two more bytes to print, 4 special numbers that take one more byte to print. So by considering these things, if I'm right, the byte count is:

$$8×3+5×2+(128−8−5)×1+1920×2+63488×3+(1000001−128−1920−63488)×4$$

Which is 3932313, and is pretty cool but also a bit boring.

Python 3Charcoal, 4982032 bytes

Charcoal doesn't have a compressed number syntax, so mostly savings are achieved by taking the ordinal of a character: ℅d...℅~ (2 bytes), ℅✑...℅✲ (4 bytes) and ℅𘚢...℅󴈾 (5 bytes) all save a byte over a numeric literal. This saves over 900000 bytes.

Otherwise, the only option is to get creative with the predefined variables χ c 10 and φ f 1000, and the operators Incremented, Decremented, Doubled, Halved, Plus, × Times and Power. There are only a limited number of these so they have been hard-coded in the program. Where two numeric literals are exponentiated, this unfortunately then requires an extra ¦ as a separator, reducing the number of opportunities where this can be used.

Although not required here, for numbers over 1000000, except when there are special cases, taking ordinals is the most efficient up to 1114111, after which you need to switch to base 95 conversion. Note that if the base 95 encoding would start with - you need to prefix a space to get it to decode correctly, so for instance 11145874 would encode as ⍘,~~~γ but 11145875 would encode as ⍘ - γ although that still saves a byte.

There are also some extra special cases to consider for large values because string compression can sometimes result in short compressed strings if there are patterns in the number e.g. 1111111111 compresses to I”|↓⦄” or 1100110011 compresses to I”)∧⧴;”. (For random numbers string compression won't win until the numbers are at least 50 digits long; I haven't measured this value exactly.)

Note that although I have used numeric literals when there isn't a saving to be made, it's possible that you need two numeric literals in a row, so an alternative same-length representation for one of the literals could avoid a ¦ separator thus saving a byte. I haven't tried to show these alternatives here.

The program starts by printing the total length of all the literals (in Charcoal's code page). It does not show all 1000001 literals as this would not fit in TIO's output buffer, instead it collapses similar ranges e.g. 99900 is found in the 99001 ... 99998 ⁹⁹⁰⁰¹ ... ⁹⁹⁹⁹⁸ range indicating that it would be represented as ⁹⁹⁹⁰⁰.

d = "⁰¹²³⁴⁵⁶⁷⁸⁹"
a = [''.join(d[int(c)]for c in str(i))for i in range(1000001)]
for i in range(100, 127):
 a[i] = "℅" + chr(i)
for i in range(10000, 16512):
 a[i] = "℅" + chr(i)
for i in range(100000, 999999):
 a[i] = "℅" + chr(i)
for c in ";∧∨“⊞⊟➙⧴″‴&|↶↷⟲←↑→↓⎇‽↧↥⌊⌈↖↗↘↙⭆?⪫⪪℅◧◨⮌≡№⊙⸿⬤≔≕▷▶✂↨⍘✳↔≦≧ⅈⅉ⌕⊕⊖⊗⊘⎚₂﹪⁺⁻⁰⁴⁵⁶⁷⁸⁹‖‹⁼›ABCDEFGHIJKLMNOPQRSTUVWXYZ⟦∕⟧…⦃⦄~�":
 a[ord(c)] = "℅´" + c
 if len(a[ord(c) - 1]) > 4:
  a[ord(c) - 1] = "⊖℅´" + c
 if len(a[ord(c) + 1]) > 4:
  a[ord(c) + 1] = "⊕℅´" + c
a[10] = "χ"
a[500] = "⊘φ"
a[999] = "⊖φ"
a[1000] = "φ"
a[1001] = "⊕φ"
for i in range(2, 11):
 a[1000 + i] = "⁺φ" + a[i]
 a[1000 * i] = "×φ" + a[i]
a[1024] = "X²χ"
a[1998] = "⊗⊖φ"
a[1999] = "⊖⊗φ"
a[2000] = "⊗φ"
a[2001] = "⊕⊗φ"
a[2002] = "⊗⊕φ"
a[16807] = "X⁷¦⁵"
for i in range(17, 127):
 a[i * 1000] = "×φ" + a[i]
a[19683] = "X³¦⁹"
a[32768] = "X⁸¦⁵"
a[46656] = "X⁶¦⁶"
a[59048] = "⊖X³χ"
a[59049] = "X³χ"
a[59050] = "⊕X³χ"
a[65536] = "X⁴¦⁸"
a[78125] = "X⁵¦⁷"
a[99999] = "⊖Xχ⁵"
a[100000] = "Xχ⁵"
a[100001] = "⊕Xχ⁵"
a[117649] = "X⁷¦⁶"
a[200000] = "⊗Xχ⁵"
a[262144] = "X⁴¦⁹"
a[279936] = "X⁶¦⁷"
a[390625] = "X⁵¦⁸"
a[500000] = "×φ⊘φ"
a[531441] = "X⁹¦⁶"
a[823543] = "X⁷¦⁷"
a[999000] = "×φ⊖φ"
a[999999] = "⊖×φφ"
a[1000000] = "×φφ"
print(sum(4+(s[1]>"䁿")if s[0] == "℅" and s[1] > "´" else len(s)for s in a))
b = 0
c = "⁰"
for i in range(1000001):
 if a[i][:2] == c:
  continue
 if len(a[i]) == 2 and a[i][0] == "℅" and c == "℅":
  continue
 if all(c in d for c in a[i]) and c == "⁰":
  continue
 if c:
  if b < i - 1:
   print(b, "...", i - 1, a[b], "...", a[i - 1])
  else:
   print(b, a[b])
 b = i
 if a[i][:2] == "℅´" or a[i][:2] == "⁺φ":
  c = a[i][:2]
 elif len(a[i]) == 2 and a[i][0] == "℅":
  c = "℅"
 elif all(c in d for c in a[i]):
  c = "⁰"
 else:
  c = ""
  print(i, a[i])

Try it online!

Python → Brainfuck (500,000,500,000 bytes)

for i in range(1000001):
    print('+' * i)

This assumes an idealized version of Brainfuck which allows constants greater than 255 in a cell. (Without this, Brainfuck is excluded as unable to store large enough numbers, though you could consider a version storing the numbers in multiple cells.)

This can be greatly improved and should not be remotely competitive.

This is a trivial example which generates, e.g., "101" for 101. This is valid in many languages besides C, of course. For most languages, this is the baseline which you aim to improve.

Python → C (5,888,897 bytes)

for i in range(1000001):
    print(i)