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.