ffmpeg / libavutil / rational.c @ d71ad089
History  View  Annotate  Download (3.7 KB)
1 
/*


2 
* rational numbers

3 
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>

4 
*

5 
* This file is part of FFmpeg.

6 
*

7 
* FFmpeg is free software; you can redistribute it and/or

8 
* modify it under the terms of the GNU Lesser General Public

9 
* License as published by the Free Software Foundation; either

10 
* version 2.1 of the License, or (at your option) any later version.

11 
*

12 
* FFmpeg is distributed in the hope that it will be useful,

13 
* but WITHOUT ANY WARRANTY; without even the implied warranty of

14 
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU

15 
* Lesser General Public License for more details.

16 
*

17 
* You should have received a copy of the GNU Lesser General Public

18 
* License along with FFmpeg; if not, write to the Free Software

19 
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 021101301 USA

20 
*/

21  
22 
/**

23 
* @file libavutil/rational.c

24 
* rational numbers

25 
* @author Michael Niedermayer <michaelni@gmx.at>

26 
*/

27  
28 
#include <assert.h> 
29 
//#include <math.h>

30 
#include <limits.h> 
31  
32 
#include "common.h" 
33 
#include "mathematics.h" 
34 
#include "rational.h" 
35  
36 
int av_reduce(int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max){ 
37 
AVRational a0={0,1}, a1={1,0}; 
38 
int sign= (num<0) ^ (den<0); 
39 
int64_t gcd= av_gcd(FFABS(num), FFABS(den)); 
40  
41 
if(gcd){

42 
num = FFABS(num)/gcd; 
43 
den = FFABS(den)/gcd; 
44 
} 
45 
if(num<=max && den<=max){

46 
a1= (AVRational){num, den}; 
47 
den=0;

48 
} 
49  
50 
while(den){

51 
uint64_t x = num / den; 
52 
int64_t next_den= num  den*x; 
53 
int64_t a2n= x*a1.num + a0.num; 
54 
int64_t a2d= x*a1.den + a0.den; 
55  
56 
if(a2n > max  a2d > max){

57 
if(a1.num) x= (max  a0.num) / a1.num;

58 
if(a1.den) x= FFMIN(x, (max  a0.den) / a1.den);

59  
60 
if (den*(2*x*a1.den + a0.den) > num*a1.den) 
61 
a1 = (AVRational){x*a1.num + a0.num, x*a1.den + a0.den}; 
62 
break;

63 
} 
64  
65 
a0= a1; 
66 
a1= (AVRational){a2n, a2d}; 
67 
num= den; 
68 
den= next_den; 
69 
} 
70 
assert(av_gcd(a1.num, a1.den) <= 1U);

71  
72 
*dst_num = sign ? a1.num : a1.num; 
73 
*dst_den = a1.den; 
74  
75 
return den==0; 
76 
} 
77  
78 
AVRational av_mul_q(AVRational b, AVRational c){ 
79 
av_reduce(&b.num, &b.den, b.num * (int64_t)c.num, b.den * (int64_t)c.den, INT_MAX); 
80 
return b;

81 
} 
82  
83 
AVRational av_div_q(AVRational b, AVRational c){ 
84 
return av_mul_q(b, (AVRational){c.den, c.num});

85 
} 
86  
87 
AVRational av_add_q(AVRational b, AVRational c){ 
88 
av_reduce(&b.num, &b.den, b.num * (int64_t)c.den + c.num * (int64_t)b.den, b.den * (int64_t)c.den, INT_MAX); 
89 
return b;

90 
} 
91  
92 
AVRational av_sub_q(AVRational b, AVRational c){ 
93 
return av_add_q(b, (AVRational){c.num, c.den});

94 
} 
95  
96 
AVRational av_d2q(double d, int max){ 
97 
AVRational a; 
98 
#define LOG2 0.69314718055994530941723212145817656807550013436025 
99 
int exponent= FFMAX( (int)(log(fabs(d) + 1e20)/LOG2), 0); 
100 
int64_t den= 1LL << (61  exponent); 
101 
av_reduce(&a.num, &a.den, (int64_t)(d * den + 0.5), den, max); 
102  
103 
return a;

104 
} 
105  
106 
int av_nearer_q(AVRational q, AVRational q1, AVRational q2)

107 
{ 
108 
/* n/d is q, a/b is the median between q1 and q2 */

109 
int64_t a = q1.num * (int64_t)q2.den + q2.num * (int64_t)q1.den; 
110 
int64_t b = 2 * (int64_t)q1.den * q2.den;

111  
112 
/* rnd_up(a*d/b) > n => a*d/b > n */

113 
int64_t x_up = av_rescale_rnd(a, q.den, b, AV_ROUND_UP); 
114  
115 
/* rnd_down(a*d/b) < n => a*d/b < n */

116 
int64_t x_down = av_rescale_rnd(a, q.den, b, AV_ROUND_DOWN); 
117  
118 
return ((x_up > q.num)  (x_down < q.num)) * av_cmp_q(q2, q1);

119 
} 
120  
121 
int av_find_nearest_q_idx(AVRational q, const AVRational* q_list) 
122 
{ 
123 
int i, nearest_q_idx = 0; 
124 
for(i=0; q_list[i].den; i++) 
125 
if (av_nearer_q(q, q_list[i], q_list[nearest_q_idx]) > 0) 
126 
nearest_q_idx = i; 
127  
128 
return nearest_q_idx;

129 
} 