first post here. I have an assignment to convert from hex to decimal, including other conversions but this one has me stumped...
So the hex values I need to convert are 12345678, 2A3DF8A7, 00FF00FF. 00FF00FF works fine, it's the number values that are giving me trouble.
I know you're supposed to multiply the digit by 16^n, but for some reason I'm getting values that are way too high even though I think I am doing it right. Obviously not since it's not working. Help would be greatly appreciated!
My code has changed throughout the last hour messing with it, but it's the last "else" now that is the problem.
public void toDec()
{
dec = 0;
for (int j = 0, i = 7; j < hex.length(); j++){
if (hex.charAt(j) == 'A') {
dec += (10 * (int)Math.pow(16, i));
}
else if (hex.charAt(j) == 'B') {
dec += (11 * (int)Math.pow(16, i));
}
else if (hex.charAt(j) == 'C') {
dec += (12 * (int)Math.pow(16, i));
}
else if (hex.charAt(j) == 'D') {
dec += (13 * (int)Math.pow(16, i));
}
else if (hex.charAt(j) == 'E') {
dec += (14 * (int)Math.pow(16, i));
}
else if (hex.charAt(j) == 'F') {
dec += (15 * (int)Math.pow(16, i));
}
else if (hex.charAt(j) == '0') {
dec = dec;
}
else {
dec += ((int)hex.charAt(j)) * ((int)Math.pow(16, i));
}
i--;
}
}
Casting char to an int is the problem here - instead of int value, representing specific digit, you get char code.
Just give it a try: System.out.println((int) '5');
The easiest way to solve that would be (hex.charAt(j) - '0').
Your problem is in your else clause, handling the digits 1 to 9.
The problem is that you're confusing the digits with the characters representing them. For example, the digit 1 is represented by the character '1', which has a character code of 49. So, when you cast a '1' character to int in your else clause (i.e. (int)hex.charAt(j)), what you get back is it's character code of 49, not 1.
Now, the easy (and idiomatic) way to fix this is to use integer math on your characters. For example, use hex.charAt(j) - '0' instead of (int)hex.charAt(j). This works because the characters '0' through '9' are assigned consecutive character codes 48 through 57, so (for example) subtracting the character code for '0' (which is 48) from the character code for '1' (which is 49) returns the actual digit value, since 49 - 48 = 1. The same works for the other digits, too: '5' - '0' is equivalent to 53 - 48, which is (of course) equal to 5.
Even better, the same approach also works for your other hexadecimal characters too! For example, if you do 'C' - 'A' + 10, you'll get the result 12 (which is the hexadecimal value of the letter C).
Related
I have been trying to understand a code of a program that converts decimal to the base of 7. I do understand everything until the point where the given loop begins. Could you explain me that?
do {
char digit = (char) (number % 7 + '0');
s = digit + s;
number /= 7;
} while (number > 0);
System.out.print(s);
From the comments, it seems it is mainly this line
char digit = (char) (number % 7 + '0');
you do not understand.
It converts the value of number % 7, which is an integer, to a digit as a character. The character codes of the digits are successive with 48 for '0', 49 for '1', and so on. Adding a number between 0 and 9 (inclusive) to the character code of '0' gives you the character code of the corresponding digit.
do {
} while (number > 0);
is a normal do-while-loop which is only slightly different to a while-loop in the way that it checks the while-condition only after the body has been evaluated, not before as a while-loop would do.
char digit = (char) (number % 7 + '0');
is converting a digit from a number to a character. '0' needs to be added to the number because the number 0 is not the same as the character '0' (see ASCII tables for example) and therefore adding the character offset '0' to a digit (e. g. 7) will result in the number representing the character '7' and not the symbol at position 8 (0-based) in the character set.
What you're missing is, I think, the fact that char(7) doesn't give 7 as a character but rather the 7th character in the ASCII table.
Doing number modulo 7 will give you a number between 0 and 6, the rest of the division by 7. But if you want to convert it to a char, you need to find that number's index in the ASCII table. That index will be zero's index plus that number hence
char digit = (char) (number % 7 + '0');
Now, I'm not sure it's necessary to use char at all... You can concatenate a string with a number.
This question already has answers here:
What is an OutOfMemoryError and how do I debug and fix it
(4 answers)
Closed 5 years ago.
Hi I'm writing a program that parses a String into individual component as but when I try to test it out, I get an Out of Memory Error. I feel as if my for/while loops are infinite but I can't seem to find the reason why.
//for loop to loop through char of string
for(int i=0; i<expressionString.length(); i++) {
//cast char into ascii int
int ascii = (int) charAt(i);
//appending to token if one of singly operator symbols: *,/,(,),[,]
if(ascii == 40 || ascii == 41 || ascii == 42 || ascii == 47 || ascii == 91 || ascii == 93){
token.append((char) ascii);
tokenList.add(token.toString());
} //append if +, -
else if(ascii == 43 || ascii == 45) {
token.append((char) ascii);
//check next char if + or /, if so append to token again
int nextChar = (char) charAt(i+1);
if(nextChar == 43 || nextChar == 45) {
token.append((char) nextChar);
}
tokenList.add(token.toString());
} //appending to token if it's a num
else if ( ascii >= 48 || ascii <=57) {
token.append((char) ascii);
//check if next char is a num
while ((int) charAt(i+1) >= 48 || (int) charAt(i+1) <= 57) {
//increment i in for loop to check
i++;
token.append((int) charAt(i));
}
tokenList.add(token.toString());
}
//
}
Please let me know if this is an error with my code as I can't seem to detech where the problem is. Thank you!
As I indicated in the comments, the fact that you are appending to a StringBuilder without ever removing anything from it is dubious.
StringBuilder is simply a wrapper around a char[], which gets automatically resized when necessary to accommodate the new text that you are trying to append. You can see in the stack trace that the OOM is occurring during one of these automatic resizes.
One solution to this problem is simply to allocate a large enough buffer initially, then the resizes don't need to occur until much more text has been appended to the StringBuilder:
StringBuilder token = new StringBuilder(MAXIMUM_EXPECTED_SIZE);
The problem with this is that it may be hard to determine MAXIMUM_EXPECTED_SIZE; and moreover that you may be wasting a lot of memory most of the time, where you are appending nowhere near that amount of text to the buffer.
It seems like you don't actually want to keep the text in token once you have transferred it to tokenList. You can delete it explicitly from the buffer using:
token.delete(0, token.length());
// or
token.setLength(0);
(Actually, this doesn't delete the data, it just allows subsequent appends to overwrite it)
But this is still wasteful: you don't need the StringBuilder at all.
Consider how you handle the numbers:
if ( ascii >= 48 || ascii <=57) {
token.append((char) ascii);
//check if next char is a num
while ((int) charAt(i+1) >= 48 && (int) charAt(i+1) <= 57) {
// ^^ NB
//increment i in for loop to check
i++;
token.append((int) charAt(i));
}
tokenList.add(token.toString());
}
What you're apparently trying to do here is to append everything between the i-th character (inclusive) and the j-th character (exclusive), where j points either to the end of the string, or to a non-numeric character. So you can do that like this:
if ( ascii >= 48 || ascii <=57) {
int j = i + 1;
//check if next char is a num
while (j < expressionString.length() && charAt(j) >= '0' && charAt(j) <= '9') {
j++;
}
tokenList.add(expressionString.subString(i, j));
i = j;
}
You can do similarly for the other appending of tokens. This just cuts out the "middle man" of the StringBuilder, which obviously avoids problems with it re-allocating its internal buffer.
Here is simplified version of what you are doing in that loop.
public class Main {
public static void main(String[] args) {
String str = "ABCDE";
StringBuilder sb = new StringBuilder();
List<String> list = new ArrayList<>();
for (char c : str.toCharArray()) {
sb.append(c);
list.add(sb.toString()); // <-- Problem! This adds the *entire* contents of the StringBuilder as a new String to the list.
}
System.out.println(list);
}
}
This program prints
[A, AB, ABC, ABCD, ABCDE]
This is because each time we append a char to the StringBuilder, we then add the entire contents of the StringBuilder as a new String to the ArrayList.
Now suppose we replace "ABCDE" with a String of length 1000000, for example we change the first line to
String str = Stream.generate(() -> "A").limit(1000000).collect(Collectors.joining()); // String of length 1000000
We are now trying to create 1000000 String objects of lengths from 1 to 1000000, with predictable results.
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOfRange(Arrays.java:3664)
at java.lang.String.<init>(String.java:207)
at java.lang.StringBuilder.toString(StringBuilder.java:407)
at my_package.Main.main(Main.java:17)
How to fix it? It depends on what you are trying to do (and we don't have all the context), but I suspect you don't need both a StringBuilder and a List.
I have following code
private static int getYear(char[] charArray)
{
return (int)charArray[0] * 1000 + (int)charArray[1] * 100 + (int)charArray[2] * 10 + (int)charArray[3];
}
This excerpt calculate a number from a 4-element char array. From "2015" there is 55343.
Any suggestion?
Assuming the purpose of the exercise is not to use String and parseInt, you need to convert the characters '0' to '9' into the digits 0 to 9. This is done by subtracting the character '0', so you get:
private static int getYear(char[] charArray)
{
return (charArray[0] - '0') * 1000
+ (charArray[1] - '0') * 100
+ (charArray[2] - '0') * 10
+ (charArray[3] - '0');
}
This is because Java stores Strings in Unicode characters. Unicode is a (huge) extension of the ASCII character set.
Have a look at the ASCII printable characters on this Wikipedia page: https://en.wikipedia.org/wiki/ASCII#ASCII_printable_code_chart
As you can see, the character (glyphs) for 0 has decimal value 48, 1 is 49, ..., and 9 is 57.
So, casting a char with the character '0' to an int will yield the value 48. Then we rely on the fact that the characters '0' to '9' are consecutive, so subtracting 48 (the value of '0') will yield 0 to 9, which is what we want.
private static int getYear(char[] charArray)
{
return Integer.parseInt(String.valueOf(charArray));
}
private static int getYear(char[] charArray){
return Integer.parseInt(new String(charArray));
}
I made an app that allows the transformation from infix to postfix expressions for real numbers (included negative ones). It works perfectly except for the case when I put a negative number on the first and then I put minus another number. For example -1 - 2 or -2 + 8 - 9. It shows -1-2 and -2 8-9 +. It should be -1 2 - and -2 8 + 9 -. It's certainly a problem when the sign is -. This is a part of my code when the input char is '-'.
for (int j = 0; j < input.length(); j++) {
char ch = input.charAt(j);
if (ch == '-') {
if ((ch == input.charAt(0)) || (input.charAt(j - 1) == '(')
|| (input.charAt(j - 1) == '-'))
temp = temp + ch;
else {
output = output + temp + " ";
temp = "";
gotOper(ch, 1);
}
}
else if ..
...
}
When the app find - and it's on the first of the input or after ( or after - so it's a negative number and I put it into a temporary variable. When it's between 0 and 9 or it's ., the same thing. else, when it's and operand, I put which is in temp in output and I do operations with the Stack. I can't show the whole code, it's very long! Can someone help me please?
EDIT: I did this input = input.replaceAll("\\s+", ""); to remove all whitespaces
This part (ch == input.charAt(0)) in the second if-statement should be replaced with (j == 0). Otherwise, it will return true whenever ch == '-' if the input also starts with a '-'.
I am writing an Atoi function in Java. It runs fine for +ve integers. But what I want is when I enter a negative integer it should give me an error. So I tried including continue statement in my class Atoi. The class implemented is:
class Atoi {
int atoi(String tmp) {
int result = 0;
for (int i = 0; i < tmp.length(); i++) {
char digit = (char)(tmp.charAt(i) - '0');
if(digit == '-')
continue;
}
else {
result += (digit * Math.pow(10, (tmp.length() - i - 1)));
}
return result;
}
}
But unfortunately it gives me the negative equivalent of the character i.e for -12 it gives me 655312! Help.
EDIT: Suppose I need to check for floating point numbers what should I do? If I enter 12.1 or 123.2 it should return 12.1 and 123.2 repectively!!
Instead of continue you should give an error (throw an exception, return -1 or whatever you mean with "give an eror").
If you want to ignore the - you can change the else clause to:
result = digit + result * 10;
Quick fix for the obvious problem: the order of the logic was wrong...
Instead of
char digit = (char)(tmp.charAt(i) - '0');
if(digit=='-')
continue;
try
char origChar=tmp.charAt(i);
if(origChar=='-')
continue;
char digit = (char)(origChar - '0');
But there are two more problems:
it does not negate the value, in case of a '-' character is present!
what if this is the input string: -1-2-3-4-5? The result will be interesting! EDIT: try this input also: 'répa'... Even more interesting result!
Don't forget to test with incorrect inputs too, and as #Klaus suggested, don't hesitate to throw an exception, (preferably IllegalArgumentException) with a correct error message, if an incorrect input is given to the function...
If this is not being done as a programming exercise, there is a simpler solution:
static int atoi(String tmp)
{
int result = Integer.parseInt(tmp);
if(result >= 0) {
return result;
} else {
throw new IllegalArgumentException("Negative string "+"\"" + tmp + "\"");
}
}
Substitute the appropriate exception or other action in the negative result case. If you want to just ignore '-', as in the posted code, replace the if-then-else with:
return Math.abs(result);
This code also throws an exception for strings like "abc".
More generally, if a library method does not do exactly what you want, it is often easy to use it in a method that modifies its behavior, rather than re-writing it.
You can write code like this, of course, but you need to check that tmp is a valid number.
int atoi(String tmp) {
int result = 0;
int factor = tmp.charAt(0) == "-" ? -1 : 1;
for (int i = 0; i < tmp.length(); i++) {
if (tmp.chatAt(i) < '0' || tmp.chatAt(i) > '9')
continue;
char digit = (char)(tmp.charAt(i) - '0');
result += (digit * Math.pow(10, (tmp.length() - i - 1)));
}
return result * factor;
}
if(digit=='-')
With
(char)(tmp.charAt(i)
You're code is assuming there are no -'s
(char)(tmp.charAt(i) - '0');
Is an optimization that's blindly clamping the 'digit' variable to a number.
You need to step through what your code is actually doing, search for an ASCII chart and work through what the subtractions of '0' does ('0' == 48), so '1' (49) - '0' (48) = 1 etc...
If you don't want to convert negative numbers then simply return 0 whenever you encounter - sign instead of looping further. Put this code before the if-else block.
if(tmp.charAt(i)=='-')
return 0;