📄 mutablenumeric.java
字号:
/* =============================================================
* SmallSQL : a free Java DBMS library for the Java(tm) platform
* =============================================================
*
* (C) Copyright 2004-2007, by Volker Berlin.
*
* Project Info: http://www.smallsql.de/
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ---------------
* MutableNumeric.java
* ---------------
* Author: Volker Berlin
*
*/
package smallsql.database;
import java.math.*;
class MutableNumeric extends Number implements Mutable{
private static final long serialVersionUID = -750525164208565056L;
private int[] value;
private int scale;
private int signum;
/**
* The most significant value is on position 0.
*/
MutableNumeric(byte[] complement){
setValue(complement);
}
private void setValue(byte[] complement){
int length = complement.length;
if(length == 0){
value = EMPTY_INTS;
signum = 0;
return;
}
value = new int[ (length + 3) / 4 ];
if(complement[0] < 0){
negate( complement );
signum = -1;
}else{
signum = 0;
for(int i=0; i<complement.length; i++)
if(complement[i] != 0){
signum = 1;
break;
}
}
for(int v=value.length-1; v>=0; v--){
int temp = 0;
for(int i=0; i<4 && 0<length; i++){
temp |= (complement[ --length ] & 0xFF) << (i*8);
}
value[v] = temp;
}
}
MutableNumeric(int complement){
if(complement == 0){
signum = 0;
value = EMPTY_INTS;
}else{
value = new int[1];
if(complement < 0){
value[0] = -complement;
signum = -1;
}else{
value[0] = complement;
signum = 1;
}
}
}
MutableNumeric(int complement, int scale){
this( complement );
this.scale = scale;
}
MutableNumeric(long complement){
if(complement == 0){
signum = 0;
value = EMPTY_INTS;
}else{
value = new int[2];
if(complement < 0){
value[0] = (int)(~(complement >> 32));
value[1] = (int)(-complement);
signum = -1;
}else{
value[0] = (int)(complement >> 32);
value[1] = (int)complement;
signum = 1;
}
}
}
MutableNumeric(long complement, int scale){
this( complement );
this.scale = scale;
}
MutableNumeric(double val){
//first convert it to a string, because double to BigDecimal has very large rounding bug
this( new BigDecimal( String.valueOf(val) ) );
}
MutableNumeric(float val){
//first convert it to a string, because float to BigDecimal has very large rounding bug
this( new BigDecimal( String.valueOf(val) ) );
}
MutableNumeric(String val){
this( new BigDecimal( val ) );
}
MutableNumeric( BigDecimal big ){
this(big.unscaledValue().toByteArray() );
scale = big.scale();
}
MutableNumeric(int signum, int[] value, int scale){
this.signum = signum;
this.value = value;
this.scale = scale;
}
MutableNumeric(MutableNumeric numeric){
this.signum = numeric.signum;
this.value = new int[numeric.value.length];
System.arraycopy(numeric.value, 0, value, 0, value.length);
this.scale = numeric.scale;
}
int[] getInternalValue(){
return value;
}
/**
* Add the value to the current MutableNumeric Object and change it.
* @param num the added value
*/
void add(MutableNumeric num){
if(num.scale < scale){
num.setScale(scale);
}else
if(num.scale > scale){
setScale(num.scale);
}
add( num.signum, num.value );
}
private void add( int sig2, int[] val2){
if(val2.length > value.length){
int[] temp = val2;
val2 = value;
value = temp;
int tempi = signum;
signum = sig2;
sig2 = tempi;
}
if(signum != sig2)
sub(val2);
else
add(val2);
}
/**
* Add the value to the current MutableNumeric Object and change it.
* The parameter <code>val2</code> has a shorter or equals length.
* The signum of both values is equals.
* @param val2 the added value
*/
private void add( int[] val2){
long temp = 0;
int v1 = value.length;
for(int v2 = val2.length; v2>0; ){
temp = (value[--v1] & 0xFFFFFFFFL) + (val2 [--v2] & 0xFFFFFFFFL) + (temp >>> 32);
value[v1] = (int)temp;
}
boolean uebertrag = (temp >>> 32) != 0;
while(v1 > 0 && uebertrag)
uebertrag = (value[--v1] = value[v1] + 1) == 0;
// resize if needed
if(uebertrag){
resizeValue(1);
}
}
/**
* Resize the value mantissa with a carryover.
* @param highBits Is the high value that is save on the resize place.
*/
private void resizeValue(int highBits){
int val[] = new int[value.length+1];
val[0] = highBits;
System.arraycopy(value, 0, val, 1, value.length);
value = val;
}
/**
* Subtract the value to the current MutableNumeric Object and change it.
* @param num the subtracted value
*/
void sub(MutableNumeric num){
if(num.scale < scale){
num.setScale(scale);
}else
if(num.scale > scale){
setScale(num.scale);
}
add( -num.signum, num.value );
}
/**
* Subtract the value to the current MutableNumeric Object and change it.
* The parameter <code>val2</code> has a shorter or equals length.
* The signum of both values is equals.
* @param val2 the subtracted value
*/
private void sub(int[] val2){
long temp = 0;
int v1 = value.length;
for(int v2 = val2.length; v2>0; ){
temp = (value[--v1] & 0xFFFFFFFFL) - (val2 [--v2] & 0xFFFFFFFFL) + (temp >>>= 32);
value[v1] = (int)temp;
}
boolean uebertrag = (temp >>> 32) != 0;
while(v1 > 0 && uebertrag)
uebertrag = (value[--v1] = value[v1] - 1) == -1;
if(uebertrag){
signum = -signum;
int last = value.length-1;
for(int i=0; i<=last; i++){
value[i] = (i == last) ? -value[i] : ~value[i];
}
}
}
void mul(MutableNumeric num){
//TODO performance
BigDecimal big = toBigDecimal().multiply(num.toBigDecimal() );
setValue( big.unscaledValue().toByteArray() );
scale = big.scale();
signum = big.signum();
}
final void mul(int factor){
if(factor < 0){
factor = - factor;
signum = -signum;
}
long carryover = 0;
for(int i = value.length-1; i>=0; i--){
long v = (value[i] & 0xFFFFFFFFL) * factor + carryover;
value[i] = (int)v;
carryover = v >> 32;
}
if(carryover > 0){
resizeValue( (int)carryover );
}
}
void div(MutableNumeric num){
//TODO performance
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -