celt_decode_lost() - very poor precision/wrong result in application of frac_div32( arg1, arg2 )
Looking in celt_decode_lost() under the comment:
/* Check if the waveform is decaying (and if so how fast)
We do this to avoid adding energy when concealing in a segment
with decaying energy */
decay = celt_sqrt( frac_div32(SHR32(E1,1),E2) );
We see that if E1=1 then the 1-bit right shift of E1 makes E1=0. Therefore ANY E1, E2 combinations like 1/2, 1/3, ... 1/n will evaluate to zero. Similarly, for small values of E1 the precision of the result is needlessly poor (see table below).
Suggested fix: If the intent of shifting was done to bound the output of frac_div32 to (0.5,0] then an alternate solution which avoids the E1=1 pitfall (and poor precision on small values of E1) is to shift the result of frac_div32(), instead.
decay = celt_sqrt( frac_div32(E1,E2)>>1 );
Here is a small table of test values to illustrate:
decay = celt_sqrt ( frac_div32(SHR32(E1,1),E2) );
====================================================
7FEB = celt_sqrt( 3FF36D10 = frac_div32(1303/1303)) <-- so-so
687C = celt_sqrt( 2AAAAAA0 = frac_div32( 11/ 15)) <-- not great
5A86 = celt_sqrt( 1FFFFFF0 = frac_div32( 3/ 4)) <-- very bad
0000 = celt_sqrt( 00000000 = frac_div32( 1/ 1)) <-- wrong
With suggested code fix:
decay = celt_sqrt( frac_div32(E1,E2)>>1 );
====================================================
7FF6 = celt_sqrt( 3FFFFFF8 = frac_div32(1303/1303))
6D97 = celt_sqrt( 2EEEEEE8 = frac_div32( 11/ 15))
6ED5 = celt_sqrt( 2FFFFFF8 = frac_div32( 3/ 4))
7FF6 = celt_sqrt( 3FFFFFF8 = frac_div32( 1/ 1))