Converting Roman Numeral to integer value? [duplicate] - java

This question already has answers here:
Converting Roman Numerals To Decimal
(30 answers)
Closed 8 years ago.
I'm a new programming student and my assignment is to convert the input of a Roman Numeral to it's integer value. Here is what I have been given:
Write a program that converts a Roman number such as MCMLXXVIII to its decimal number representation. This program must have 3 methods and a main method!
Write a method that takes input from the user and passes it to a conversion method.
Write a method that yields the numeric value of each of the letters (conversion method).
Write a method that outputs the number the user entered and the converted number.
Write a main method to test the 3 methods.
HINT: Use a single dimensional array!
Convert a string as follows:
• Look at the first two characters. If the first has a larger value than the second, then simply convert the first.
• Call the conversion method again for the substring starting with the second character.
• Add both values. o If the first one has a smaller value than the second, compute the difference and add to it the conversion of the tail.
Now I am struggling trying to figure out what to do for my conversion method. Here is what I have written so far:
public static String romanInput(String number) {
Scanner numberInput = new Scanner (System.in);
System.out.print("Enter a roman numeral: ");
String userInput = numberInput.next();
return userInput;
}
public static int numberConversion(int number) {
int romanConv = 0;
char[] romanChar = {1, 5, 10, 50, 100, 500, 1000};
for (int i = 0; i < romanChar.length; i++)
}
You could see that I have already written the method that takes the input from a user. I think I did this correctly. However, I don't know what to do for this conversion method. It says to use a single dimensional array so that's what I did over here:
char[] romanChar = {1, 5, 10, 50, 100, 500, 1000};
Those are supposed to be the values of I, V, X, L, C, D, and M. I'm really just confused as where to go from there and I would appreciate it if someone can help me out.

The Roman numeration is non-positional, meaning that the value of the digits does not depend on their position and you can ignore the latter. Then it suffices to add the values of all digits.
There is an exception anyway: if a digit immediately precedes a digit of a higher value, then it is subtracted instead of added.
So the processing is simply:
Clear an accumulator.
Read the digits from left to right. For new every digit, convert it to its value and add it to the accumulator. In the end the accumulator contains the number value.
To handle the exception, you can use the following trick:
Use a variable that holds the value of the previous digit (initially set to the value of M);
when the current digit has a higher value than the previous, you must correct the accumulator by subtracting twice the value of the previous.
Programmatically:
( Initialize )
Prv= 1000
Acc= 0
Loop:
( Accumulate )
Cur= Lookup(Digit[i])
Acc+= Cur
( Adjust for inversions )
if Prv < Cur -> Acc-= 2 * Prv
Prv= Cur
For instance, CXIX gives
Prv Cur Acc
C 1000 100 100
X 100 10 110
I 10 1 111
X 1 10 121-2*1 = 119

If I were you, I would begin by taking one baby step at a time. For example, if the only input I have to worry about is "I", then what? That is trivial of course.
Next, if the input is "II", then what? This suggests that I need to process the input one character at a time. Both the "I"s are equal to one each, and the result is the sum of the two. That means, I must have a "result" or some such variable, initialized to zero, and then for each character from the input string (I, then I), convert that to its numeric value (1, and then 1), add them up and return the value.
This logic works well for "III" also.
But then you face your first challenge with "IV". That is not trivial, specially if you are new to such an algorithm. Let me keep it aside, with a note that that is tough so will deal with this later.
The values "V", "VI", "VII", "VIII" all work fine with the above logic.
But then again I would be stuck with "IX". Similar to "IV" above. Maybe I have an idea about these two now, but then, maybe I'll still keep both these aside for the time being.
This works fine for "X", "XI", "XII", "XIII", and then again problem with "XIV".
I'll resist the temptation to solve the problems of "IV", "IX", "XIV" so that you can try them yourself; remember these are non-trivial, at least compared to what I have written above. Try it out.
So you see, incremental addition works well, but reduction is an unresolved problem.
Hope this helps.

Related

How to convert int value 09 to char array as {'0','9'}?

