~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/function/math/round.cc

  • Committer: Brian Aker
  • Date: 2010-01-27 18:58:12 UTC
  • Revision ID: brian@gaz-20100127185812-n62n0vwetnx8jrjy
Remove dead code.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "config.h"
 
21
 
 
22
#include <math.h>
 
23
#include <limits.h>
 
24
 
 
25
#include <limits>
 
26
#include <algorithm>
 
27
 
 
28
#include "drizzled/function/math/round.h"
 
29
 
 
30
extern const double log_10[309];
 
31
 
 
32
 
 
33
using namespace std;
 
34
 
 
35
void Item_func_round::fix_length_and_dec()
 
36
{
 
37
  int      decimals_to_set;
 
38
  int64_t val1;
 
39
  bool     val1_unsigned;
 
40
 
 
41
  unsigned_flag= args[0]->unsigned_flag;
 
42
  if (!args[1]->const_item())
 
43
  {
 
44
    max_length= args[0]->max_length;
 
45
    decimals= args[0]->decimals;
 
46
    if (args[0]->result_type() == DECIMAL_RESULT)
 
47
    {
 
48
      max_length++;
 
49
      hybrid_type= DECIMAL_RESULT;
 
50
    }
 
51
    else
 
52
      hybrid_type= REAL_RESULT;
 
53
    return;
 
54
  }
 
55
 
 
56
  val1= args[1]->val_int();
 
57
  val1_unsigned= args[1]->unsigned_flag;
 
58
  if (val1 < 0)
 
59
    decimals_to_set= val1_unsigned ? INT_MAX : 0;
 
60
  else
 
61
    decimals_to_set= (val1 > INT_MAX) ? INT_MAX : (int) val1;
 
62
 
 
63
  if (args[0]->decimals == NOT_FIXED_DEC)
 
64
  {
 
65
    max_length= args[0]->max_length;
 
66
    decimals= min(decimals_to_set, (int)NOT_FIXED_DEC);
 
67
    hybrid_type= REAL_RESULT;
 
68
    return;
 
69
  }
 
70
 
 
71
  switch (args[0]->result_type()) {
 
72
  case REAL_RESULT:
 
73
  case STRING_RESULT:
 
74
    hybrid_type= REAL_RESULT;
 
75
    decimals= min(decimals_to_set, (int)NOT_FIXED_DEC);
 
76
    max_length= float_length(decimals);
 
77
    break;
 
78
  case INT_RESULT:
 
79
    if ((!decimals_to_set && truncate) || (args[0]->decimal_precision() < DECIMAL_LONGLONG_DIGITS))
 
80
    {
 
81
      int length_can_increase= test(!truncate && (val1 < 0) && !val1_unsigned);
 
82
      max_length= args[0]->max_length + length_can_increase;
 
83
      /* Here we can keep INT_RESULT */
 
84
      hybrid_type= INT_RESULT;
 
85
      decimals= 0;
 
86
      break;
 
87
    }
 
88
    /* fall through */
 
89
  case DECIMAL_RESULT:
 
90
  {
 
91
    hybrid_type= DECIMAL_RESULT;
 
92
    decimals_to_set= min(DECIMAL_MAX_SCALE, decimals_to_set);
 
93
    int decimals_delta= args[0]->decimals - decimals_to_set;
 
94
    int precision= args[0]->decimal_precision();
 
95
    int length_increase= ((decimals_delta <= 0) || truncate) ? 0:1;
 
96
 
 
97
    precision-= decimals_delta - length_increase;
 
98
    decimals= min(decimals_to_set, DECIMAL_MAX_SCALE);
 
99
    max_length= my_decimal_precision_to_length(precision, decimals,
 
100
                                               unsigned_flag);
 
101
    break;
 
102
  }
 
103
  default:
 
104
    assert(0); /* This result type isn't handled */
 
105
  }
 
106
}
 
107
 
 
108
double my_double_round(double value, int64_t dec, bool dec_unsigned,
 
109
                       bool truncate)
 
