From 5ed9f2e5aaa922b423e87a1b812ca5489238d08e Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Mon, 20 Oct 2003 22:33:53 +0000 Subject: [PATCH] use continued fractions to approximate a fraction if its numerator or denominator is too large Originally committed as revision 2405 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavcodec/utils.c | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/libavcodec/utils.c b/libavcodec/utils.c index f9ed4f5ab6..34051ad3a4 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -684,7 +684,7 @@ char av_get_pict_type_char(int pict_type){ int av_reduce(int *dst_nom, int *dst_den, int64_t nom, int64_t den, int64_t max){ int exact=1, sign=0; - int64_t gcd, larger; + int64_t gcd; assert(den != 0); @@ -698,22 +698,34 @@ int av_reduce(int *dst_nom, int *dst_den, int64_t nom, int64_t den, int64_t max) sign= 1; } - for(;;){ //note is executed 1 or 2 times - gcd = ff_gcd(nom, den); - nom /= gcd; - den /= gcd; + gcd = ff_gcd(nom, den); + nom /= gcd; + den /= gcd; - larger= FFMAX(nom, den); - - if(larger > max){ - int64_t div= (larger + max - 1) / max; - nom = (nom + div/2)/div; - den = (den + div/2)/div; - exact=0; - }else - break; + if(nom > max || den > max){ + AVRational a0={0,1}, a1={1,0}; + exact=0; + + for(;;){ + int64_t x= nom / den; + int64_t a2n= x*a1.num + a0.num; + int64_t a2d= x*a1.den + a0.den; + + if(a2n > max || a2d > max) break; + + nom %= den; + + a0= a1; + a1= (AVRational){a2n, a2d}; + if(nom==0) break; + x= nom; nom=den; den=x; + } + nom= a1.num; + den= a1.den; } + assert(ff_gcd(nom, den) == 1); + if(sign) nom= -nom; *dst_nom = nom;