I am working on the problem to find the next greatest number with the same set of digits.
For this I take a integer value input from the user and I want to convert to char array or int array so that I can access individual digits.
But when I take
int value=09 as the input and convert to char array it gives only 9 as it considers it to be octal value. How can I overcome this ?
it is not possible in java to take the int values with leading zeros.
so for the value with leading zeros take it in string format.
but we can insert zeros
int n=7;
String str=String.format("%04d", n); //4 denotes the size of the string
System.out.println(str); // o/p->0007
It is not possible convert a 09 int value to a String of 9 since the value 09 can not be stored in an int.
int is not capable of storing trailing zeros.
Take this sample.
int foo = Integer.valueOf("09");
System.out.println(foo);
Output
9
So to solve your problem you should get a String from the user, validate it and parse it to an Integer[].
Solution
public Integer[] parseToInteger(String number) {
return Arrays.asList(number.toCharArray())
.stream()
.map(c -> Integer.valueOf(c.toString()))
.toArray(size -> new Integer[size]);
}
Now you have an Array of Integer.
Since leading 0's are dropped from integers there is no reason to support assigning such a value to an int.
If I want to convert 9 to '9' I usually just add '0' to it.
You can also do the following:
char c = Character.forDigit(9,10);
If you have a string of characters, you can do the following:
String str = "09";
List<Character> chrs =
str.chars().mapToObj(a -> Character.valueOf((char) a))
.collect(Collectors.toList());
System.out.println(chrs);
Prints
[0,9]
You are asking how to parse a number starting with a leading zero, but I get the feeling that you are actually on the worng track given the problem you are trying to resolve. So let's take one step backward, and lets make sure I understand your problem correctly.
You say that you have to find the "next greatest number with the same set of digits". So you are playing "Scrabble" with digits, trying to find the smalest number composed with the same digits that is strictly greater to the original number. For example, given the input "09", you would output "90", and for "123", you would output "132". Is that right? Let assume so.
Now, the real challenge here is how to determine the smalest number composed with thise digits that is stricly greater to the original number. Actually, there's a few possible strategies:
Enumerate all possible permutations of those digits, then filter out those that are not strictly greater to the original number, and then, among the remaining values, find the smallest value. That would be a very innefficient strategy, requiring both disproportionate memory and processing power. Please, don't consider this seriously (that is, unless you are actually coding for a Quantum Computer ;) ).
Set a variable to the initial number, then iteratively increment that variable by one until you eventually get a number that is composed of the same digits as the original values. That one might look simple to implement, but it actually hides some complexities (i.e. determining that two numbers are composed from the same digits is not trivial, special handling would be required to avoid endless loop if the initial number is actually the greatest value that can be formed with those digits). Anyway, this strategy would also be rather innefficient, requiring considerable processing power.
Iterate over the digits themselves, and determine exactly which digits have to be swapped/reordered to get the next number. This is actually very simple to implement (I just wrote it in less that 5 minutes), but require some thinking first. The algorithm is O(n log n), where n is the length of the number (in digits). Take a sheet of paper, write example numbers in columns, and try to understand the logic behind it. This is definitely the way to go.
All three strategies have one thing in common: they all require that you work (at some point at least) with digits rather than with the number itself. In the last strategy, you actually never need the actual value itself. You are simply playing Scrabble, with digits rather than letters.
So assuming you indeed want to implement strategy 3, here is what your main method might looks like (I wont expand more on this one, comments should be far enough):
public static void main(String[] args) {
// Read input number and parse it into an array of digit
String inputText = readLineFromUser();
int[] inputDigits = parseToDigits(inputText);
// Determine the next greater number
int[] outputDigits = findNextGreaterNumber(inputDigits);
// Output the resulting value
String outputText = joinDigits(outputDigits);
println(outputText);
}
So here's the point of all this discussion: the parseToDigits method takes a String and return an array of digits (I used int here to keep things simpler, but byte would actually have been enough). So basically, you want to take the characters of the input string, and convert that array to an array of integer, with each position in the output containing the value of the corresponding digit in the input. This can be written in various ways in Java, but I think the most simple would be with a simple for loop:
public static int[] parseToDigits(String input) {
char[] chars = input.toCharArray();
int[] digits = new int[chars.length];
for (int i = 0 ; i < chars.length ; i++)
digits[i] = Character.forDigit(chars[i], 10);
return digits;
}
Note that Character.forDigit(digit, radix) returns the value of character digit in base radix; if digit is not valid for the given base, forDigit returns 0. For simplicity, I'm skipping proper validation checking here. One could consider calling Character.isDigit(digit, radix) first to determine if a digit is acceptable, throwing an exception if it is not.
As to the opposite opperation, joinDigits, it would looks like:
public static String joinDigits(int[] digits) {
char[] chars = new char[digits.length];
for (int i = 0 ; i < digits.length ; i++)
chars[i] = Character.digit(digits[i], 10);
return new String(chars);
}
Hope that helps.

