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.










_______________________________________________
ffmpeg-user mailing list
[email protected]
https://ffmpeg.org/mailman/listinfo/ffmpeg-user

To unsubscribe, visit link above, or email
[email protected] with subject "unsubscribe".

Reply via email to