[FFmpeg-user] missing a selected frame

Stéphane Chauveau stephane at chauveau-central.net
Fri Jul 19 16:58:39 EEST 2019


On 7/19/19 3:16 PM, Ulf Zibis wrote:
>
>> Using eq() on floating points is indeed a bad idea because of floating
>> point rounding.
> In the code of the select filter I've found:
> #define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts))
>      select->var_values[VAR_T  ] = TS2D(frame->pts) *
> av_q2d(inlink->time_base);
>
> So there rounding happens twice.
>
> This could be avoided with:
>      select->var_values[VAR_T  ] = (frame->pts == AV_NOPTS_VALUE) ? NAN :
> frame->pts * inlink->time_base.num / inlink->time_base.den;
>
> But after applying this I got even worse results, so there must be
> another rounding counterpart somewhere which "heals" most rounding
> issues, but not all as I can see with "10.2" from my example.
>
> -Ulf

You don't get it. The problem is not that you need a better formula. The 
problem is that some values such as  10.2 cannot be exactly represented 
using floating point values.

For example, let's consider a few examples using the printf builtin from 
bash.

First, let's print 10.2 using  the default floating point precision

# printf "%f\n"  10.2
10.20000

Now, let's increase the number of digits after the decimal point.

# for ((i=5;i<=40;i+=5)) ; do printf "%.${i}f\n" 10.2 ; done

10.20000
10.2000000000
10.200000000000000
10.19999999999999999983
10.1999999999999999998265277
10.199999999999999999826527652402
10.19999999999999999982652765240231929
10.1999999999999999998265276524023192905588

As you can see, the actual value of 10.2  is 
10.1999999999999999998265276524023192905588....

The next value that can be represented using a 'double precision 
floating point is

10.2000000000000000006938893903907228377648....

# for ((i=5;i<=40;i+=5)) ; do printf "%.${i}f\n" 10.2000000000000000004 
; done

10.20000
10.2000000000
10.200000000000000
10.20000000000000000069
10.2000000000000000006938894
10.200000000000000000693889390391
10.20000000000000000069388939039072284
10.2000000000000000006938893903907228377648

There is nothing between those two values.

If you do the same with 102.0 and 10.0 you will notice that those two 
values can be represented exactly. This is beause they are small 
integers and those can be represented exactly using floating point numbers.

# for ((i=5;i<=40;i+=5)) ; do printf "%.${i}f\n" 102.0 ; done102.00000

102.0000000000
102.000000000000000
102.00000000000000000000
102.0000000000000000000000000
102.000000000000000000000000000000
102.00000000000000000000000000000000000
102.0000000000000000000000000000000000000000

Consider the C expression

((double) 102) / ((double) 10)

The conversion or 102 and 10  to floating point double precision values 
does not cause any rounding. So far so good.

102.00000000000000... / 10.0000000000000000000000000

However, since 10.2 cannot be represented in floating point, the final 
result of the division is either

10.1999999999999999998265276524023192905588...

or

10.2000000000000000006938893903907228377648...

The divison operator will choose one of the two values. The parser also 
choose one of the two values when converting the string "10.2" into a 
floating point value. The problem is that you cannot be sure that both 
actions will do the same choice. Eventually, the test eq(t,10.2) becomes

eq( 10.1999999999999999998265276524023192905588 , 
10.2000000000000000006938893903907228377648 )

and the result of that comparison is FALSE.

Your new formula does not work because it uses integer arithmetic. You 
are basically computing 102/10 = 10  which is obviously a lot worse than 
the two floating point approximations. YOU CANNOT AVOID ROUNDING ERRORS 
WHEN USING FLOATING POINT ARITHMETIC. THIS IS IMPOSSIBLE EXCEPT IN SOME 
SPECIAL CASES THAT ARE NOT APPLICABLE HERE.

Stéphane C.












More information about the ffmpeg-user mailing list