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 <= 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}