@ -4089,7 +4089,7 @@ int64_to_numeric(int64 val)
}
}
/*
/*
* Convert val1 / ( 10 * * val2 ) to numeric . This is much faster than normal
* Convert val1 / ( 10 * * log10 val2) to numeric . This is much faster than normal
* numeric division .
* numeric division .
*/
*/
Numeric
Numeric
@ -4097,50 +4097,78 @@ int64_div_fast_to_numeric(int64 val1, int log10val2)
{
{
Numeric res ;
Numeric res ;
NumericVar result ;
NumericVar result ;
int64 saved_val1 = val1 ;
int rscale ;
int w ;
int w ;
int m ;
int m ;
init_var ( & result ) ;
/* result scale */
rscale = log10val2 < 0 ? 0 : log10val2 ;
/* how much to decrease the weight by */
/* how much to decrease the weight by */
w = log10val2 / DEC_DIGITS ;
w = log10val2 / DEC_DIGITS ;
/* how much is left */
/* how much is left to divide by */
m = log10val2 % DEC_DIGITS ;
m = log10val2 % DEC_DIGITS ;
if ( m < 0 )
{
m + = DEC_DIGITS ;
w - - ;
}
/*
/*
* If there is anything left , multiply the dividend by what ' s left , then
* If there is anything left to divide by ( 10 ^ m with 0 < m < DEC_DIGITS ) ,
* shift the weight by one more .
* multiply the dividend by 10 ^ ( DEC_DIGITS - m ) , and shift the weight by
* one more .
*/
*/
if ( m > 0 )
if ( m > 0 )
{
{
static int pow10 [ ] = { 1 , 10 , 100 , 1000 } ;
# if DEC_DIGITS == 4
static const int pow10 [ ] = { 1 , 10 , 100 , 1000 } ;
# elif DEC_DIGITS == 2
static const int pow10 [ ] = { 1 , 10 } ;
# elif DEC_DIGITS == 1
static const int pow10 [ ] = { 1 } ;
# else
# error unsupported NBASE
# endif
int64 factor = pow10 [ DEC_DIGITS - m ] ;
int64 new_val1 ;
StaticAssertStmt ( lengthof ( pow10 ) = = DEC_DIGITS , " mismatch with DEC_DIGITS " ) ;
StaticAssertStmt ( lengthof ( pow10 ) = = DEC_DIGITS , " mismatch with DEC_DIGITS " ) ;
if ( unlikely ( pg_mul_s64_overflow ( val1 , pow10 [ DEC_DIGITS - m ] , & val1 ) ) )
if ( unlikely ( pg_mul_s64_overflow ( val1 , factor , & new_val1 ) ) )
{
{
/*
# ifdef HAVE_INT128
* If it doesn ' t fit , do the whole computation in numeric the slow
/* do the multiplication using 128-bit integers */
* way . Note that va1l may have been overwritten , so use
int128 tmp ;
* saved_val1 instead .
*/
tmp = ( int128 ) val1 * ( int128 ) factor ;
int val2 = 1 ;
int128_to_numericvar ( tmp , & result ) ;
for ( int i = 0 ; i < log10val2 ; i + + )
# else
val2 * = 10 ;
/* do the multiplication using numerics */
res = numeric_div_opt_error ( int64_to_numeric ( saved_val1 ) , int64_to_numeric ( val2 ) , NULL ) ;
NumericVar tmp ;
res = DatumGetNumeric ( DirectFunctionCall2 ( numeric_round ,
NumericGetDatum ( res ) ,
init_var ( & tmp ) ;
Int32GetDatum ( log10val2 ) ) ) ;
return res ;
int64_to_numericvar ( val1 , & result ) ;
int64_to_numericvar ( factor , & tmp ) ;
mul_var ( & result , & tmp , & result , 0 ) ;
free_var ( & tmp ) ;
# endif
}
}
else
int64_to_numericvar ( new_val1 , & result ) ;
w + + ;
w + + ;
}
}
else
init_var ( & result ) ;
int64_to_numericvar ( val1 , & result ) ;
int64_to_numericvar ( val1 , & result ) ;
result . weight - = w ;
result . weight - = w ;
result . dscale + = w * DEC_DIGITS - ( DEC_DIGITS - m ) ;
result . dscale = rscale ;
res = make_result ( & result ) ;
res = make_result ( & result ) ;