KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > smallsql > database > MutableNumeric


1 /* =============================================================
2  * SmallSQL : a free Java DBMS library for the Java(tm) platform
3  * =============================================================
4  *
5  * (C) Copyright 2004-2006, by Volker Berlin.
6  *
7  * Project Info: http://www.smallsql.de/
8  *
9  * This library is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17  * License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22  * USA.
23  *
24  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
25  * in the United States and other countries.]
26  *
27  * ---------------
28  * MutableNumeric.java
29  * ---------------
30  * Author: Volker Berlin
31  *
32  */

33 package smallsql.database;
34
35 import java.math.*;
36
37 class MutableNumeric extends Number JavaDoc implements Mutable{
38
39     private static final long serialVersionUID = -750525164208565056L;
40     private int[] value;
41     private int scale;
42     private int signum;
43
44     
45     /**
46      * The most significant value is on position 0.
47      */

48     MutableNumeric(byte[] complement){
49         setValue(complement);
50     }
51     
52     private void setValue(byte[] complement){
53         int length = complement.length;
54         if(length == 0){
55             value = EMPTY_INTS;
56             signum = 0;
57             return;
58         }
59         value = new int[ (length + 3) / 4 ];
60         if(complement[0] < 0){
61             negate( complement );
62             signum = -1;
63         }else{
64             signum = 0;
65             for(int i=0; i<complement.length; i++)
66                 if(complement[i] != 0){
67                     signum = 1;
68                     break;
69                 }
70         }
71         for(int v=value.length-1; v>=0; v--){
72             int temp = 0;
73             for(int i=0; i<4 && 0<length; i++){
74                 temp |= (complement[ --length ] & 0xFF) << (i*8);
75             }
76             value[v] = temp;
77         }
78     }
79
80     MutableNumeric(int complement){
81         if(complement == 0){
82             signum = 0;
83             value = EMPTY_INTS;
84         }else{
85             value = new int[1];
86             if(complement < 0){
87                 value[0] = -complement;
88                 signum = -1;
89             }else{
90                 value[0] = complement;
91                 signum = 1;
92             }
93         }
94     }
95
96     MutableNumeric(int complement, int scale){
97         this( complement );
98         this.scale = scale;
99     }
100
101     MutableNumeric(long complement){
102         if(complement == 0){
103             signum = 0;
104             value = EMPTY_INTS;
105         }else{
106             value = new int[2];
107             if(complement < 0){
108                 value[0] = (int)(~(complement >> 32));
109                 value[1] = (int)(-complement);
110                 signum = -1;
111             }else{
112                 value[0] = (int)(complement >> 32);
113                 value[1] = (int)complement;
114                 signum = 1;
115             }
116         }
117     }
118
119     MutableNumeric(long complement, int scale){
120         this( complement );
121         this.scale = scale;
122     }
123
124     MutableNumeric(double val){
125         //first convert it to a string, because double to BigDecimal has very large rounding bug
126
this( new BigDecimal( String.valueOf(val) ) );
127     }
128
129     MutableNumeric(float val){
130         //first convert it to a string, because float to BigDecimal has very large rounding bug
131
this( new BigDecimal( String.valueOf(val) ) );
132     }
133
134     MutableNumeric(String JavaDoc val){
135         this( new BigDecimal( val ) );
136     }
137
138     MutableNumeric( BigDecimal big ){
139         this(big.unscaledValue().toByteArray() );
140         scale = big.scale();
141     }
142
143     MutableNumeric(int signum, int[] value, int scale){
144         this.signum = signum;
145         this.value = value;
146         this.scale = scale;
147     }
148     
149     MutableNumeric(MutableNumeric numeric){
150         this.signum = numeric.signum;
151         this.value = new int[numeric.value.length];
152         System.arraycopy(numeric.value, 0, value, 0, value.length);
153         this.scale = numeric.scale;
154     }
155     
156     
157     int[] getInternalValue(){
158         return value;
159     }
160     
161
162     // Addiert den Wert zum aktuellen MutableNumeric Object und verändert es.
163
void add(MutableNumeric num){
164         if(num.scale < scale){
165             num.setScale(scale);
166         }else
167         if(num.scale > scale){
168             setScale(num.scale);
169         }
170         add( num.signum, num.value );
171     }
172     
173
174     private void add( int sig2, int[] val2){
175         if(val2.length > value.length){
176             int[] temp = val2;
177             val2 = value;
178             value = temp;
179             int tempi = signum;
180             signum = sig2;
181             sig2 = tempi;
182         }
183         if(signum != sig2)
184             sub(val2);
185         else
186             add(val2);
187     }
188
189     // val2 ist kürzer oder gleich lang wie value
190
// die signum werte habe beide das gleiche Vorzeichen
191
private void add( int[] val2){
192         long temp = 0;
193         int v1 = value.length;
194         for(int v2 = val2.length; v2>0; ){
195             temp = (value[--v1] & 0xFFFFFFFFL) + (val2 [--v2] & 0xFFFFFFFFL) + (temp >>> 32);
196             value[v1] = (int)temp;
197         }
198         boolean uebertrag = (temp >>> 32) != 0;
199         while(v1 > 0 && uebertrag)
200             uebertrag = (value[--v1] = value[v1] + 1) == 0;
201
202         // vergrößern, wenn notwendig
203
if(uebertrag){
204             resizeValue(1);
205         }
206     }
207     
208     
209     
210     /**
211      * Resize the value mantisse with a carryover.
212      * @param highBits Is the high value that is save on the resize place.
213      */

214     private void resizeValue(int highBits){
215         int val[] = new int[value.length+1];
216         val[0] = highBits;
217         System.arraycopy(value, 0, val, 1, value.length);
218         value = val;
219     }
220      
221     
222     // Subtrahiert den Wert zum aktuellen MutableNumeric Object und verändert es.
223
void sub(MutableNumeric num){
224         if(num.scale < scale){
225             num.setScale(scale);
226         }else
227         if(num.scale > scale){
228             setScale(num.scale);
229         }
230         add( -num.signum, num.value );
231     }
232
233     // val2 ist kürzer oder gleich lang wie value
234
// val2 wird von der aktuellen Zahl abgezogen
235
private void sub(int[] val2){
236         long temp = 0;
237         int v1 = value.length;
238         for(int v2 = val2.length; v2>0; ){
239             temp = (value[--v1] & 0xFFFFFFFFL) - (val2 [--v2] & 0xFFFFFFFFL) + (temp >>>= 32);
240             value[v1] = (int)temp;
241         }
242
243         boolean uebertrag = (temp >>> 32) != 0;
244         while(v1 > 0 && uebertrag)
245             uebertrag = (value[--v1] = value[v1] - 1) == -1;
246
247         if(uebertrag){
248             signum = -signum;
249             int last = value.length-1;
250             for(int i=0; i<=last; i++){
251                 value[i] = (i == last) ? -value[i] : ~value[i];
252             }
253         }
254     }
255
256     void mul(MutableNumeric num){
257         //TODO performance
258
BigDecimal big = toBigDecimal().multiply(num.toBigDecimal() );
259         setValue( big.unscaledValue().toByteArray() );
260         scale = big.scale();
261         signum = big.signum();
262     }
263
264     final void mul(int factor){
265         if(factor < 0){
266             factor = - factor;
267             signum = -signum;
268         }
269         long carryover = 0;
270         for(int i = value.length-1; i>=0; i--){
271             long v = (value[i] & 0xFFFFFFFFL) * factor + carryover;
272             value[i] = (int)v;
273             carryover = v >> 32;
274         }
275         if(carryover > 0){
276             resizeValue( (int)carryover );
277         }
278     }
279     
280
281     void div(MutableNumeric num){
282         //TODO performance
283
int newScale = Math.max(scale+5, num.scale +4);
284         BigDecimal big = toBigDecimal().divide(num.toBigDecimal(), newScale, BigDecimal.ROUND_HALF_EVEN);
285         setValue( big.unscaledValue().toByteArray() );
286         scale = big.scale();
287         signum = big.signum();
288     }
289     
290
291     final void div(int quotient){
292         //increment the scale with 5
293
mul(100000);
294         scale += 5;
295         
296         divImpl(quotient);
297     }
298     
299     
300     final private void divImpl(int quotient){
301         if(quotient == 1) return;
302         if(quotient < 0){
303             quotient = - quotient;
304             signum = -signum;
305         }
306         int valueLength = value.length;
307         long carryover = 0;
308         for(int i = 0; i<valueLength; i++){
309             long v = (value[i] & 0xFFFFFFFFL) + carryover;
310             value[i] = (int)(v / quotient);
311             carryover = ((v % quotient) << 32);
312         }
313         carryover /= quotient;
314         if(carryover > 2147483648L || //2147483648L == Integer.MAX_VALUE+1
315
(carryover == 2147483648L && (value[valueLength-1] % 2 == 1))){
316             int i = valueLength-1;
317             boolean isCarryOver = true;
318             while(i >= 0 && isCarryOver)
319                 isCarryOver = (value[i--] += 1) == 0;
320         }
321         if(valueLength>1 && value[0] == 0){
322             int[] temp = new int[valueLength-1];
323             System.arraycopy(value, 1, temp, 0, valueLength-1);
324             value = temp;
325         }
326             
327     }
328     
329     
330     void mod(MutableNumeric num){
331         //TODO performance
332
num = new MutableNumeric( doubleValue() % num.doubleValue() );
333         value = num.value;
334         scale = num.scale;
335         signum = num.signum;
336     }
337
338
339     int getScale(){
340         return scale;
341     }
342     
343     
344     void setScale(int newScale){
345         if(newScale == scale) return;
346         int factor = 1;
347         if(newScale > scale){
348             for(;newScale>scale; scale++){
349                 factor *=10;
350                 if(factor == 1000000000){
351                     mul(factor);
352                     factor = 1;
353                 }
354             }
355             mul(factor);
356         }else{
357             for(;newScale<scale; scale--){
358                 factor *=10;
359                 if(factor == 1000000000){
360                     divImpl(factor);
361                     factor = 1;
362                 }
363             }
364             divImpl(factor);
365         }
366     }
367     
368     
369     
370
371     /**
372      * @return Returns the signum.
373      */

374     int getSignum() {
375         return signum;
376     }
377     
378     
379     void setSignum(int signum){
380         this.signum = signum;
381     }
382     
383
384     void floor(){
385         //TODO performance
386
int oldScale = scale;
387         setScale(0);
388         setScale(oldScale);
389     }
390     
391
392     private void negate(byte[] complement){
393         int last = complement.length-1;
394         for(int i=0; i<=last; i++){
395             complement[i] = (byte)( (i == last) ? -complement[i] : ~complement[i]);
396         }
397     }
398
399     
400     /**
401      * Convert this number in a 2 complement that can be used from BigInteger.
402      * The length is ever a multiple of 4
403      * @return the 2 complement of this object
404      */

405     byte[] toByteArray(){
406         if(signum == 0) return EMPTY_BYTES;
407         byte[] complement;
408         int offset;
409
410         int v = 0;
411         while(v < value.length && value[v] == 0) v++;
412         if (v == value.length) return EMPTY_BYTES;
413
414         if(value[v] < 0){
415             // If the highest bit is set then it must resize
416
// because this bit is needed for the signum
417
complement = new byte[(value.length-v)*4 + 4];
418             if(signum < 0)
419                 complement[0] = complement[1] = complement[2] = complement[3] = -1;
420             offset = 4;
421         }else{
422             complement = new byte[(value.length-v)*4];
423             offset = 0;
424         }
425         int last = value.length-1;
426         for(; v <= last; v++){
427             int val = (signum>0) ? value[v] : (v == last) ? -value[v] : ~value[v];
428             complement[offset++] = (byte)(val >> 24);
429             complement[offset++] = (byte)(val >> 16);
430             complement[offset++] = (byte)(val >> 8);
431             complement[offset++] = (byte)(val);
432         }
433         return complement;
434     }
435
436     public int intValue(){
437         return Utils.long2int(longValue());
438     }
439     
440
441     public long longValue(){
442         if(value.length == 0 || signum == 0){
443             return 0;
444         }else{
445             if (value.length == 1 && (value[0] > 0)){
446                 // einfacher Integer Wert
447
return Utils.double2long(value[0] / scaleDoubleFactor[scale] * signum);
448             }else
449             if (value.length == 1){
450                 // überlaufender Integer Wert
451
long temp = value[0] & 0xFFFFFFFFL;
452                 return Utils.double2long(temp / scaleDoubleFactor[scale] * signum);
453             }else
454             if (value.length == 2 && (value[0] > 0)){
455                 // einfacher Long Wert
456
long temp = (((long)value[0]) << 32) | (value[1] & 0xFFFFFFFFL);
457                 return Utils.double2long(temp / scaleDoubleFactor[scale] * signum);
458             }else{
459                 if(scale != 0){
460                     MutableNumeric numeric = new MutableNumeric(this);
461                     numeric.setScale(0);
462                     return numeric.longValue();
463                 }
464                 return (signum > 0) ? Long.MAX_VALUE : Long.MIN_VALUE;
465             }
466         }
467     }
468     
469
470     public float floatValue(){
471         if(value.length == 0 || signum == 0){
472             return 0;
473         }else{
474             if (value.length == 1 && (value[0] > 0)){
475                 // einfacher Integer Wert
476
return value[0] / scaleFloatFactor[scale] * signum;
477             }else
478             if (value.length == 1){
479                 // überlaufender Integer Wert
480
long temp = value[0] & 0xFFFFFFFFL;
481                 return temp / scaleFloatFactor[scale] * signum;
482             }else
483             if (value.length == 2 && (value[0] > 0)){
484                 // einfacher Long Wert
485
long temp = (((long)value[0]) << 32) | (value[1] & 0xFFFFFFFFL);
486                 return temp / scaleFloatFactor[scale] * signum;
487             }else{
488                 return new BigDecimal( new BigInteger( toByteArray() ), scale ).floatValue();
489             }
490         }
491     }
492
493     public double doubleValue(){
494         if(value.length == 0 || signum == 0){
495             return 0;
496         }else{
497             if (value.length == 1 && (value[0] > 0)){
498                 // einfacher Integer Wert
499
return value[0] / scaleDoubleFactor[scale] * signum;
500             }else
501             if (value.length == 1){
502                 // überlaufender Integer Wert
503
long temp = value[0] & 0xFFFFFFFFL;
504                 return temp / scaleDoubleFactor[scale] * signum;
505             }else
506             if (value.length == 2 && (value[0] > 0)){
507                 // einfacher Long Wert
508
long temp = (((long)value[0]) << 32) | (value[1] & 0xFFFFFFFFL);
509                 return temp / scaleDoubleFactor[scale] * signum;
510             }else{
511                 return new BigDecimal( new BigInteger( toByteArray() ), scale ).doubleValue();
512             }
513         }
514     }
515
516     public String JavaDoc toString(){
517         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
518         if(value.length == 0 || signum == 0){
519             buf.append( '0' );
520         }else{
521             if (value.length == 1 && (value[0] > 0)){
522                 // einfacher Integer Wert
523
buf.append( Integer.toString(value[0]) );
524             }else
525             if (value.length == 1){
526                 // überlaufender Integer Wert
527
long temp = value[0] & 0xFFFFFFFFL;
528                 buf.append( Long.toString( temp ) );
529             }else
530             if (value.length == 2 && (value[0] > 0)){
531                 // einfacher Long Wert
532
long temp = (((long)value[0]) << 32) | (value[1] & 0xFFFFFFFFL);
533                 buf.append( Long.toString( temp ) );
534             }else{
535                 return new BigDecimal( new BigInteger( toByteArray() ), scale ).toString();
536             }
537         }
538         if(scale > 0){
539             while(buf.length() <= scale) buf.insert( 0, '0' );
540             buf.insert( buf.length() - scale, '.' );
541         }
542         if (signum < 0) buf.insert( 0, '-');
543         return buf.toString();
544     }
545     
546     public int compareTo(MutableNumeric numeric){
547         //TODO performance
548
return toBigDecimal().compareTo(numeric.toBigDecimal());
549     }
550
551     public boolean equals(Object JavaDoc obj){
552         if(!(obj instanceof MutableNumeric)) return false;
553         return compareTo((MutableNumeric)obj) == 0;
554     }
555     
556     public BigDecimal toBigDecimal(){
557         if(signum == 0) return new BigDecimal( BigInteger.ZERO, scale);
558         return new BigDecimal( new BigInteger( toByteArray() ), scale );
559     }
560
561     public BigDecimal toBigDecimal(int scale){
562         if(scale == this.scale) return toBigDecimal();
563         return toBigDecimal().setScale( scale, BigDecimal.ROUND_HALF_EVEN);
564     }
565
566     public Object JavaDoc getImmutableObject(){
567         return toBigDecimal();
568     }
569     
570
571     private static final byte[] EMPTY_BYTES = new byte[0];
572     private static final int [] EMPTY_INTS = new int [0];
573     private static final double[] scaleDoubleFactor = { 1, 10, 100, 1000, 10000, 100000, 1000000 };
574     private static final float[] scaleFloatFactor = { 1, 10, 100, 1000, 10000, 100000, 1000000 };
575 }
Popular Tags