/*******************************************************************************
* Copyright (c) 2009-2013 CWI
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*
* * Arnold Lankamp - interfaces and implementation
* * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI
*******************************************************************************/
package org.rascalmpl.value.impl.primitive;
import java.math.BigDecimal;
import java.math.BigInteger;
import org.rascalmpl.value.IBool;
import org.rascalmpl.value.IInteger;
import org.rascalmpl.value.INumber;
import org.rascalmpl.value.IRational;
import org.rascalmpl.value.IReal;
import org.rascalmpl.value.IValue;
import org.rascalmpl.value.type.Type;
import org.rascalmpl.value.type.TypeFactory;
import org.rascalmpl.value.visitors.IValueVisitor;
/**
* Specialized implementation for integer values that fall outside the 32-bit range.
*
* @author Arnold Lankamp
*/
/*package*/ class BigIntegerValue extends AbstractNumberValue implements IInteger, ICanBecomeABigInteger{
private final static Type INTEGER_TYPE = TypeFactory.getInstance().integerType();
protected final BigInteger value;
/*package*/ BigIntegerValue(BigInteger value){
super();
if(value.equals(BigInteger.ZERO))
value = BigInteger.ZERO;
if(value.equals(BigInteger.ONE))
value = BigInteger.ONE;
this.value = value;
}
@Override
public IInteger toInteger() {
return this;
}
@Override
public Type getType(){
return INTEGER_TYPE;
}
@Override
public int intValue(){
return value.intValue();
}
@Override
public long longValue(){
return value.longValue();
}
@Override
public double doubleValue(){
return value.doubleValue();
}
@Override
public IReal toReal(int precision){
// precision is ignored intentionally
return BigDecimalValue.newReal(new BigDecimal(value));
}
@Override
public IRational toRational(){
return RationalValue.newRational(this, IntegerValue.INTEGER_ONE);
}
@Override
public byte[] getTwosComplementRepresentation(){
return value.toByteArray();
}
@Override
public BigInteger toBigInteger(){
return value;
}
@Override
public IInteger add(IInteger other){
BigInteger o = ((ICanBecomeABigInteger) other).toBigInteger();
BigInteger result = value.add(o);
if(result == value)
return this;
else if(result == o)
return other;
int length = result.bitLength();
if(length <= 31){
return IntegerValue.newInteger(result.intValue());
}
return IntegerValue.newInteger(result);
}
@Override
public IReal add(IReal other) {
return (IReal) other.add(this);
}
@Override
public IRational add(IRational other) {
return (IRational) other.add(this);
}
@Override
public IInteger subtract(IInteger other){
BigInteger result = value.subtract(((ICanBecomeABigInteger) other).toBigInteger());
if(result == value)
return this;
int length = result.bitLength();
if(length <= 31){
return IntegerValue.newInteger(result.intValue());
}
return IntegerValue.newInteger(result);
}
@Override
public INumber subtract(IReal other) {
return toReal(other.precision()).subtract(other);
}
@Override
public INumber subtract(IRational other) {
return toRational().subtract(other);
}
@Override
public IInteger multiply(IInteger other){
BigInteger o = ((ICanBecomeABigInteger) other).toBigInteger();
BigInteger result = value.multiply(o);
if(result == value)
return this;
else if(result == o)
return other;
// The result of this operation can never fit in a 32-bit integer, so no need to check.
return IntegerValue.newInteger(result);
}
@Override
public IReal multiply(IReal other) {
return (IReal) other.multiply(this);
}
@Override
public IRational multiply(IRational other) {
return (IRational) other.multiply(this);
}
@Override
public IInteger divide(IInteger other){
BigInteger result = value.divide(((ICanBecomeABigInteger) other).toBigInteger());
if(result == value)
return this;
int length = result.bitLength();
if(length <= 31){
return IntegerValue.newInteger(result.intValue());
}
return IntegerValue.newInteger(result);
}
@Override
public IRational divide(IRational other) {
return toRational().divide(other);
}
@Override
public INumber divide(IInteger other, int precision) {
return toReal(precision).divide(other, precision);
}
@Override
public INumber divide(IRational other, int precision) {
return toReal(precision).divide(other, precision);
}
@Override
public IReal divide(IReal other, int precision) {
return toReal(precision).divide(other, precision);
}
@Override
public IInteger mod(IInteger other){
BigInteger result = value.mod(((ICanBecomeABigInteger) other).toBigInteger());
if(other instanceof IntegerValue){
int integerResult = result.intValue();
return IntegerValue.newInteger(integerResult);
}
return IntegerValue.newInteger(result);
}
@Override
public IInteger remainder(IInteger other){
BigInteger result = value.remainder(((ICanBecomeABigInteger) other).toBigInteger());
if(other instanceof IntegerValue){
int integerResult = result.intValue();
return IntegerValue.newInteger(integerResult);
}
return IntegerValue.newInteger(result);
}
@Override
public IInteger negate(){
return IntegerValue.newInteger(value.negate());
}
@Override
public IBool equal(IInteger other){
return BoolValue.getBoolValue(compare(other) == 0);
}
@Override
public IBool equal(IReal other) {
return other.equal(this);
}
@Override
public IBool equal(IRational other) {
return other.equal(this);
}
@Override
public IBool greater(IInteger other){
return BoolValue.getBoolValue(compare(other) > 0);
}
@Override
public IBool greater(IReal other) {
return other.less(this);
}
@Override
public IBool greater(IRational other) {
return other.less(this);
}
@Override
public IBool greaterEqual(IInteger other){
return BoolValue.getBoolValue(compare(other) >= 0);
}
@Override
public IBool greaterEqual(IReal other) {
return other.lessEqual(this);
}
@Override
public IBool greaterEqual(IRational other) {
return other.lessEqual(this);
}
@Override
public IBool less(IInteger other){
return BoolValue.getBoolValue(compare(other) < 0);
}
@Override
public IBool less(IReal other) {
return other.greater(this);
}
@Override
public IBool less(IRational other) {
return other.greater(this);
}
@Override
public IBool lessEqual(IInteger other){
return BoolValue.getBoolValue(compare(other) <= 0);
}
@Override
public IBool lessEqual(IReal other) {
return other.greaterEqual(this);
}
@Override
public IBool lessEqual(IRational other) {
return other.greaterEqual(this);
}
@Override
public int compare(IInteger other){
return value.compareTo(((ICanBecomeABigInteger) other).toBigInteger());
}
@Override
public int compare(INumber other) {
if (isIntegerType(other)) {
return compare(other.toInteger());
}
else if (isRationalType(other)) {
return toRational().compare(other);
}
else {
assert other instanceof IReal;
return toReal(((IReal) other).precision()).compare(other);
}
}
@Override
public <T, E extends Throwable> T accept(IValueVisitor<T,E> v) throws E{
return v.visitInteger(this);
}
public int hashCode(){
return value.hashCode();
}
public boolean equals(Object o){
if(o == null) return false;
else if(o == this) return true;
if(o.getClass() == getClass()){
BigIntegerValue otherInteger = (BigIntegerValue) o;
return value.equals(otherInteger.value);
}
return false;
}
@Override
public boolean isEqual(IValue other){
return equals(other);
}
@Override
public String getStringRepresentation(){
return value.toString();
}
@Override
public int signum() {
return value.signum();
}
@Override
public IInteger abs() {
return IntegerValue.newInteger(value.abs());
}
}