28 #include <drizzled/function/math/round.h>
29 #include <drizzled/util/test.h>
34 extern const double log_10[309];
39 void Item_func_round::fix_length_and_dec()
45 unsigned_flag= args[0]->unsigned_flag;
46 if (!args[1]->const_item())
48 max_length= args[0]->max_length;
49 decimals= args[0]->decimals;
50 if (args[0]->result_type() == DECIMAL_RESULT)
53 hybrid_type= DECIMAL_RESULT;
56 hybrid_type= REAL_RESULT;
60 val1= args[1]->val_int();
61 val1_unsigned= args[1]->unsigned_flag;
63 decimals_to_set= val1_unsigned ? INT_MAX : 0;
65 decimals_to_set= (val1 > INT_MAX) ? INT_MAX : (
int) val1;
67 if (args[0]->decimals == NOT_FIXED_DEC)
69 max_length= args[0]->max_length;
70 decimals= min(decimals_to_set, (
int)NOT_FIXED_DEC);
71 hybrid_type= REAL_RESULT;
75 switch (args[0]->result_type()) {
78 hybrid_type= REAL_RESULT;
79 decimals= min(decimals_to_set, (
int)NOT_FIXED_DEC);
80 max_length= float_length(decimals);
83 if ((!decimals_to_set && truncate) || (args[0]->decimal_precision() < DECIMAL_LONGLONG_DIGITS))
85 int length_can_increase= test(!truncate && (val1 < 0) && !val1_unsigned);
86 max_length= args[0]->max_length + length_can_increase;
88 hybrid_type= INT_RESULT;
95 hybrid_type= DECIMAL_RESULT;
96 decimals_to_set= min(DECIMAL_MAX_SCALE, decimals_to_set);
97 int decimals_delta= args[0]->decimals - decimals_to_set;
98 int precision= args[0]->decimal_precision();
99 int length_increase= ((decimals_delta <= 0) || truncate) ? 0:1;
101 precision-= decimals_delta - length_increase;
102 decimals= min(decimals_to_set, DECIMAL_MAX_SCALE);
103 max_length= class_decimal_precision_to_length(precision, decimals,
112 double my_double_round(
double value, int64_t dec,
bool dec_unsigned,
116 bool dec_negative= (dec < 0) && !dec_unsigned;
117 uint64_t abs_dec= dec_negative ? -dec : dec;
124 tmp=(abs_dec < array_elements(log_10) ?
125 log_10[abs_dec] : pow(10.0,(
double) abs_dec));
127 double value_times_tmp= value * tmp;
138 if(
sizeof(
double) <
sizeof(double_t))
140 volatile double t= value_times_tmp;
144 double infinity= numeric_limits<double>::infinity();
145 if (dec_negative && (tmp == infinity))
147 else if (!dec_negative && (value_times_tmp == infinity))
152 tmp2= dec < 0 ? floor(value/tmp)*tmp : floor(value*tmp)/tmp;
154 tmp2= dec < 0 ? ceil(value/tmp)*tmp : ceil(value*tmp)/tmp;
157 tmp2=dec < 0 ? rint(value/tmp)*tmp : rint(value*tmp)/tmp;
164 double value= args[0]->val_real();
166 if (!(null_value= args[0]->null_value || args[1]->null_value))
167 return my_double_round(value, args[1]->val_int(), args[1]->unsigned_flag,
178 static inline uint64_t my_unsigned_round(uint64_t value, uint64_t to)
180 uint64_t tmp= value / to * to;
181 return (value - tmp < (to >> 1)) ? tmp : tmp + to;
187 int64_t value= args[0]->val_int();
188 int64_t dec= args[1]->val_int();
191 if ((null_value= args[0]->null_value || args[1]->null_value))
193 if ((dec >= 0) || args[1]->unsigned_flag)
199 if(abs_dec >= array_elements(log_10_int))
202 tmp= log_10_int[abs_dec];
205 value= (unsigned_flag) ?
206 (int64_t)(((uint64_t) value / tmp) * tmp) : (value / tmp) * tmp;
208 value= (unsigned_flag || value >= 0) ?
209 (int64_t)(my_unsigned_round((uint64_t) value, tmp)) :
210 -(int64_t) my_unsigned_round((uint64_t) -value, tmp);
218 int64_t dec= args[1]->val_int();
220 if (dec >= 0 || args[1]->unsigned_flag)
221 dec= min(dec, (int64_t) decimals);
222 else if (dec < INT_MIN)
225 if (!(null_value= (args[0]->null_value || args[1]->null_value ||
226 class_decimal_round(E_DEC_FATAL_ERROR, value, (
int) dec,
227 truncate, decimal_value) > 1)))
229 decimal_value->frac= decimals;
230 return decimal_value;