00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <config.h>
00021
00022 #include <math.h>
00023 #include <limits.h>
00024
00025 #include <limits>
00026 #include <algorithm>
00027
00028 #include <drizzled/function/math/round.h>
00029 #include <drizzled/util/test.h>
00030
00031 namespace drizzled
00032 {
00033
00034 extern const double log_10[309];
00035
00036
00037 using namespace std;
00038
00039 void Item_func_round::fix_length_and_dec()
00040 {
00041 int decimals_to_set;
00042 int64_t val1;
00043 bool val1_unsigned;
00044
00045 unsigned_flag= args[0]->unsigned_flag;
00046 if (!args[1]->const_item())
00047 {
00048 max_length= args[0]->max_length;
00049 decimals= args[0]->decimals;
00050 if (args[0]->result_type() == DECIMAL_RESULT)
00051 {
00052 max_length++;
00053 hybrid_type= DECIMAL_RESULT;
00054 }
00055 else
00056 hybrid_type= REAL_RESULT;
00057 return;
00058 }
00059
00060 val1= args[1]->val_int();
00061 val1_unsigned= args[1]->unsigned_flag;
00062 if (val1 < 0)
00063 decimals_to_set= val1_unsigned ? INT_MAX : 0;
00064 else
00065 decimals_to_set= (val1 > INT_MAX) ? INT_MAX : (int) val1;
00066
00067 if (args[0]->decimals == NOT_FIXED_DEC)
00068 {
00069 max_length= args[0]->max_length;
00070 decimals= min(decimals_to_set, (int)NOT_FIXED_DEC);
00071 hybrid_type= REAL_RESULT;
00072 return;
00073 }
00074
00075 switch (args[0]->result_type()) {
00076 case REAL_RESULT:
00077 case STRING_RESULT:
00078 hybrid_type= REAL_RESULT;
00079 decimals= min(decimals_to_set, (int)NOT_FIXED_DEC);
00080 max_length= float_length(decimals);
00081 break;
00082 case INT_RESULT:
00083 if ((!decimals_to_set && truncate) || (args[0]->decimal_precision() < DECIMAL_LONGLONG_DIGITS))
00084 {
00085 int length_can_increase= test(!truncate && (val1 < 0) && !val1_unsigned);
00086 max_length= args[0]->max_length + length_can_increase;
00087
00088 hybrid_type= INT_RESULT;
00089 decimals= 0;
00090 break;
00091 }
00092
00093 case DECIMAL_RESULT:
00094 {
00095 hybrid_type= DECIMAL_RESULT;
00096 decimals_to_set= min(DECIMAL_MAX_SCALE, decimals_to_set);
00097 int decimals_delta= args[0]->decimals - decimals_to_set;
00098 int precision= args[0]->decimal_precision();
00099 int length_increase= ((decimals_delta <= 0) || truncate) ? 0:1;
00100
00101 precision-= decimals_delta - length_increase;
00102 decimals= min(decimals_to_set, DECIMAL_MAX_SCALE);
00103 max_length= class_decimal_precision_to_length(precision, decimals,
00104 unsigned_flag);
00105 break;
00106 }
00107 default:
00108 assert(0);
00109 }
00110 }
00111
00112 double my_double_round(double value, int64_t dec, bool dec_unsigned,
00113 bool truncate)
00114 {
00115 double tmp;
00116 bool dec_negative= (dec < 0) && !dec_unsigned;
00117 uint64_t abs_dec= dec_negative ? -dec : dec;
00118
00119
00120
00121
00122 double tmp2;
00123
00124 tmp=(abs_dec < array_elements(log_10) ?
00125 log_10[abs_dec] : pow(10.0,(double) abs_dec));
00126
00127 double value_times_tmp= value * tmp;
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138 if(sizeof(double) < sizeof(double_t))
00139 {
00140 volatile double t= value_times_tmp;
00141 value_times_tmp= t;
00142 }
00143
00144 double infinity= numeric_limits<double>::infinity();
00145 if (dec_negative && (tmp == infinity))
00146 tmp2= 0;
00147 else if (!dec_negative && (value_times_tmp == infinity))
00148 tmp2= value;
00149 else if (truncate)
00150 {
00151 if (value >= 0)
00152 tmp2= dec < 0 ? floor(value/tmp)*tmp : floor(value*tmp)/tmp;
00153 else
00154 tmp2= dec < 0 ? ceil(value/tmp)*tmp : ceil(value*tmp)/tmp;
00155 }
00156 else
00157 tmp2=dec < 0 ? rint(value/tmp)*tmp : rint(value*tmp)/tmp;
00158 return tmp2;
00159 }
00160
00161
00162 double Item_func_round::real_op()
00163 {
00164 double value= args[0]->val_real();
00165
00166 if (!(null_value= args[0]->null_value || args[1]->null_value))
00167 return my_double_round(value, args[1]->val_int(), args[1]->unsigned_flag,
00168 truncate);
00169
00170 return 0.0;
00171 }
00172
00173
00174
00175
00176
00177
00178 static inline uint64_t my_unsigned_round(uint64_t value, uint64_t to)
00179 {
00180 uint64_t tmp= value / to * to;
00181 return (value - tmp < (to >> 1)) ? tmp : tmp + to;
00182 }
00183
00184
00185 int64_t Item_func_round::int_op()
00186 {
00187 int64_t value= args[0]->val_int();
00188 int64_t dec= args[1]->val_int();
00189 decimals= 0;
00190 uint64_t abs_dec;
00191 if ((null_value= args[0]->null_value || args[1]->null_value))
00192 return 0;
00193 if ((dec >= 0) || args[1]->unsigned_flag)
00194 return value;
00195
00196 abs_dec= -dec;
00197 int64_t tmp;
00198
00199 if(abs_dec >= array_elements(log_10_int))
00200 return 0;
00201
00202 tmp= log_10_int[abs_dec];
00203
00204 if (truncate)
00205 value= (unsigned_flag) ?
00206 (int64_t)(((uint64_t) value / tmp) * tmp) : (value / tmp) * tmp;
00207 else
00208 value= (unsigned_flag || value >= 0) ?
00209 (int64_t)(my_unsigned_round((uint64_t) value, tmp)) :
00210 -(int64_t) my_unsigned_round((uint64_t) -value, tmp);
00211 return value;
00212 }
00213
00214
00215 type::Decimal *Item_func_round::decimal_op(type::Decimal *decimal_value)
00216 {
00217 type::Decimal val, *value= args[0]->val_decimal(&val);
00218 int64_t dec= args[1]->val_int();
00219
00220 if (dec >= 0 || args[1]->unsigned_flag)
00221 dec= min(dec, (int64_t) decimals);
00222 else if (dec < INT_MIN)
00223 dec= INT_MIN;
00224
00225 if (!(null_value= (args[0]->null_value || args[1]->null_value ||
00226 class_decimal_round(E_DEC_FATAL_ERROR, value, (int) dec,
00227 truncate, decimal_value) > 1)))
00228 {
00229 decimal_value->frac= decimals;
00230 return decimal_value;
00231 }
00232 return 0;
00233 }
00234
00235 }