[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