com.hfg.math.RomanNumeralSymbol Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of com_hfg Show documentation
Show all versions of com_hfg Show documentation
com.hfg xml, html, svg, and bioinformatics utility library
package com.hfg.math;
import java.util.Map;
import com.hfg.util.collection.OrderedMap;
//------------------------------------------------------------------------------
/**
Individual Roman numeral symbol representation. Used by the RomanNumeral class,
it encapsulates the logic of which symbols can precede a given symbol.
See http://en.wikipedia.org/wiki/Roman_numerals
@author J. Alex Taylor, hairyfatguy.com
*/
//------------------------------------------------------------------------------
// com.hfg XML/HTML Coding Library
//
// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
// [email protected]
//------------------------------------------------------------------------------
public class RomanNumeralSymbol implements Comparable
{
//**************************************************************************
// PRIVATE FIELDS
//**************************************************************************
char mLetter;
int mValue;
private static Map sValueMap = new OrderedMap(10);
//**************************************************************************
// PUBLIC FIELDS
//**************************************************************************
/** The Roman numeral for the integer 1. */
public static RomanNumeralSymbol I = new RomanNumeralSymbol('I', 1);
/** The Roman numeral for the integer 5. */
public static RomanNumeralSymbol V = new RomanNumeralSymbol('V', 5);
/** The Roman numeral for the integer 10. */
public static RomanNumeralSymbol X = new RomanNumeralSymbol('X', 10);
/** The Roman numeral for the integer 50. */
public static RomanNumeralSymbol L = new RomanNumeralSymbol('L', 50);
/** The Roman numeral for the integer 100. */
public static RomanNumeralSymbol C = new RomanNumeralSymbol('C', 100);
/** The Roman numeral for the integer 500. */
public static RomanNumeralSymbol D = new RomanNumeralSymbol('D', 500);
/** The Roman numeral for the integer 1000. */
public static RomanNumeralSymbol M = new RomanNumeralSymbol('M', 1000);
//**************************************************************************
// CONSTRUCTORS
//**************************************************************************
//--------------------------------------------------------------------------
private RomanNumeralSymbol(char inLetter, int inValue)
{
mLetter = inLetter;
mValue = inValue;
sValueMap.put(mLetter, this);
}
//**************************************************************************
// PUBLIC METHODS
//**************************************************************************
//--------------------------------------------------------------------------
/**
Returns the RomanNumeralSymbol value for the specified character.
*/
public static RomanNumeralSymbol valueOf(char inLetter)
{
return sValueMap.get(Character.toUpperCase(inLetter));
}
//--------------------------------------------------------------------------
/**
Returns an array of all the RomanNumeralSymbol values.
*/
public static RomanNumeralSymbol[] values()
{
return sValueMap.values().toArray(new RomanNumeralSymbol[1]);
}
//--------------------------------------------------------------------------
/**
Returns the character value of the Roman numeral symbol.
*/
public char getLetter()
{
return mLetter;
}
//--------------------------------------------------------------------------
/**
Returns the integer value of the Roman numeral symbol.
*/
public int getIntValue()
{
return mValue;
}
//--------------------------------------------------------------------------
/**
Returns the Roman numeral string value of the Roman numeral symbol.
*/
@Override
public String toString()
{
return mLetter + "";
}
//--------------------------------------------------------------------------
/**
Numerically compares two RomanNumeralSymbol objects.
*/
public int compareTo(RomanNumeralSymbol inObj)
{
return NumUtil.compare(mValue, inObj.mValue);
}
//--------------------------------------------------------------------------
/**
Returns whether this symbol can legally precede the specified symbol given
the subtractive principle.
*/
/*
From wikipedia:
Subtractive principle
Generally, Roman numerals are written in descending order from left to right,
and are added sequentially, for example MMVI (2006) is interpreted as 1000 + 1000 + 5 + 1.
Certain combinations employ a subtractive principle, which specifies that where a symbol
of smaller value precedes a symbol of larger value, the smaller value is subtracted from
the larger value, and the result is added to the total. For example, in MCMXLIV (1944), t
he symbols C, X and I each precede a symbol of higher value, and the result is interpreted as
1000 plus (1000 minus 100) plus (50 minus 10) plus (5 minus 1).
A numeral for 10n (I, X, or C) may not precede a numeral larger than 10n+1, where n is an integer.
That is, I may precede V and X, but not L or C; X may precede L or C, but not D or M.
The numerals 5?10n (V, L, or D) may not be followed by a numeral of greater or equal value.
Any symbol that appears more than once consecutively may not be followed by a symbol of larger value.
*/
public boolean canPrecede(RomanNumeralSymbol inSymbol)
{
boolean result;
if (inSymbol.getIntValue() < getIntValue())
{
result = true;
}
else
{
double predecessorLog10 = Math.log10((double)getIntValue());
result = (predecessorLog10%1 == 0
&& (inSymbol.getIntValue() <= Math.pow(10, (predecessorLog10 + 1))));
}
return result;
}
}