In a range coder, using finite-precision arithmetic can lead to cases where it's not possible to encode the next symbol without first applying some kind of flush or tweak to open up space in the working registers.
A consequence of this is that, depending on how things are tweaked, some small gap may be left in the set of legal bitstreams.
For example, the Wikipedia page proposes to narrow the output range to something that allows more bits to be shifted out, leaving some part of the original range as undefined.
In the decoder it's possible to come to that same point, and then find that the input bitstream itself doesn't conform with the encoder tweak, but instead continues down into the gap that should have been discarded by the encoder. There's no correct decode of such a bitstream.
Contrast this with something like Huffman, which is normally defined without any ambiguous input configuration (except at the end of the stream where there may be an incomplete symbol). So it's possible to decode an arbitrary bitstream into a message which can then be re-encoded into the original bitstream.
My question is this: Is it possible to formulate some kind of tweak which deals with the precision limits but does not create the possibility of an undecodable or ambiguous bitstream? Such that given an arbitrary bitstream it's always possible to decode it to some set of symbols which can be re-encoded back into the original bitstream?
Intuitively it seems like it should be impossible and I shouldn't bash my head against this problem; but I look at Huffman and reason that it has a property that I should be able to simulate.
And in the process of writing the question I believe I may have found a solution; but I'm not sure just yet. I'll leave it here and either someone (possibly myself) will eventually tell me why I'm wrong, or it'll be correct and potentially useful to others...
When you get to the point that the range of the output is too small for the next symbol, the implication is that that range straddles a value which is a large power of two, and that is the point at which the low and high boundaries end up differing in the most significant bit.
So take your symbol frequency table and partition it at approximately the same place as the POT boundary in your range. Then set either the high or low boundary to the POT depending on whether the symbol is first or second partition; then flush the newly released bits and encode the partition as if it were a complete symbol and carry on.
Perhaps there's a functionally equivalent way of doing this which is less long-winded, though.