@@ -4089,58 +4089,86 @@ int64_to_numeric(int64 val)
4089
4089
}
4090
4090
4091
4091
/*
4092
- * Convert val1/(10**val2 ) to numeric. This is much faster than normal
4092
+ * Convert val1/(10**log10val2 ) to numeric. This is much faster than normal
4093
4093
* numeric division.
4094
4094
*/
4095
4095
Numeric
4096
4096
int64_div_fast_to_numeric (int64 val1 , int log10val2 )
4097
4097
{
4098
4098
Numeric res ;
4099
4099
NumericVar result ;
4100
- int64 saved_val1 = val1 ;
4100
+ int rscale ;
4101
4101
int w ;
4102
4102
int m ;
4103
4103
4104
+ init_var (& result );
4105
+
4106
+ /* result scale */
4107
+ rscale = log10val2 < 0 ? 0 : log10val2 ;
4108
+
4104
4109
/* how much to decrease the weight by */
4105
4110
w = log10val2 / DEC_DIGITS ;
4106
- /* how much is left */
4111
+ /* how much is left to divide by */
4107
4112
m = log10val2 % DEC_DIGITS ;
4113
+ if (m < 0 )
4114
+ {
4115
+ m += DEC_DIGITS ;
4116
+ w -- ;
4117
+ }
4108
4118
4109
4119
/*
4110
- * If there is anything left, multiply the dividend by what's left, then
4111
- * shift the weight by one more.
4120
+ * If there is anything left to divide by (10^m with 0 < m < DEC_DIGITS),
4121
+ * multiply the dividend by 10^(DEC_DIGITS - m), and shift the weight by
4122
+ * one more.
4112
4123
*/
4113
4124
if (m > 0 )
4114
4125
{
4115
- static __thread int pow10 [] = {1 , 10 , 100 , 1000 };
4126
+ #if DEC_DIGITS == 4
4127
+ static __thread int pow10 [] = {1 , 10 , 100 , 1000 };
4128
+ #elif DEC_DIGITS == 2
4129
+ static __thread int pow10 [] = {1 , 10 };
4130
+ #elif DEC_DIGITS == 1
4131
+ static __thread int pow10 [] = {1 };
4132
+ #else
4133
+ #error unsupported NBASE
4134
+ #endif
4135
+ int64 factor = pow10 [DEC_DIGITS - m ];
4136
+ int64 new_val1 ;
4116
4137
4117
4138
StaticAssertStmt (lengthof (pow10 ) == DEC_DIGITS , "mismatch with DEC_DIGITS" );
4118
- if (unlikely (pg_mul_s64_overflow (val1 , pow10 [DEC_DIGITS - m ], & val1 )))
4139
+
4140
+ if (unlikely (pg_mul_s64_overflow (val1 , factor , & new_val1 )))
4119
4141
{
4120
- /*
4121
- * If it doesn't fit, do the whole computation in numeric the slow
4122
- * way. Note that va1l may have been overwritten, so use
4123
- * saved_val1 instead.
4124
- */
4125
- int val2 = 1 ;
4126
-
4127
- for (int i = 0 ; i < log10val2 ; i ++ )
4128
- val2 *= 10 ;
4129
- res = numeric_div_opt_error (int64_to_numeric (saved_val1 ), int64_to_numeric (val2 ), NULL );
4130
- res = DatumGetNumeric (DirectFunctionCall2 (numeric_round ,
4131
- NumericGetDatum (res ),
4132
- Int32GetDatum (log10val2 )));
4133
- return res ;
4142
+ #ifdef HAVE_INT128
4143
+ /* do the multiplication using 128-bit integers */
4144
+ int128 tmp ;
4145
+
4146
+ tmp = (int128 ) val1 * (int128 ) factor ;
4147
+
4148
+ int128_to_numericvar (tmp , & result );
4149
+ #else
4150
+ /* do the multiplication using numerics */
4151
+ NumericVar tmp ;
4152
+
4153
+ init_var (& tmp );
4154
+
4155
+ int64_to_numericvar (val1 , & result );
4156
+ int64_to_numericvar (factor , & tmp );
4157
+ mul_var (& result , & tmp , & result , 0 );
4158
+
4159
+ free_var (& tmp );
4160
+ #endif
4134
4161
}
4162
+ else
4163
+ int64_to_numericvar (new_val1 , & result );
4164
+
4135
4165
w ++ ;
4136
4166
}
4137
-
4138
- init_var (& result );
4139
-
4140
- int64_to_numericvar (val1 , & result );
4167
+ else
4168
+ int64_to_numericvar (val1 , & result );
4141
4169
4142
4170
result .weight -= w ;
4143
- result .dscale += w * DEC_DIGITS - ( DEC_DIGITS - m ) ;
4171
+ result .dscale = rscale ;
4144
4172
4145
4173
res = make_result (& result );
4146
4174
0 commit comments