Okay, here's my idea for the ultimate challenge. Very roughly: the numbers will first be stored into a binary format. I'll take the binary digits and put them in base-256 digits in lists (just combine every 8 binary bits into one list element). Then I'll change each of these digits into a character, and combine these into a string.

There'll be different types of numbers: integers, fractions, and decimal. The storage format for integers will be something like this:

2 bits: 01 signifies its an integer

4 bits: legnth of number; take this number and multiply by 3 to get the length. If the number is 0, there is no sign bit or significand, and the number it represents is 0.

1 bit: sign

variable: the number

Decimal:

1 bit: 1 signifies its a real

1 bit: sign

8 bits: base-10 exponent

2 bits: length of significand; take this number and multiply it by 12

12, 24, 36 or 46 bits: significand in binary; assumes the most significant bit is always 1, because 0 can be represented by an integer type

Fraction:

2 bits: 00 signifies its a fraction

1 bit: sign

3 bits: length of the numerator; take the number, add 1, multiply by 3

3 bits: length of the denominator; do the same

variable: numerator

variable: denominator

Something like this. If the list has any complex numbers, then it becomes a complex list, and the real and complex part of every number is then stored. This is one of the disadvantages of normal numbers; that complex lists take up twice as much space as normal lists regardless of how many elements are actually complex. But in this system, the number 0 can be stored in 6 bits, so this isn't a problem. Worst case (50 rands in a list or something) this system gets a 85% compression ratio. What do you think? Feel free to try and implement this… good luck.

Edit: For some reason, I felt I had to use only one-byte token, but using just 15 two-byte tokens improves my compression by 7.9% percent.