110
{
 
111
  double tmp;
 
112
  bool dec_negative= (dec < 0) && !dec_unsigned;
 
113
  uint64_t abs_dec= dec_negative ? -dec : dec;
 
114
  /*
 
115
    tmp2 is here to avoid return the value with 80 bit precision
 
116
    This will fix that the test round(0.1,1) = round(0.1,1) is true
 
117
  */
 
118
  double tmp2;
 
119
 
 
120
  tmp=(abs_dec < array_elements(log_10) ?
 
121
       log_10[abs_dec] : pow(10.0,(double) abs_dec));
 
122
 
 
123
  double value_times_tmp= value * tmp;
 
124
 
 
125
  /*
 
126
    NOTE: This is a workaround for a gcc 4.3 bug on Intel x86 32bit
 
127
    See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39228
 
128
    See http://bugs.mysql.com/bug.php?id=42965
 
129
 
 
130
    This forces the compiler to store/load the value as 64bit and avoids
 
131
    an optimisation that *could* have the infinite check be done on the 80bit
 
132
    representation.
 
133
   */
 
134
  if(sizeof(double) < sizeof(double_t))
 
135
  {
 
136
    volatile double t= value_times_tmp;
 
137
    value_times_tmp= t;
 
138
  }
 
139
 
 
140
  double infinity= numeric_limits<double>::infinity();
 
141
  if (dec_negative && (tmp == infinity))
 
142
    tmp2= 0;
 
143
  else if (!dec_negative && (value_times_tmp == infinity))
 
144
    tmp2= value;
 
145
  else if (truncate)
 
146
  {
 
147
    if (value >= 0)
 
148
      tmp2= dec < 0 ? floor(value/tmp)*tmp : floor(value*tmp)/tmp;
 
149
    else
 
150
      tmp2= dec < 0 ? ceil(value/tmp)*tmp : ceil(value*tmp)/tmp;
 
151
  }
 
152
  else
 
153
    tmp2=dec < 0 ? rint(value/tmp)*tmp : rint(value*tmp)/tmp;
 
154
  return tmp2;
 
155
}
 
156
 
 
157
 
 
158
double Item_func_round::real_op()
 
159
{
 
160
  double value= args[0]->val_real();
 
161
 
 
162
  if (!(null_value= args[0]->null_value || args[1]->null_value))
 
163
    return my_double_round(value, args[1]->val_int(), args[1]->unsigned_flag,
 
164
                           truncate);
 
165
 
 
166
  return 0.0;
 
167
}
 
168
 
 
169
/*
 
170
  Rounds a given value to a power of 10 specified as the 'to' argument,
 
171
  avoiding overflows when the value is close to the uint64_t range boundary.
 
172
*/
 
173
 
 
174
static inline uint64_t my_unsigned_round(uint64_t value, uint64_t to)
 
175
{
 
176
  uint64_t tmp= value / to * to;
 
177
  return (value - tmp < (to >> 1)) ? tmp : tmp + to;
 
178
}
 
179
 
 
180
 
 
181
int64_t Item_func_round::int_op()
 
182
{
 
183
  int64_t value= args[0]->val_int();
 
184
  int64_t dec= args[1]->val_int();
 
185
  decimals= 0;
 
186
  uint64_t abs_dec;
 
187
  if ((null_value= args[0]->null_value || args[1]->null_value))
 
188
    return 0;
 
189
  if ((dec >= 0) || args[1]->unsigned_flag)
 
190
    return value; // integer have not digits after point
 
191
 
 
192
  abs_dec= -dec;
 
193
  int64_t tmp;
 
194
 
 
195
  if(abs_dec >= array_elements(log_10_int))
 
196
    return 0;
 
197
 
 
198
  tmp= log_10_int[abs_dec];
 
199
 
 
200
  if (truncate)
 
201
    value= (unsigned_flag) ?
 
202
      ((uint64_t) value / tmp) * tmp : (value / tmp) * tmp;
 
203
  else
 
204
    value= (unsigned_flag || value >= 0) ?
 
205
      my_unsigned_round((uint64_t) value, tmp) :
 
206
      -(int64_t) my_unsigned_round((uint64_t) -value, tmp);
 
207
  return value;
 
208
}
 
209
 
 
210
 
 
211
my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value)
 
212
{
 
213
  my_decimal val, *value= args[0]->val_decimal(&val);
 
214
  int64_t dec= args[1]->val_int();
 
215
 
 
216
  if (dec >= 0 || args[1]->unsigned_flag)
 
217
    dec= min(dec, (int64_t) decimals);
 
218
  else if (dec < INT_MIN)
 
219
    dec= INT_MIN;
 
220
 
 
221
  if (!(null_value= (args[0]->null_value || args[1]->null_value ||
 
222
                     my_decimal_round(E_DEC_FATAL_ERROR, value, (int) dec,
 
223
                                      truncate, decimal_value) > 1)))
 
224
  {
 
225
    decimal_value->frac= decimals;
 
226
    return decimal_value;
 
227
  }
 
228
  return 0;
 
229
}
 
230