/* * [Roman.java] * * Summary: Display a number in Roman numerals. * * Copyright: (c) 1999-2017 Roedy Green, Canadian Mind Products, http://mindprod.com * * Licence: This software may be copied and used freely for any purpose but military. * http://mindprod.com/contact/nonmil.html * * Requires: JDK 1.8+ * * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/ * * Version History: * 1.0 1999-01-19 * 1.1 1999-01-20 remove 0 and negative number support * 1.2 1999-08-11 correct code for 8 to VIII not VII. * thanks to bug report from "Oliver * Borchert" <oliver.borchert@nist.gov> */ package com.mindprod.inwords; /** * Display a number in Roman numerals. *

* e.g. * 12345 -> " MMMMMMMMMMMMCCCXLV" *

* You can think of Roman numerals as a sort of base 5 representation. * It likely originated from counting on the fingers, where V represents one handful of fingers. * The Mayans counted similarly with a dot for one and a horizontal bar for five. * * @author Roedy Green, Canadian Mind Products * @version 1.2 1999-08-11 correct code for 8 to VIII not VII. * thanks to bug report from "Oliver * Borchert" <oliver.borchert@nist.gov> * Why is this code written in an unusual way? see inwords.use * There are terser algorithms, such as the Pascal version posted at * http://www.merlyn.demon.co.uk/programs/cvt_rome.pas * but they don't show the parallelism with other numbering systems * and I think they are harder to understand. * @since 1999-01-19 */ public final class Roman implements ToWords { private static final int FIRST_COPYRIGHT_YEAR = 1999; /** * undisplayed copyright notice * * @noinspection UnusedDeclaration */ private static final String EMBEDDED_COPYRIGHT = "Copyright: (c) 1999-2017 Roedy Green, Canadian Mind Products, http://mindprod.com"; private static final char[] fiveLetter = { 'V', 'L', 'D' }; private static final char[] unitLetter = { 'I', 'X', 'C', 'M' }; private static final int[] divisor = { /* * HowToProcess many of this group is needed to form one of the succeeding group. */ /* 1 10 100 1000 */ 10, 10, 10, 1000000 }; /** * test harness * * @param args not used */ public static void main( String[] args ) { Test.test( new Roman() ); } // end main /** * convert long integer into Roman Numerals. e.g. -12345 -> "minus MMMMMMMMMMMMCCCXLV" Handles negative and positive * integers on range -Long.MAX_VALUE .. Long.MAX_VALUE; It cannot handle Long.MIN_VALUE; * * @param num number to convert to words * * @return words */ @SuppressWarnings( { "WeakerAccess" } ) public String toWords( long num ) { if ( num < 0 ) { return "The Romans had no negative numbers."; } if ( num == 0 ) { return "The Romans had no zero."; } if ( num > 100000 ) { return "too unwieldy for Roman numerals"; } String s = ""; // Work least significant digit to most, right to left. // until high order part is all 0s. for ( int group = 0; num > 0; group++ ) { int remdr = ( int ) ( num % divisor[ group ] ); num = num / divisor[ group ]; StringBuilder t; if ( group == 3 ) { /* M is as big as it gets, just repeat */ t = new StringBuilder( remdr ); for ( int j = 0; j < remdr; j++ ) { t.append( unitLetter[ group ] ); } } else { t = new StringBuilder( 3 ); switch ( remdr ) { case 0: break; case 1: t.append( unitLetter[ group ] ); break; case 2: t.append( unitLetter[ group ] ); t.append( unitLetter[ group ] ); break; case 3: t.append( unitLetter[ group ] ); t.append( unitLetter[ group ] ); t.append( unitLetter[ group ] ); break; case 4: t.append( unitLetter[ group ] ); t.append( fiveLetter[ group ] ); break; case 5: t.append( fiveLetter[ group ] ); break; case 6: t.append( fiveLetter[ group ] ); t.append( unitLetter[ group ] ); break; case 7: t.append( fiveLetter[ group ] ); t.append( unitLetter[ group ] ); t.append( unitLetter[ group ] ); break; case 8: t.append( fiveLetter[ group ] ); t.append( unitLetter[ group ] ); t.append( unitLetter[ group ] ); t.append( unitLetter[ group ] ); break; case 9: t.append( unitLetter[ group ] ); t.append( unitLetter[ group + 1 ] ); break; } // end switch } // end else s = t + s; } // end for return s; } // end inWords } // end Roman