From 2ee5b08e94e76ad08f96f007474034e9fe5fdf17 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Thu, 21 Oct 2010 23:47:23 +0000 Subject: [PATCH] (trunk libT) #3521 "rounding issue in tr_truncd()" -- try yet again to work out all the fringe cases :) --- libtransmission/utils-test.c | 11 +++++++++++ libtransmission/utils.c | 17 ++++++++++------- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/libtransmission/utils-test.c b/libtransmission/utils-test.c index d6363c690..c07d2fe64 100644 --- a/libtransmission/utils-test.c +++ b/libtransmission/utils-test.c @@ -1,3 +1,4 @@ +#include #include /* fprintf */ #include /* strcmp */ @@ -379,6 +380,7 @@ static int test_truncd( void ) { char buf[32]; + const double nan = sqrt( -1 ); tr_snprintf( buf, sizeof( buf ), "%.2f%%", 99.999 ); check( !strcmp( buf, "100.00%" ) ); @@ -395,6 +397,15 @@ test_truncd( void ) tr_snprintf( buf, sizeof( buf ), "%.2f", tr_truncd( 2.05, 2 ) ); check( !strcmp( buf, "2.05" ) ); + tr_snprintf( buf, sizeof( buf ), "%.2f", tr_truncd( 3.3333, 2 ) ); + check( !strcmp( buf, "3.33" ) ); + + tr_snprintf( buf, sizeof( buf ), "%.0f", tr_truncd( 3.3333, 0 ) ); + check( !strcmp( buf, "3" ) ); + + tr_snprintf( buf, sizeof( buf ), "%.2f", tr_truncd( nan, 2 ) ); + check( !strcmp( buf, "nan" ) ); + return 0; } diff --git a/libtransmission/utils.c b/libtransmission/utils.c index 1d621c3f3..77ff5e19d 100644 --- a/libtransmission/utils.c +++ b/libtransmission/utils.c @@ -24,6 +24,8 @@ #include #include /* isalpha(), tolower() */ #include +#include /* DBL_EPSILON */ +#include /* localeconv() */ #include /* pow(), fabs(), floor() */ #include #include @@ -1431,14 +1433,15 @@ tr_parseNumberRange( const char * str_in, int len, int * setmeCount ) ***/ double -tr_truncd( double x, int decimal_places ) +tr_truncd( double x, int precision ) { - /* sigh... surely there's a better way to do this */ - char buf[1024]; - const int i = (int) pow( 10, decimal_places ); - snprintf( buf, sizeof( buf ), "%f", x*i ); - *strchr(buf,'.') = '\0'; - return atof(buf) / i; + char * pt; + char buf[128]; + const int max_precision = (int) log10( 1.0 / DBL_EPSILON ) - 1; + tr_snprintf( buf, sizeof( buf ), "%.*f", max_precision, x ); + if(( pt = strstr( buf, localeconv()->decimal_point ))) + pt[precision ? precision+1 : 0] = '\0'; + return atof(buf); } char*