For such small number of bits, it is infeasible to save many bits as Glorfindel has pointed out.
However, if the domain you are using has a few more bits, you can achieve significant savings for the average case by encoding ranges with the start value and a delta.
Lets assume the domain is the integers, so 32 bits. With the naive approach, you need 64 bits (start, end) to store a range.
If we switch to an encoding of (start, delta), we can construct the end of the range from that. We know that in the worst case, the start is 0 and the delta has 32 bits.
2^5 is 32, so we encode the length of the delta in five bits (no zero length, always add 1), and the encoding becomes (start, length, delta). In the worst case, this costs 32*2 + 5 bits, so 69 bits. So in the worst case, if all ranges are long, this is worse then the naive encoding.
In the best case, it costs 32 + 5 + 1 = 38 bits.
This means if you have to encode a lot of ranges, and those ranges each only cover small part of your domain, you end up using less space on average using this encoding. It doesn't matter how the starts are distributed, since the start will always take 32 bits, but it does matter how the lengths of the ranges are distributed. If the more small lengths you have, the better the compression, the more ranges you have that cover the whole length of the domain, the worse this encoding will get.
However, if you have lots of ranges grouped around similar start points, (for example because you get values from a sensor), you can achieve even bigger savings. You can apply the same technique to the start value and use a bias to offset the start value.
Lets say you have 10000 ranges. The ranges are grouped around a certain value. You encode the bias with 32 bits.
Using the naive approach, you would need 32*2 * 10 000 = 640 000 bits to store all those ranges.
Encoding the bias takes 32 bits, and encoding each range takes in the best case then 5 + 1 + 5 + 1 = 12 bits, for a total of 120 000 + 32 = 120 032 bits.
In the worst case, you need 5 + 32 + 5 + 32 bits, thus 74 bits, for a total of 740 032 bits.
This means, for 10 000 values on a domain that takes 32 bits to encode, we get
- 120 032 bits with the smart delta-encoding in the best case
- 640 000 bits with the naive start, end encoding, always (no best or worst case)
- 740 032 bits with the smart delta encoding in the worst case
If you take the naive encoding as baseline, that means either savings of up to 81.25% or up to 15.625% more cost.
Depending on how your values are distributed, those savings are significant. Know your business domain! Know what you want to encode.
As an extension, you can also change the bias. If you analyse the data and identify groups of values, you can sort the data into buckets and encode each of those buckets separately, with its own bias. This means you can apply this technique not only to ranges that are grouped around a single start value, but also to ranges that are grouped around multiple values.
If your start points are distributed equally, this encoding doesn't really work that well.
This encoding is obviously extremely bad to index. You can not simply read the x-th value. It can pretty much only be read sequentially. Which is appropriate in some situations, e.g. streaming over the network or bulk storage (e.g. on tape or HDD).
Evaluating the data, grouping it and choosing the correct bias can be substantial work and might require some fine-tuning for optimal results.