trying to perform arithmetic operations on numbers expressed as a character string

I am obviously new to java. I have this assignment where I am supposed to write a program which performs arithmetic operations on numbers expressed as a character string.
I don't know where to start. I have tried googling, looking through my book, big java, in the relevant sections but can't seem to find helpful information.
I found a program that have completed the same assignment but I want to learn write my own and understand how to go about.
I can show you one of the methods that he used.
I have bolded a few comments where I get confused.
public static String add(String num1, String num2) {
while (num1.length() > num2.length()) {
num2 = "0" + num2;
}
while (num1.length() < num2.length()) {
num1 = "0" + num1;
}
int carry = 0; // whats the point of this?
String result = "";
// look at the for loop bellow. I don't understand why he is converting the strings to ints this
// way? this doesn't even return the correct inputed numbers?
for (int i = 1; i <= num1.length(); i++) {
int digit1 = Character.getNumericValue(num1.charAt(num1.length() - i));
int digit2 = Character.getNumericValue(num2.charAt(num2.length() - i));
int sum = digit1 + digit2 + carry;
carry = sum / 10;
result = (sum % 10) + result;
// why is he dividing the sum with 10? If the user inputs a 5, would't the result become 0.5
// which isn't a valid int value? this line is also confusing
}
if (carry > 0) {
result = carry + result;
}
return result;
}
Any explanation or even guidance to a page where I am trying to do is explained would be very appreciated.
I found a program that have completed the same assignment but I want to learn write my own and understand how to go about.
That is the right idea. I suggest that you stop looking at the code that you found. (I'm sure that your teachers don't want you to look up the answers on the internet, and you will learn more from your homework if you don't do it.)
So how to proceed?
(I am assuming that you are supposed to code the methods to do the arithmetic, and not just convert the entire string to a primitive number or BigInteger and use them to do the arithmetic.)
Here's my suggested approach:
What you are trying to program is the equivalent of doing long addition with a pencil and paper. Like you were taught in primary school. So I suggest that you think of that pencil-and-paper procedure as an algorithm and work out how to express it as Java code. The first step is to make sure that you have the steps of this algorithm clearly in your head.
Try to break the larger problem into smaller sub-problems. One sub-problem could be how to convert a character representing a decimal digit into an integer; e.g. how to convert '1' to 1. Next sub-problem is adding two numbers in the range 0 to 9 and dealing with the "carry". A final sub-problem is converting an integer in the range 0 to 9 into the corresponding character.
Write sample Java code fragments for each sub-problem. If you have been taught about writing methods, some of the code fragments could be expressed as Java methods.
Then you assemble the solutions to the sub-problems into a solution for the entire problem. For example, adding two (positive!) numbers represented as strings involves looping over the digits, starting at the "right hand" end.
As part of your program, write a collection of test cases that you can use to automate the checking. For example:
String test1 = add("8", "3");
if (!test1.equals("11")) {
System.out.println("test1 incorrect: expected '11' go '" +
test1 + "'");
}
Hints:
You can "explode" a String to a char[] using the toCharArray method. Or you could use charAt to get characters individually.
You can convert between a char representing a digit and an int using Character methods or with some simple arithmetic.
You can use + to concatenate a string and a character, or a character and a string. Or you can use a StringBuilder.
If you need to deal with signed numbers, strip off and remember the sign, do the appropriate computation, and put it back; e.g. "-123 + -456" is "- (123 + 456)".
If you need to do long multiplication and long division, you can build them up from long addition and long subtraction.
You can convert a number in String format to a number in numeric format by “long n = Long. parseLong(String)” or “Long n = Long.valueOf(String)”. Then just add 2 long variables using a + sign. It will throw NumberFormatException if the String is not a number but a character. Throw that exception back to the caller.
The first part of the code pads both numbers to equal lengths.
e.g. "45" + "789" will be padded to "045" + "789"
The for loop evaluates one character at a time, starting from the right hand most.
iteration 1 -> (right most)
5 + 9 -> 14
when you divide an integer with another integer, you will always get an integer.
hence carry = 14/10 = 1 (note: not 1.4, but 1, because an int cannot have decimal places)
and the remainder is 14 % 10 = 4 (mod operation)
we now concatenate this remainder into "result" (which is "" empty)
result = (14%10)+ result; // value of result is now "4"
iteration 2 -> (second right most)
4+8 + (carry) = 4 + 8 + 1 = 13
same thing, there is a carry of 13/10 = 1
and the remainder is 13%10 = 3
we concatenate the remainder into result ("4")
result = (13%10) + result = 3 +"4" = "34"
iteration 3->
0 + 7 + 1 = 8
this time 8/10 will give you 0 (hence carry = 0)
and 8%10 will give a remainder of 8.
result = 8 + "34" = "834"
after all the numbers have been evaluated, the code checks if there are anymore carry. if the value is more than 0, then that value is added to the front of the result.

Issues With length() And Multiples Of 3

If you get the length of a String using length(), the String always being multiples of 3 (in my case: "1.02.03.04.05.06.07.0 etc.").
Each 3 characters representing a letter, with .1 indicating a capital letter.
How do you use the length to find how many sequences of three there are in the String, for each instance of said String (each time being another multiple of 3)?
Edit:
Yes to Burrito's question, I am looking to find the number of 3 character blocks in each unique String.
It's pretty simple. Next time please show the working of your code.
public int findMultiplesOf3(String value)
{
return (value.length()/3);
}
Edit
Any length of the string which is less than 3 or not divisible by 3, the return value will only be a whole number. (For Ex 22/3 = 7.333 But the return value would be 7) Since we are returning an int (integer) value in the function header.

Java reading .txt file to array

I've been trying to workout this excersise all day, but not having any luck. Thanks in advance for any help.
Here's the problem
The approach you are to implement is to store each integer in an array
of digits, with one digit per array element. We will be using arrays
of length 50, so we will be able to store integers up to 50 digits
long. We have to be careful in how we store these digits. Consider,
for example, storing the numbers 38423 and 27. If we store these at
the “front” of the array with the leading digit of each number in
index 0 of the array, then when we go to add these numbers together,
we’re likely to add them like this:
38423
27
To simulate this right-shifting of values, we will store each value as
a sequence of exactly 50 digits, but we’ll allow the number to have
leading 0’s. For example, the problem above is converted into:
0000000000000000000038423
0000000000000000000000027
Now the columns line up properly and we have plenty of space at the
front in case we have even longer numbers to add to these.
The data for your program will be stored in a file called sum.txt.
Each line of the input file will have a different addition problem for
you to solve. Each line will have one or more integers to be added
together. Take a look at the input file at the end of this write-up
and the output you are supposed to produce. Notice that you produce a
line of output for each input line showing the addition problem you
are solving and its answer. Your output should also indicate at the
end how many lines of input were processed. You must exactly reproduce
this output.
You should use the techniques described in chapter 6 to open a file,
to read it line by line, and to process the contents of each line. In
reading these numbers, you won’t be able to read them as ints or longs
because many of them are too large to be stored in an int or long. So
you’ll have to read them as String values using calls on the method
next(). Your first task, then, will be to convert a String of digits
into an array of 50 digits. As described above, you’ll want to shift
the number to the right and include leading 0’s in front. The String
method charAt and the method Character.getNumericValue will be helpful
for solving this part of the problem.
You are to add up each line of numbers, which means that you’ll have
to write some code that allows you to add together two of these
numbers or to add one of them to another. This is something you
learned in Elementary School to add starting from the right, keeping
track of whether there is a digit to carry from one column to the
next. Your challenge here is to take a process that you are familiar
with and to write code that performs the corresponding task.
Your program also must write out these numbers. In doing so, it should
not print any leading 0’s. Even though it is convenient to store the
number internally with leading 0’s, a person reading your output would
rather see these numbers without any leading 0’s.
You can assume that the input file has numbers that have 50 or fewer
digits and that the answer is always 50 digits or fewer. Notice,
however, that you have to deal with the possibility that an individual
number might be 0 or the answer might be 0. There will be no negative
integers in the input file.
You should solve this problem using arrays that are exactly 50 digits
long. Certain bugs can be solved by stretching the array to something
like 51 digits, but it shouldn’t be necessary to do that and you would
lose style points if your arrays require more than 50 digits.
The choice of 50 for the number of digits is arbitrary (a magic
number), so you should introduce a class constant that you use
throughout that would make it easy to modify your code to operate with
a different number of digits.
Consider the input file as an example of the kind of problems your
program must solve. We might use a more complex input file for actual
grading.
The Java class libraries include classes called BigInteger and
BigDecimal that use a strategy similar to what we are asking you to
implement in this program. You are not allowed to solve this problem
using BigInteger or BigDecimal. You must solve it using arrays of
digits.
Your program should be stored in a file called Sum.java.
Input file sum.txt
82384
204 435
22 31 12
999 483
28350 28345 39823 95689 234856 3482 55328 934803
7849323789 22398496 8940 32489 859320
729348690234239 542890432323 534322343298
3948692348692348693486235 5834938349234856234863423
999999999999999999999999 432432 58903 34
82934 49802390432 8554389 4789432789 0 48372934287
0
0 0 0
7482343 0 4879023 0 8943242
3333333333 4723 3333333333 6642 3333333333
Output that should be produced
82384 = 82384
204 + 435 = 639
22 + 31 + 12 = 65
999 + 483 = 1482
28350 + 28345 + 39823 + 95689 + 234856 + 3482 + 55328 + 934803 = 1420676
7849323789 + 22398496 + 8940 + 32489 + 859320 = 7872623034
729348690234239 + 542890432323 + 534322343298 = 730425903009860
3948692348692348693486235 + 5834938349234856234863423 = 9783630697927204928349658
999999999999999999999999 + 432432 + 58903 + 34 = 1000000000000000000491368
82934 + 49802390432 + 8554389 + 4789432789 + 0 + 48372934287 = 102973394831
0 = 0
0 + 0 + 0 = 0
7482343 + 0 + 4879023 + 0 + 8943242 = 21304608
3333333333 + 4723 + 3333333333 + 6642 + 3333333333 = 10000011364
Total lines = 14
My code thus far
public class Sum {
public static void main(String args[]) throws FileNotFoundException{
File file = new File("sum.txt");
Scanner scanner = new Scanner(file);
String[] myInts = new String[50];
int mySpot = 0;
while(scanner.hasNext()){
myInts[mySpot] = scanner.next();
mySpot++;
}
for(int i = 0; i < myInts.length; i++){
}
System.out.println(Character.getNumericValue(myInts[0]));
System.out.println(Arrays.toString(myInts));
}
}
When all else fails read the instructions:
"The approach you are to implement is to store each integer in an array of digits, with one digit per array element. We will be using arrays of length 50, so we will be able to store integers up to 50 digits long."
Tells me that this line:
String[] myInts = new String[50];
Has some significant problems.
Tip 1: Don't call it myInts when it's an array of String objects. Things are hard enough already.
Tip 2: Understand that new String[50] is not going to give you a string sized to 50 characters. It's going to give you space to store references to 50 string objects.
Tip 3: Understand that each line of your input can be solved separately so there is no need to remember anything from the lines you've solved before.
Tip 4: Read one line at a time into String line;
Tip 5: After reading a line solve the display problem in two parts: left side and right side of ='s.
Tip 6: Left side: display the line with spaces replaced with space + space. line.replace(" "," + ");
Tip 7: Right side: use line.split(" ") to split line on space, loop the split array of strings, each of these strings is what you'll be converting to int arrays.
Tip 8: "convert a String of digits into an array of 50 digits" <- Life will be easier if you write a method that does this. Take a String. Return an int[]. private int[] makeIntArray(String num) Take care of the "right shifting/leading zero" problem here.
Tip 9: int and long aren't big enough to hold the bigger numbers so break the number String down to Strings of digits before converting to int[].
Tip 10: Read Splitting words into letters in Java
Tip 11: Read Split string into array of character strings
Tip 12: Once you have single characters you can use Integer.parseInt(singleCharString[index--]) if you broke it down to an array of strings or Character.digit( chr[index--], 10); if you broke it down to an array of characters.
Tip 13: "write some code that allows you to add together two of these numbers or to add one of them to another." Read that carefully and it tells you that you really need to declare two vars. int[] sum = new sum[SIZE]; and int[] next = new next[SIZE]; where size is private final static int SIZE = 50;
Tip 14: adding two of these int[] numbers to produce a new int[] would be another good time to make a method. int[] sum(int[] op1, int[] op2)
Tip 15: Since all our int[]'s are right shifted already and always 50 long start a loop with i at 49 and count down. result[i-1] = (op1[i] + op2[i] + carry) % 10; and carry = (op1[i] + op2[i] + carry) / 10 will come in handy. Make sure to stop the loop at 1 or [i-1] will go index out of bounds on you.
Tip 16: Test, Test, and Test again. Make small changes then test. Small change, test. Don't just type and pray. Use the debugger if you like but personally I prefer to check values like this System.out.println("line: " + line);//TODO remove debugging code
Tip #1: Initialize the array with 0. That way, when you process the file, all you have to worry about is to replace the index locations with the digits obtained from your file.
Tip #2: You have to do some repeated division by 10 and modulus operation to extract the digits from the number (or binary shift if you prefer). For example, to split the the digits from '27', you can do 27 % 10 (7) and 27 / 10 (2). The key here is to store the result as int. After all, each digit is a whole number (not a floating point number). For number of greater magnitude, you will need to discard the process digit position so that the number gets smaller. You will now when you are done when the quotient of the division is equal to zero. Therefore, you can say in pseudo-code: DIVIDE number by 10 WHILE number > 0 (something like that)
Tip #3, you will have to iterate in reverse to store the digits in the array. If the array has a length of 50, you will start with LENGTH-1 and count down to ZER0.
Tip #4: Use an array of ints not an array of Strings if the problem allows you to. Use Integer.parseInt(String s) to convert the numeric String to a primitive int.
I think the question says to read each digit into a different array of standard size while you are reading all the words into a same a same array. and it will also be good to process this line by line
something like this
Scanner scanner = new Scanner(file);
int[][] myInts = new int[wordSize][];
int mySpot = 0;
while (scanner.hasNextLine()) {
Scanner scanner1 = new Scanner(scanner.nextLine());
while (scanner1.hasNext()) {
String s = scanner1.next();
int i;
for ( i= 0; i < wordSize - s.length(); i++) {
myInts[i][mySpot] = 0;
}
i--;
for (int j=0;j < s.length(); i++,j++) {
myInts[i][mySpot] = Character.digit(s.charAt(i), 10);
}
mySpot++;
}
// do the additions here and add this line to output file
}

Java Convert from Scientific Notation to Float

I have a program that I am working on which would effectively convert binary, decimal, or hex numbers to other formats (don't ask why I'm doing this, I honestly don't know). So far I only have a binary - decimal conversion going, and it works fine however whenever the binary number entered is 8 digits or more it crashes.
As far as I can tell when I input the number 10011001 it gets translated to scientific notation and becomes 1.0011001E7 which wouldn't really be a problem, except that the way I am converting the numbers involves creating a string with the same value as the number and breaking it into individual characters. Unfortunately, this means I have a string valued "1.0011001E7" instead of "10011001", so when I cut up the characters I hit the "." and the program doesn't know what to do when I try to make calculations with that. So basically my question comes down to this, how do I force it to use the not-scientific notation version for these calculations?
Thanks for all your help, and here is the code if it helps at all:
//This Splits A Single String Of Digits Into An Array Of Individual Digits
public float[] splitDigits(float fltInput){
//This Declares The Variables
String strInput = "" + fltInput;
float[] digit = new float[strInput.length() - 2];
int m = 0;
//This Declares The Array To Hold The Answer
for (m = 0; m < (strInput.length() - 2); m++){
digit[m] = Float.parseFloat(strInput.substring(m, m + 1)); //Breaks here
}
//This Returns The Answer
return digit;
}
Just use BigDecimal
BigDecimal num = new BigDecimal(fltInput);
String numWithNoExponents = num.toPlainString();
Note here the fltInput will be automatically converted to a double.

Categories