001/*
002 * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
003 * Copyright (C) 2006 - JScience (http://jscience.org/)
004 * All rights reserved.
005 * 
006 * Permission to use, copy, modify, and distribute this software is
007 * freely granted, provided that this notice is preserved.
008 */
009package org.jscience.mathematics.number;
010
011import org.jscience.mathematics.structure.Field;
012
013import javolution.context.LocalContext;
014import javolution.context.ObjectFactory;
015import javolution.text.Text;
016import javolution.xml.XMLFormat;
017import javolution.xml.stream.XMLStreamException;
018
019/**
020 * <p> This class represents a modulo integer. It can be used in conjonction 
021 *     with the {@link org.jscience.mathematics.vector.Matrix Matrix}
022 *     class to resolve modulo equations (ref. number theory).</p>
023 *     
024 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
025 * @version 3.0, February 13, 2006
026 * @see <a href="http://en.wikipedia.org/wiki/Modular_arithmetic">
027 *      Wikipedia: Modular Arithmetic</a>
028 */
029public final class ModuloInteger extends Number<ModuloInteger> implements Field<ModuloInteger> {
030    
031    /**
032     * The modulo integer representing the additive identity.
033     */
034    public static final ModuloInteger ZERO = new ModuloInteger();
035    static {
036        ZERO._value = LargeInteger.ZERO;
037    }
038
039    /**
040     * The modulo integer representing the multiplicative identity.
041     */
042    public static final ModuloInteger ONE = new ModuloInteger();
043    static {
044        ONE._value = LargeInteger.ONE;
045    }
046
047    /**
048     * Holds the default XML representation for modulo integers.
049     * This representation consists of a simple <code>value</code> attribute
050     * holding the {@link #toText() textual} representation.
051     */
052    static final XMLFormat<ModuloInteger> XML = new XMLFormat<ModuloInteger>(ModuloInteger.class) {
053        
054        @Override
055        public ModuloInteger newInstance(Class<ModuloInteger> cls, InputElement xml) throws XMLStreamException {
056            return ModuloInteger.valueOf(xml.getAttribute("value"));
057        }
058        
059        public void write(ModuloInteger mi, OutputElement xml) throws XMLStreamException {
060            xml.setAttribute("value", mi._value.toText());
061            }
062
063         public void read(InputElement xml, ModuloInteger mi) {
064             // Nothing to do, immutable.
065         }
066     };
067
068    /**
069     * Holds the local modulus (for modular arithmetic).
070     */
071    private static final LocalContext.Reference<LargeInteger> MODULUS
072        = new LocalContext.Reference<LargeInteger>();
073
074    /**
075     * Holds the large integer value.
076     */
077    private LargeInteger _value;
078
079    /**
080     * Returns the modulo integer having the specified value (independently of
081     * the current modulo).
082     * 
083     * @param  value the modulo integer intrinsic value.
084     * @return the corresponding modulo number.
085     */
086    public static ModuloInteger valueOf(LargeInteger value) {
087         return ModuloInteger.newInstance(value);
088    }
089    /**
090     * Returns the modulo integer for the specified character sequence in
091     * decimal number.
092     * 
093     * @param chars the character sequence.
094     * @return the corresponding modulo number.
095     */
096    public static ModuloInteger valueOf(CharSequence chars) {
097        return ModuloInteger.newInstance(LargeInteger.valueOf(chars));
098    }
099    
100    /**
101     * Returns the {@link javolution.context.LocalContext local} modulus 
102     * for modular arithmetic or <code>null</code> if the arithmetic operations
103     * are non-modular (default). 
104     * 
105     * @return the local modulus or <code>null</code> if none.
106     * @see #setModulus
107     */
108    public static LargeInteger getModulus() {
109        return MODULUS.get();
110    }
111
112    /**
113     * Sets the {@link javolution.context.LocalContext local} modulus 
114     * for modular arithmetic.
115     * 
116     * @param modulus the new modulus or <code>null</code> to unset the modulus.
117     * @throws IllegalArgumentException if <code>modulus &lt;= 0</code>
118     */
119    public static void setModulus(LargeInteger modulus) {
120        if ((modulus != null) && (!modulus.isPositive()))
121            throw new IllegalArgumentException("modulus: " + modulus
122                    + " has to be greater than 0");
123        MODULUS.set(modulus);
124    }
125
126    /**
127     * Returns the current modulo value of this number. If the modulus 
128     * is {@link #setModulus set} to <code>null</code> the intrinsic value
129     * (the creation value) is returned.
130     * 
131     * @return the positive number equals to this number modulo modulus or
132     *         this modulo creation value.
133     */
134    public LargeInteger moduloValue() {
135        LargeInteger modulus = MODULUS.get();
136        return (modulus == null) ? _value : _value.mod(modulus);
137    }
138
139    /**
140     * Returns the text representation of the current modulo value of 
141     * this number.
142     *
143     * @return the representation of its modulo value.
144     */
145    public Text toText() {
146        return moduloValue().toText();
147    }
148
149    /**
150     * Compares this modulo integer against the specified object
151     * independently of the current modulus.
152     * 
153     * @param that the object to compare with.
154     * @return <code>true</code> if that is a modulo number with the same 
155     *         intrinsic value; <code>false</code> otherwise.
156     */
157    public boolean equals(Object that) {
158        return (that instanceof ModuloInteger) ?
159            _value.equals(((ModuloInteger) that)._value) :
160            false;
161    }
162
163    /**
164     * Returns the hash code for this large integer number.
165     * 
166     * @return the hash code value.
167     */
168    public int hashCode() {
169        return _value.hashCode();
170    }
171
172    @Override
173    public boolean isLargerThan(ModuloInteger that) {
174        return _value.isLargerThan(that._value);
175    }
176
177    @Override
178    public long longValue() {
179        return moduloValue().longValue();
180    }
181
182    @Override
183    public double doubleValue() {
184        return moduloValue().doubleValue();
185    }
186
187    @Override
188    public int compareTo(ModuloInteger that) {
189        return _value.compareTo(that._value);
190    }
191
192    public ModuloInteger times(ModuloInteger that) {
193        LargeInteger value = moduloValue().times(that.moduloValue());
194        LargeInteger modulus = MODULUS.get();
195        return (modulus == null) ? ModuloInteger.valueOf(value)
196                : ModuloInteger.valueOf(value.mod(modulus));
197    }
198
199    public ModuloInteger plus(ModuloInteger that) {
200        LargeInteger value = moduloValue().plus(that.moduloValue());
201        LargeInteger modulus = MODULUS.get();
202        return (modulus == null) ? ModuloInteger.valueOf(value)
203                : ModuloInteger.valueOf(value.mod(modulus));
204    }
205
206    public ModuloInteger opposite() {
207        LargeInteger value = moduloValue().opposite();
208        LargeInteger modulus = MODULUS.get();
209        return (modulus == null) ? ModuloInteger.valueOf(value)
210                : ModuloInteger.valueOf(value.mod(modulus));
211    }
212
213    public ModuloInteger inverse() {
214        LargeInteger modulus = MODULUS.get();
215        if (modulus == null) 
216            throw new ArithmeticException("Modulus not set");
217        return ModuloInteger.valueOf(_value.modInverse(modulus));
218    }
219
220    ///////////////////////
221    // Factory creation. //
222    ///////////////////////
223    
224    private static ModuloInteger newInstance(LargeInteger value) {
225        ModuloInteger m = FACTORY.object();
226        m._value = value;
227        return m;
228    }
229    
230    private static final ObjectFactory<ModuloInteger> FACTORY = new ObjectFactory<ModuloInteger>() {
231        protected ModuloInteger create() {
232            return new ModuloInteger();
233        }
234    };
235    
236    private ModuloInteger() {
237    }
238
239    @Override
240    public ModuloInteger copy() {
241        return newInstance(_value.copy());
242    }
243
244    private static final long serialVersionUID = 1L;
245
246}