492.3.13
by Lee
code clean move Item_func_floor, Item_func_length, Item_func_min_max, Item_func_rand, Item_func_round to functions directory |
1 |
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
|
2 |
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
|
|
3 |
*
|
|
4 |
* Copyright (C) 2008 Sun Microsystems
|
|
5 |
*
|
|
6 |
* This program is free software; you can redistribute it and/or modify
|
|
7 |
* it under the terms of the GNU General Public License as published by
|
|
8 |
* the Free Software Foundation; version 2 of the License.
|
|
9 |
*
|
|
10 |
* This program is distributed in the hope that it will be useful,
|
|
11 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13 |
* GNU General Public License for more details.
|
|
14 |
*
|
|
15 |
* You should have received a copy of the GNU General Public License
|
|
16 |
* along with this program; if not, write to the Free Software
|
|
17 |
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
18 |
*/
|
|
19 |
||
20 |
#include <drizzled/server_includes.h> |
|
642.1.30
by Lee
move math functions to drizzled/function/math directory |
21 |
#include <drizzled/function/math/round.h> |
919.2.11
by Monty Taylor
Removed C99 isnan() usage, which allows us to remove the util/math.{cc,h} workarounds. Yay for standards! |
22 |
|
23 |
#include <limits> |
|
1067.4.2
by Nathan Williams
All files in drizzled/function/ now use std::min instead of cmin. |
24 |
#include <algorithm> |
919.2.11
by Monty Taylor
Removed C99 isnan() usage, which allows us to remove the util/math.{cc,h} workarounds. Yay for standards! |
25 |
|
572.1.4
by Monty Taylor
Removed a bunch of unusued tests and defines from autoconf. |
26 |
using namespace std; |
492.3.13
by Lee
code clean move Item_func_floor, Item_func_length, Item_func_min_max, Item_func_rand, Item_func_round to functions directory |
27 |
|
28 |
void Item_func_round::fix_length_and_dec() |
|
29 |
{
|
|
30 |
int decimals_to_set; |
|
31 |
int64_t val1; |
|
32 |
bool val1_unsigned; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
33 |
|
492.3.13
by Lee
code clean move Item_func_floor, Item_func_length, Item_func_min_max, Item_func_rand, Item_func_round to functions directory |
34 |
unsigned_flag= args[0]->unsigned_flag; |
35 |
if (!args[1]->const_item()) |
|
36 |
{
|
|
37 |
max_length= args[0]->max_length; |
|
38 |
decimals= args[0]->decimals; |
|
39 |
if (args[0]->result_type() == DECIMAL_RESULT) |
|
40 |
{
|
|
41 |
max_length++; |
|
42 |
hybrid_type= DECIMAL_RESULT; |
|
43 |
}
|
|
44 |
else
|
|
45 |
hybrid_type= REAL_RESULT; |
|
46 |
return; |
|
47 |
}
|
|
48 |
||
49 |
val1= args[1]->val_int(); |
|
50 |
val1_unsigned= args[1]->unsigned_flag; |
|
51 |
if (val1 < 0) |
|
52 |
decimals_to_set= val1_unsigned ? INT_MAX : 0; |
|
53 |
else
|
|
54 |
decimals_to_set= (val1 > INT_MAX) ? INT_MAX : (int) val1; |
|
55 |
||
56 |
if (args[0]->decimals == NOT_FIXED_DEC) |
|
57 |
{
|
|
58 |
max_length= args[0]->max_length; |
|
1067.4.2
by Nathan Williams
All files in drizzled/function/ now use std::min instead of cmin. |
59 |
decimals= min(decimals_to_set, (int)NOT_FIXED_DEC); |
492.3.13
by Lee
code clean move Item_func_floor, Item_func_length, Item_func_min_max, Item_func_rand, Item_func_round to functions directory |
60 |
hybrid_type= REAL_RESULT; |
61 |
return; |
|
62 |
}
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
63 |
|
492.3.13
by Lee
code clean move Item_func_floor, Item_func_length, Item_func_min_max, Item_func_rand, Item_func_round to functions directory |
64 |
switch (args[0]->result_type()) { |
65 |
case REAL_RESULT: |
|
66 |
case STRING_RESULT: |
|
67 |
hybrid_type= REAL_RESULT; |
|
1067.4.2
by Nathan Williams
All files in drizzled/function/ now use std::min instead of cmin. |
68 |
decimals= min(decimals_to_set, (int)NOT_FIXED_DEC); |
492.3.13
by Lee
code clean move Item_func_floor, Item_func_length, Item_func_min_max, Item_func_rand, Item_func_round to functions directory |
69 |
max_length= float_length(decimals); |
70 |
break; |
|
71 |
case INT_RESULT: |
|
72 |
if ((!decimals_to_set && truncate) || (args[0]->decimal_precision() < DECIMAL_LONGLONG_DIGITS)) |
|
73 |
{
|
|
74 |
int length_can_increase= test(!truncate && (val1 < 0) && !val1_unsigned); |
|
75 |
max_length= args[0]->max_length + length_can_increase; |
|
76 |
/* Here we can keep INT_RESULT */
|
|
77 |
hybrid_type= INT_RESULT; |
|
78 |
decimals= 0; |
|
79 |
break; |
|
80 |
}
|
|
81 |
/* fall through */
|
|
82 |
case DECIMAL_RESULT: |
|
83 |
{
|
|
84 |
hybrid_type= DECIMAL_RESULT; |
|
1067.4.2
by Nathan Williams
All files in drizzled/function/ now use std::min instead of cmin. |
85 |
decimals_to_set= min(DECIMAL_MAX_SCALE, decimals_to_set); |
492.3.13
by Lee
code clean move Item_func_floor, Item_func_length, Item_func_min_max, Item_func_rand, Item_func_round to functions directory |
86 |
int decimals_delta= args[0]->decimals - decimals_to_set; |
87 |
int precision= args[0]->decimal_precision(); |
|
88 |
int length_increase= ((decimals_delta <= 0) || truncate) ? 0:1; |
|
89 |
||
90 |
precision-= decimals_delta - length_increase; |
|
1067.4.2
by Nathan Williams
All files in drizzled/function/ now use std::min instead of cmin. |
91 |
decimals= min(decimals_to_set, DECIMAL_MAX_SCALE); |
492.3.13
by Lee
code clean move Item_func_floor, Item_func_length, Item_func_min_max, Item_func_rand, Item_func_round to functions directory |
92 |
max_length= my_decimal_precision_to_length(precision, decimals, |
93 |
unsigned_flag); |
|
94 |
break; |
|
95 |
}
|
|
96 |
default: |
|
97 |
assert(0); /* This result type isn't handled */ |
|
98 |
}
|
|
99 |
}
|
|
100 |
||
101 |
double my_double_round(double value, int64_t dec, bool dec_unsigned, |
|
102 |
bool truncate) |
|
103 |
{
|
|
104 |
double tmp; |
|
105 |
bool dec_negative= (dec < 0) && !dec_unsigned; |
|
106 |
uint64_t abs_dec= dec_negative ? -dec : dec; |
|
107 |
/*
|
|
108 |
tmp2 is here to avoid return the value with 80 bit precision
|
|
109 |
This will fix that the test round(0.1,1) = round(0.1,1) is true
|
|
110 |
*/
|
|
869.1.16
by Stewart Smith
fix func_math on x86 32bit. |
111 |
double tmp2; |
492.3.13
by Lee
code clean move Item_func_floor, Item_func_length, Item_func_min_max, Item_func_rand, Item_func_round to functions directory |
112 |
|
113 |
tmp=(abs_dec < array_elements(log_10) ? |
|
114 |
log_10[abs_dec] : pow(10.0,(double) abs_dec)); |
|
115 |
||
869.1.16
by Stewart Smith
fix func_math on x86 32bit. |
116 |
double value_times_tmp= value * tmp; |
117 |
||
118 |
/*
|
|
119 |
NOTE: This is a workaround for a gcc 4.3 bug on Intel x86 32bit
|
|
120 |
See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39228
|
|
121 |
See http://bugs.mysql.com/bug.php?id=42965
|
|
122 |
||
123 |
This forces the compiler to store/load the value as 64bit and avoids
|
|
919.2.9
by Monty Taylor
Replaced C99 isinf() with C++ numeric_traits<>::infinity() |
124 |
an optimisation that *could* have the infinite check be done on the 80bit
|
869.1.16
by Stewart Smith
fix func_math on x86 32bit. |
125 |
representation.
|
126 |
*/
|
|
127 |
if(sizeof(double) < sizeof(double_t)) |
|
128 |
{
|
|
129 |
volatile double t= value_times_tmp; |
|
130 |
value_times_tmp= t; |
|
131 |
}
|
|
132 |
||
919.2.9
by Monty Taylor
Replaced C99 isinf() with C++ numeric_traits<>::infinity() |
133 |
double infinity= numeric_limits<double>::infinity(); |
134 |
if (dec_negative && (tmp == infinity)) |
|
492.3.13
by Lee
code clean move Item_func_floor, Item_func_length, Item_func_min_max, Item_func_rand, Item_func_round to functions directory |
135 |
tmp2= 0; |
919.2.9
by Monty Taylor
Replaced C99 isinf() with C++ numeric_traits<>::infinity() |
136 |
else if (!dec_negative && (value_times_tmp == infinity)) |
492.3.13
by Lee
code clean move Item_func_floor, Item_func_length, Item_func_min_max, Item_func_rand, Item_func_round to functions directory |
137 |
tmp2= value; |
138 |
else if (truncate) |
|
139 |
{
|
|
140 |
if (value >= 0) |
|
141 |
tmp2= dec < 0 ? floor(value/tmp)*tmp : floor(value*tmp)/tmp; |
|
142 |
else
|
|
143 |
tmp2= dec < 0 ? ceil(value/tmp)*tmp : ceil(value*tmp)/tmp; |
|
144 |
}
|
|
145 |
else
|
|
146 |
tmp2=dec < 0 ? rint(value/tmp)*tmp : rint(value*tmp)/tmp; |
|
147 |
return tmp2; |
|
148 |
}
|
|
149 |
||
150 |
||
151 |
double Item_func_round::real_op() |
|
152 |
{
|
|
153 |
double value= args[0]->val_real(); |
|
154 |
||
155 |
if (!(null_value= args[0]->null_value || args[1]->null_value)) |
|
156 |
return my_double_round(value, args[1]->val_int(), args[1]->unsigned_flag, |
|
157 |
truncate); |
|
158 |
||
159 |
return 0.0; |
|
160 |
}
|
|
161 |
||
162 |
/*
|
|
163 |
Rounds a given value to a power of 10 specified as the 'to' argument,
|
|
164 |
avoiding overflows when the value is close to the uint64_t range boundary.
|
|
165 |
*/
|
|
166 |
||
167 |
static inline uint64_t my_unsigned_round(uint64_t value, uint64_t to) |
|
168 |
{
|
|
169 |
uint64_t tmp= value / to * to; |
|
170 |
return (value - tmp < (to >> 1)) ? tmp : tmp + to; |
|
171 |
}
|
|
172 |
||
173 |
||
174 |
int64_t Item_func_round::int_op() |
|
175 |
{
|
|
176 |
int64_t value= args[0]->val_int(); |
|
177 |
int64_t dec= args[1]->val_int(); |
|
178 |
decimals= 0; |
|
179 |
uint64_t abs_dec; |
|
180 |
if ((null_value= args[0]->null_value || args[1]->null_value)) |
|
181 |
return 0; |
|
182 |
if ((dec >= 0) || args[1]->unsigned_flag) |
|
183 |
return value; // integer have not digits after point |
|
184 |
||
185 |
abs_dec= -dec; |
|
186 |
int64_t tmp; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
187 |
|
492.3.13
by Lee
code clean move Item_func_floor, Item_func_length, Item_func_min_max, Item_func_rand, Item_func_round to functions directory |
188 |
if(abs_dec >= array_elements(log_10_int)) |
189 |
return 0; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
190 |
|
492.3.13
by Lee
code clean move Item_func_floor, Item_func_length, Item_func_min_max, Item_func_rand, Item_func_round to functions directory |
191 |
tmp= log_10_int[abs_dec]; |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
192 |
|
492.3.13
by Lee
code clean move Item_func_floor, Item_func_length, Item_func_min_max, Item_func_rand, Item_func_round to functions directory |
193 |
if (truncate) |
194 |
value= (unsigned_flag) ? |
|
195 |
((uint64_t) value / tmp) * tmp : (value / tmp) * tmp; |
|
196 |
else
|
|
197 |
value= (unsigned_flag || value >= 0) ? |
|
198 |
my_unsigned_round((uint64_t) value, tmp) : |
|
199 |
-(int64_t) my_unsigned_round((uint64_t) -value, tmp); |
|
200 |
return value; |
|
201 |
}
|
|
202 |
||
203 |
||
204 |
my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value) |
|
205 |
{
|
|
206 |
my_decimal val, *value= args[0]->val_decimal(&val); |
|
207 |
int64_t dec= args[1]->val_int(); |
|
1067.4.2
by Nathan Williams
All files in drizzled/function/ now use std::min instead of cmin. |
208 |
|
492.3.13
by Lee
code clean move Item_func_floor, Item_func_length, Item_func_min_max, Item_func_rand, Item_func_round to functions directory |
209 |
if (dec >= 0 || args[1]->unsigned_flag) |
1067.4.2
by Nathan Williams
All files in drizzled/function/ now use std::min instead of cmin. |
210 |
dec= min(dec, (int64_t) decimals); |
492.3.13
by Lee
code clean move Item_func_floor, Item_func_length, Item_func_min_max, Item_func_rand, Item_func_round to functions directory |
211 |
else if (dec < INT_MIN) |
212 |
dec= INT_MIN; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
213 |
|
492.3.13
by Lee
code clean move Item_func_floor, Item_func_length, Item_func_min_max, Item_func_rand, Item_func_round to functions directory |
214 |
if (!(null_value= (args[0]->null_value || args[1]->null_value || |
215 |
my_decimal_round(E_DEC_FATAL_ERROR, value, (int) dec, |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
216 |
truncate, decimal_value) > 1))) |
492.3.13
by Lee
code clean move Item_func_floor, Item_func_length, Item_func_min_max, Item_func_rand, Item_func_round to functions directory |
217 |
{
|
218 |
decimal_value->frac= decimals; |
|
219 |
return decimal_value; |
|
220 |
}
|
|
221 |
return 0; |
|
222 |
}
|
|
223 |