/*
* JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
* Copyright (C) 2006 - JScience (http://jscience.org/)
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software is
* freely granted, provided that this notice is preserved.
*/
package org.jscience.mathematics.number;
import org.jscience.mathematics.structure.Field;
import javolution.context.LocalContext;
import javolution.context.ObjectFactory;
import javolution.text.Text;
import javolution.xml.XMLFormat;
import javolution.xml.stream.XMLStreamException;
/**
* This class represents a modulo integer. It can be used in conjonction
* with the {@link org.jscience.mathematics.vector.Matrix Matrix}
* class to resolve modulo equations (ref. number theory).
*
* @author Jean-Marie Dautelle
* @version 3.0, February 13, 2006
* @see
* Wikipedia: Modular Arithmetic
*/
public final class ModuloInteger extends Number implements Field {
/**
* The modulo integer representing the additive identity.
*/
public static final ModuloInteger ZERO = new ModuloInteger();
static {
ZERO._value = LargeInteger.ZERO;
}
/**
* The modulo integer representing the multiplicative identity.
*/
public static final ModuloInteger ONE = new ModuloInteger();
static {
ONE._value = LargeInteger.ONE;
}
/**
* Holds the default XML representation for modulo integers.
* This representation consists of a simple value attribute
* holding the {@link #toText() textual} representation.
*/
static final XMLFormat XML = new XMLFormat(ModuloInteger.class) {
@Override
public ModuloInteger newInstance(Class cls, InputElement xml) throws XMLStreamException {
return ModuloInteger.valueOf(xml.getAttribute("value"));
}
public void write(ModuloInteger mi, OutputElement xml) throws XMLStreamException {
xml.setAttribute("value", mi._value.toText());
}
public void read(InputElement xml, ModuloInteger mi) {
// Nothing to do, immutable.
}
};
/**
* Holds the local modulus (for modular arithmetic).
*/
private static final LocalContext.Reference MODULUS
= new LocalContext.Reference();
/**
* Holds the large integer value.
*/
private LargeInteger _value;
/**
* Returns the modulo integer having the specified value (independently of
* the current modulo).
*
* @param value the modulo integer intrinsic value.
* @return the corresponding modulo number.
*/
public static ModuloInteger valueOf(LargeInteger value) {
return ModuloInteger.newInstance(value);
}
/**
* Returns the modulo integer for the specified character sequence in
* decimal number.
*
* @param chars the character sequence.
* @return the corresponding modulo number.
*/
public static ModuloInteger valueOf(CharSequence chars) {
return ModuloInteger.newInstance(LargeInteger.valueOf(chars));
}
/**
* Returns the {@link javolution.context.LocalContext local} modulus
* for modular arithmetic or null if the arithmetic operations
* are non-modular (default).
*
* @return the local modulus or null if none.
* @see #setModulus
*/
public static LargeInteger getModulus() {
return MODULUS.get();
}
/**
* Sets the {@link javolution.context.LocalContext local} modulus
* for modular arithmetic.
*
* @param modulus the new modulus or null to unset the modulus.
* @throws IllegalArgumentException if modulus <= 0
*/
public static void setModulus(LargeInteger modulus) {
if ((modulus != null) && (!modulus.isPositive()))
throw new IllegalArgumentException("modulus: " + modulus
+ " has to be greater than 0");
MODULUS.set(modulus);
}
/**
* Returns the current modulo value of this number. If the modulus
* is {@link #setModulus set} to null the intrinsic value
* (the creation value) is returned.
*
* @return the positive number equals to this number modulo modulus or
* this modulo creation value.
*/
public LargeInteger moduloValue() {
LargeInteger modulus = MODULUS.get();
return (modulus == null) ? _value : _value.mod(modulus);
}
/**
* Returns the text representation of the current modulo value of
* this number.
*
* @return the representation of its modulo value.
*/
public Text toText() {
return moduloValue().toText();
}
/**
* Compares this modulo integer against the specified object
* independently of the current modulus.
*
* @param that the object to compare with.
* @return true if that is a modulo number with the same
* intrinsic value; false otherwise.
*/
public boolean equals(Object that) {
return (that instanceof ModuloInteger) ?
_value.equals(((ModuloInteger) that)._value) :
false;
}
/**
* Returns the hash code for this large integer number.
*
* @return the hash code value.
*/
public int hashCode() {
return _value.hashCode();
}
@Override
public boolean isLargerThan(ModuloInteger that) {
return _value.isLargerThan(that._value);
}
@Override
public long longValue() {
return moduloValue().longValue();
}
@Override
public double doubleValue() {
return moduloValue().doubleValue();
}
@Override
public int compareTo(ModuloInteger that) {
return _value.compareTo(that._value);
}
public ModuloInteger times(ModuloInteger that) {
LargeInteger value = moduloValue().times(that.moduloValue());
LargeInteger modulus = MODULUS.get();
return (modulus == null) ? ModuloInteger.valueOf(value)
: ModuloInteger.valueOf(value.mod(modulus));
}
public ModuloInteger plus(ModuloInteger that) {
LargeInteger value = moduloValue().plus(that.moduloValue());
LargeInteger modulus = MODULUS.get();
return (modulus == null) ? ModuloInteger.valueOf(value)
: ModuloInteger.valueOf(value.mod(modulus));
}
public ModuloInteger opposite() {
LargeInteger value = moduloValue().opposite();
LargeInteger modulus = MODULUS.get();
return (modulus == null) ? ModuloInteger.valueOf(value)
: ModuloInteger.valueOf(value.mod(modulus));
}
public ModuloInteger inverse() {
LargeInteger modulus = MODULUS.get();
if (modulus == null)
throw new ArithmeticException("Modulus not set");
return ModuloInteger.valueOf(_value.modInverse(modulus));
}
///////////////////////
// Factory creation. //
///////////////////////
private static ModuloInteger newInstance(LargeInteger value) {
ModuloInteger m = FACTORY.object();
m._value = value;
return m;
}
private static final ObjectFactory FACTORY = new ObjectFactory() {
protected ModuloInteger create() {
return new ModuloInteger();
}
};
private ModuloInteger() {
}
@Override
public ModuloInteger copy() {
return newInstance(_value.copy());
}
private static final long serialVersionUID = 1L;
}
Ads help maintain this website.