EMMA Coverage Report (generated Wed Jun 28 19:54:35 CEST 2006)
[all classes][smallsql.database]

COVERAGE SUMMARY FOR SOURCE FILE [MutableNumeric.java]

nameclass, %method, %block, %line, %
MutableNumeric.java100% (1/1)90%  (35/39)76%  (1295/1697)78%  (225,2/290)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class MutableNumeric100% (1/1)90%  (35/39)76%  (1295/1697)78%  (225,2/290)
equals (Object): boolean 0%   (0/1)0%   (0/14)0%   (0/2)
floor (): void 0%   (0/1)0%   (0/10)0%   (0/4)
mod (MutableNumeric): void 0%   (0/1)0%   (0/22)0%   (0/5)
resizeValue (int): void 0%   (0/1)0%   (0/24)0%   (0/5)
sub (int []): void 100% (1/1)48%  (55/114)61%  (8,5/14)
add (int, int []): void 100% (1/1)53%  (18/34)45%  (5/11)
longValue (): long 100% (1/1)65%  (79/121)53%  (8/15)
sub (MutableNumeric): void 100% (1/1)67%  (18/27)67%  (4/6)
add (int []): void 100% (1/1)69%  (53/77)77%  (8,5/11)
toByteArray (): byte [] 100% (1/1)70%  (99/142)75%  (14,2/19)
doubleValue (): double 100% (1/1)71%  (77/109)73%  (8/11)
floatValue (): float 100% (1/1)71%  (77/109)73%  (8/11)
mul (int): void 100% (1/1)78%  (42/54)73%  (8/11)
toString (): String 100% (1/1)80%  (106/132)82%  (14/17)
divImpl (int): void 100% (1/1)84%  (108/128)87%  (19,1/22)
add (MutableNumeric): void 100% (1/1)85%  (22/26)83%  (5/6)
setScale (int): void 100% (1/1)91%  (59/65)87%  (13,9/16)
setValue (byte []): void 100% (1/1)92%  (83/90)85%  (17/20)
<static initializer> 100% (1/1)100% (69/69)100% (5/5)
MutableNumeric (BigDecimal): void 100% (1/1)100% (10/10)100% (3/3)
MutableNumeric (MutableNumeric): void 100% (1/1)100% (27/27)100% (6/6)
MutableNumeric (String): void 100% (1/1)100% (7/7)100% (2/2)
MutableNumeric (byte []): void 100% (1/1)100% (6/6)100% (3/3)
MutableNumeric (double): void 100% (1/1)100% (8/8)100% (2/2)
MutableNumeric (float): void 100% (1/1)100% (8/8)100% (2/2)
MutableNumeric (int): void 100% (1/1)100% (36/36)100% (11/11)
MutableNumeric (int, int [], int): void 100% (1/1)100% (12/12)100% (5/5)
MutableNumeric (int, int): void 100% (1/1)100% (7/7)100% (3/3)
MutableNumeric (long): void 100% (1/1)100% (60/60)100% (13/13)
MutableNumeric (long, int): void 100% (1/1)100% (7/7)100% (3/3)
compareTo (MutableNumeric): int 100% (1/1)100% (6/6)100% (1/1)
div (MutableNumeric): void 100% (1/1)100% (32/32)100% (6/6)
div (int): void 100% (1/1)100% (13/13)100% (4/4)
getImmutableObject (): Object 100% (1/1)100% (3/3)100% (1/1)
intValue (): int 100% (1/1)100% (4/4)100% (1/1)
mul (MutableNumeric): void 100% (1/1)100% (20/20)100% (5/5)
negate (byte []): void 100% (1/1)100% (30/30)100% (4/4)
toBigDecimal (): BigDecimal 100% (1/1)100% (21/21)100% (2/2)
toBigDecimal (int): BigDecimal 100% (1/1)100% (13/13)100% (2/2)

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 */
33package smallsql.database;
34 
35import java.math.*;
36 
37public class MutableNumeric extends Number implements Mutable{
38 
39    int[] value;
40    int scale;
41    int signum;
42 
43    private int[] addIntVal; //array with the size of 1
44 
45    // most significat value ist an position 0
46    MutableNumeric(byte[] complement){
47                setValue(complement);
48    }
49    
50    private void setValue(byte[] complement){
51        int length = complement.length;
52        if(length == 0){
53            value   = EMPTY_INTS;
54            signum  = 0;
55            return;
56        }
57        value = new int[ (length + 3) / 4 ];
58        if(complement[0] < 0){
59            negate( complement );
60            signum = -1;
61        }else{
62                        signum = 0;
63                for(int i=0; i<complement.length; i++)
64                        if(complement[i] != 0){
65                                signum = 1;
66                                break;
67                        }
68        }
69        for(int v=value.length-1; v>=0; v--){
70            int temp = 0;
71            for(int i=0; i<4 && 0<length; i++){
72                temp |= (complement[ --length ] & 0xFF) << (i*8);
73            }
74            value[v] = temp;
75        }
76    }
77 
78    MutableNumeric(int complement){
79        if(complement == 0){
80            signum = 0;
81            value = EMPTY_INTS;
82        }else{
83            value = new int[1];
84            if(complement < 0){
85                value[0] = -complement;
86                signum = -1;
87            }else{
88                value[0] = complement;
89                signum = 1;
90            }
91        }
92    }
93 
94    MutableNumeric(int complement, int scale){
95        this( complement );
96        this.scale = scale;
97    }
98 
99    MutableNumeric(long complement){
100        if(complement == 0){
101            signum = 0;
102            value = EMPTY_INTS;
103        }else{
104            value = new int[2];
105            if(complement < 0){
106                value[0] = (int)(~(complement >> 32));
107                value[1] = (int)(-complement);
108                signum = -1;
109            }else{
110                value[0] = (int)(complement >> 32);
111                value[1] = (int)complement;
112                signum = 1;
113            }
114        }
115    }
116 
117    MutableNumeric(long complement, int scale){
118        this( complement );
119        this.scale = scale;
120    }
121 
122    MutableNumeric(double val){
123            //first convert it to a string, because double to BigDecimal has very large rounding bug
124        this( new BigDecimal( String.valueOf(val) ) );
125    }
126 
127    MutableNumeric(float val){
128        //first convert it to a string, because float to BigDecimal has very large rounding bug
129        this( new BigDecimal( String.valueOf(val) ) );
130    }
131 
132    MutableNumeric(String val){
133        this( new BigDecimal( val ) );
134    }
135 
136    MutableNumeric( BigDecimal big ){
137        this(big.unscaledValue().toByteArray() );
138        scale   = big.scale();
139    }
140 
141    MutableNumeric(int signum, int[] value, int scale){
142        this.signum = signum;
143        this.value  = value;
144        this.scale  = scale;
145    }
146    
147        MutableNumeric(MutableNumeric numeric){
148                this.signum = numeric.signum;
149                this.value  = new int[numeric.value.length];
150                System.arraycopy(numeric.value, 0, value, 0, value.length);
151                this.scale  = numeric.scale;
152        }
153        
154 
155    // Addiert den Wert zum aktuellen MutableNumeric Object und verändert es.
156    void add(MutableNumeric num){
157                if(num.scale < scale){
158                        num.setScale(scale);
159                }else
160                if(num.scale > scale){
161                        setScale(num.scale);
162                }
163        add( num.signum, num.value );
164    }
165        
166 
167    private void add( int sig2, int[] val2){
168        if(val2.length > value.length){
169            int[] temp = val2;
170            val2 = value;
171            value = temp;
172            int tempi = signum;
173            signum = sig2;
174            sig2 = tempi;
175        }
176        if(signum != sig2)
177            sub(val2);
178        else
179            add(val2);
180    }
181 
182    // val2 ist kürzer oder gleich lang wie value
183    // die signum werte habe beide das gleiche Vorzeichen
184    private void add( int[] val2){
185        long temp = 0;
186        int v1 = value.length;
187        for(int v2 = val2.length; v2>0; ){
188            temp = (value[--v1] & 0xFFFFFFFFL) + (val2 [--v2] & 0xFFFFFFFFL) + (temp >>> 32);
189            value[v1] = (int)temp;
190        }
191        boolean uebertrag = (temp >>> 32) != 0;
192        while(v1 > 0 && uebertrag)
193            uebertrag = (value[--v1] = value[v1] + 1) == 0;
194 
195        // vergrößern, wenn notwendig
196        if(uebertrag){
197                        resizeValue(1);
198        }
199    }
200    
201    
202    
203    /**
204     * Resize the value mantisse with a carryover. 
205     * @param highBits Is the high value that is save on the resize place.
206     */
207        private void resizeValue(int highBits){
208                int val[] = new int[value.length+1];
209                val[0] = highBits;
210                System.arraycopy(value, 0, val, 1, value.length);
211                value = val;
212    }
213         
214    
215    // Subtrahiert den Wert zum aktuellen MutableNumeric Object und verändert es.
216    void sub(MutableNumeric num){
217                if(num.scale < scale){
218                        num.setScale(scale);
219                }else
220                if(num.scale > scale){
221                        setScale(num.scale);
222                }
223        add( -num.signum, num.value );
224    }
225 
226    // val2 ist kürzer oder gleich lang wie value
227    // val2 wird von der aktuellen Zahl abgezogen
228    private void sub(int[] val2){
229        long temp = 0;
230        int v1 = value.length;
231        for(int v2 = val2.length; v2>0; ){
232            temp = (value[--v1] & 0xFFFFFFFFL) - (val2 [--v2] & 0xFFFFFFFFL) + (temp >>>= 32);
233            value[v1] = (int)temp;
234        }
235 
236        boolean uebertrag = (temp >>> 32) != 0;
237        while(v1 > 0 && uebertrag)
238            uebertrag = (value[--v1] = value[v1] - 1) == -1;
239 
240        if(uebertrag){
241            signum = -signum;
242            int last = value.length-1;
243            for(int i=0; i<=last; i++){
244                value[i] = (i == last) ? -value[i] : ~value[i];
245            }
246        }
247    }
248 
249    void mul(MutableNumeric num){
250                //TODO performance
251                BigDecimal big = toBigDecimal().multiply(num.toBigDecimal() );
252                setValue( big.unscaledValue().toByteArray() );
253                scale = big.scale();
254                signum = big.signum();
255    }
256 
257        final void mul(int factor){
258                if(factor < 0){
259                        factor = - factor;
260                        signum = -signum;
261                }
262                long carryover = 0;
263                for(int i = value.length-1; i>=0; i--){
264                        long v = (value[i] & 0xFFFFFFFFL) * factor + carryover;
265                        value[i] = (int)v;
266                        carryover = v >> 32;
267                }
268                if(carryover > 0){
269                        resizeValue( (int)carryover );
270                }
271        }
272        
273 
274    void div(MutableNumeric num){
275            //TODO performance
276                int newScale = Math.max(scale+5, num.scale +4);
277                BigDecimal big = toBigDecimal().divide(num.toBigDecimal(), newScale, BigDecimal.ROUND_HALF_EVEN);
278                setValue( big.unscaledValue().toByteArray() );
279                scale = big.scale();
280                signum = big.signum();
281    }
282        
283 
284        final void div(int quotient){
285                //increment the scale with 5
286                mul(100000);
287                scale += 5;
288                
289                divImpl(quotient);
290        }
291        
292        
293        final private void divImpl(int quotient){        
294                if(quotient == 1) return;
295                if(quotient < 0){
296                        quotient = - quotient;
297                        signum = -signum;
298                }
299                int valueLength = value.length;
300                long carryover = 0;
301                for(int i = 0; i<valueLength; i++){
302                        long v = (value[i] & 0xFFFFFFFFL) + carryover;
303                        value[i] = (int)(v / quotient);
304                        carryover = ((v % quotient) << 32);
305                }
306                carryover /= quotient;
307                if(carryover > 2147483648L || //2147483648L == Integer.MAX_VALUE+1
308                  (carryover == 2147483648L && (value[valueLength-1] % 2 == 1))){
309                        int i = valueLength-1;
310                        boolean isCarryOver = true;
311                        while(i >= 0 && isCarryOver)
312                                isCarryOver = (value[i--] += 1) == 0;
313                }
314                if(valueLength>1 && value[0] == 0){
315                        int[] temp = new int[valueLength-1];
316                        System.arraycopy(value, 1, temp, 0, valueLength-1);
317                        value = temp;
318                }
319                        
320        }
321        
322        
323    void mod(MutableNumeric num){
324            //TODO performance
325                num = new MutableNumeric( doubleValue() % num.doubleValue() );
326                value = num.value;
327                scale = num.scale;
328                signum = num.signum;
329    }
330 
331 
332        
333        void setScale(int newScale){
334                if(newScale == scale) return;
335                int factor = 1;
336                if(newScale > scale){
337                        for(;newScale>scale; scale++){
338                                factor *=10;
339                                if(factor == 1000000000){
340                                        mul(factor);
341                                        factor = 1;
342                                }
343                        }
344                        mul(factor);
345                }else{
346                        for(;newScale<scale; scale--){
347                                factor *=10;
348                                if(factor == 1000000000){
349                                        divImpl(factor);
350                                        factor = 1;
351                                }
352                        }
353                        divImpl(factor);                
354                }
355        }
356        
357        
358        void floor(){
359                //TODO performance
360                int oldScale = scale;
361                setScale(0);
362                setScale(oldScale);
363        }
364        
365 
366    private void negate(byte[] complement){
367        int last = complement.length-1;
368        for(int i=0; i<=last; i++){
369            complement[i] = (byte)( (i == last) ? -complement[i] : ~complement[i]);
370        }
371    }
372 
373    // Konvertiert es in ein 2 Komplement, wie es von BigInteger verarbeitet werden kann
374    // die Länge ist immer ein vielfaches von 4
375    byte[] toByteArray(){
376        if(signum == 0) return EMPTY_BYTES;
377        byte[] complement;
378        int offset;
379 
380        int v = 0;
381        for( ;v < value.length && value[v] == 0; v++ ) ;
382        if (v == value.length) return EMPTY_BYTES;
383 
384        if(value[v] < 0){
385            // wenn das most signifikante bit ist gesetzt, dann muß vergrößert werden,
386            // weil es für das Vorzeichen bnötigt wird.
387            complement = new byte[(value.length-v)*4 + 4];
388            if(signum < 0)
389                complement[0] = complement[1] = complement[2] = complement[3] = -1;
390            offset = 4;
391        }else{
392            complement = new byte[(value.length-v)*4];
393            offset = 0;
394        }
395        int last = value.length-1;
396        for(; v <= last; v++){
397            int val = (signum>0) ? value[v] : (v == last) ? -value[v] : ~value[v];
398            complement[offset++] = (byte)(val >> 24);
399            complement[offset++] = (byte)(val >> 16);
400            complement[offset++] = (byte)(val >> 8);
401            complement[offset++] = (byte)(val);
402        }
403        return complement;
404    }
405 
406    public int intValue(){
407        return Utils.long2int(longValue());
408    }
409    
410 
411    public long longValue(){
412        if(value.length == 0 || signum == 0){
413            return 0;
414        }else{
415            if (value.length == 1 && (value[0] > 0)){
416                // einfacher Integer Wert
417                return Utils.double2long(value[0] / scaleDoubleFactor[scale] * signum);
418            }else
419            if (value.length == 1){
420                // überlaufender Integer Wert
421                long temp = value[0] & 0xFFFFFFFFL;
422                return Utils.double2long(temp / scaleDoubleFactor[scale] * signum);
423            }else
424            if (value.length == 2 && (value[0] > 0)){
425                // einfacher Long Wert
426                long temp = (((long)value[0]) << 32) | (value[1] & 0xFFFFFFFFL);
427                return Utils.double2long(temp / scaleDoubleFactor[scale] * signum);
428            }else{
429                           if(scale != 0){
430                                   MutableNumeric numeric = new MutableNumeric(this);
431                                   numeric.setScale(0);
432                                   return numeric.longValue();
433                           }                                   
434                    return (signum > 0) ? Long.MAX_VALUE : Long.MIN_VALUE;
435            }
436        }
437    }
438    
439 
440    public float floatValue(){
441        if(value.length == 0 || signum == 0){
442            return 0;
443        }else{
444            if (value.length == 1 && (value[0] > 0)){
445                // einfacher Integer Wert
446                return value[0] / scaleFloatFactor[scale] * signum;
447            }else
448            if (value.length == 1){
449                // überlaufender Integer Wert
450                long temp = value[0] & 0xFFFFFFFFL;
451                return temp / scaleFloatFactor[scale] * signum;
452            }else
453            if (value.length == 2 && (value[0] > 0)){
454                // einfacher Long Wert
455                long temp = (((long)value[0]) << 32) | (value[1] & 0xFFFFFFFFL);
456                return temp / scaleFloatFactor[scale] * signum;
457            }else{
458                return new BigDecimal( new BigInteger( toByteArray() ), scale ).floatValue();
459            }
460        }
461    }
462 
463    public double doubleValue(){
464        if(value.length == 0 || signum == 0){
465            return 0;
466        }else{
467            if (value.length == 1 && (value[0] > 0)){
468                // einfacher Integer Wert
469                return value[0] / scaleDoubleFactor[scale] * signum;
470            }else
471            if (value.length == 1){
472                // überlaufender Integer Wert
473                long temp = value[0] & 0xFFFFFFFFL;
474                return temp / scaleDoubleFactor[scale] * signum;
475            }else
476            if (value.length == 2 && (value[0] > 0)){
477                // einfacher Long Wert
478                long temp = (((long)value[0]) << 32) | (value[1] & 0xFFFFFFFFL);
479                return temp / scaleDoubleFactor[scale] * signum;
480            }else{
481                return new BigDecimal( new BigInteger( toByteArray() ), scale ).doubleValue();
482            }
483        }
484    }
485 
486    public String toString(){
487        StringBuffer buf = new StringBuffer();
488        if(value.length == 0 || signum == 0){
489            buf.append( '0' );
490        }else{
491            if (value.length == 1 && (value[0] > 0)){
492                // einfacher Integer Wert
493                buf.append( Integer.toString(value[0]) );
494            }else
495            if (value.length == 1){
496                // überlaufender Integer Wert
497                long temp = value[0] & 0xFFFFFFFFL;
498                buf.append( Long.toString( temp ) );
499            }else
500            if (value.length == 2 && (value[0] > 0)){
501                // einfacher Long Wert
502                long temp = (((long)value[0]) << 32) | (value[1] & 0xFFFFFFFFL);
503                buf.append( Long.toString( temp ) );
504            }else{
505                return new BigDecimal( new BigInteger( toByteArray() ), scale ).toString();
506            }
507        }
508        if(scale > 0){
509            while(buf.length() <= scale) buf.insert( 0, '0' );
510            buf.insert( buf.length() - scale, '.' );
511        }
512        if (signum < 0) buf.insert( 0, '-');
513        return buf.toString();
514    }
515    
516    public int compareTo(MutableNumeric numeric){
517            //TODO performance
518                return toBigDecimal().compareTo(numeric.toBigDecimal());
519    }           
520 
521        public boolean equals(Object obj){
522                if(!(obj instanceof MutableNumeric)) return false;
523                return compareTo((MutableNumeric)obj) == 0;
524        }
525        
526    public BigDecimal toBigDecimal(){
527                if(signum == 0) return new BigDecimal( BigInteger.ZERO, scale);
528        return new BigDecimal( new BigInteger( toByteArray() ), scale );
529    }
530 
531    public BigDecimal toBigDecimal(int scale){
532        if(scale == this.scale) return toBigDecimal();
533        return toBigDecimal().setScale( scale, BigDecimal.ROUND_HALF_EVEN);
534    }
535 
536        public Object getImmutableObject(){
537                return toBigDecimal();
538        }
539        
540    private static final byte[] EMPTY_BYTES = new byte[0];
541    private static final int [] EMPTY_INTS  = new int [0];
542    private static final double[] scaleDoubleFactor = { 1, 10, 100, 1000, 10000, 100000, 1000000 };
543    private static final float[]  scaleFloatFactor =  { 1, 10, 100, 1000, 10000, 100000, 1000000 };
544}

[all classes][smallsql.database]
EMMA 2.1.5320 (stable) (C) Vladimir Roubtsov