I am trying to do the following math equation in Java:
(44334*(220*220))+ (81744*220) + 39416)
When I enter the same equation in WolframAlpha (or in Google) I get:
2163788696
In java I get negative number..
I have been struggling to find out why this is happening but with no luck.
I also tried saving the answer in a BigInteger, but then I get negative values because the digits are too large.
What should I do?
EDIT: To deal with the integer wrap-around, use a long:
System.out.println("Result: " +
(44334L * 220 * 220 + 81744 * 220 + 39416)); // 2163788696
The plus operator is left-associative (whether it's being used for string concatenation or addition), so if the entire arithmetic expression weren't parenthesized, it would be concatenating the results of the sub-expressions as individual strings from left to right.
The left operand determines whether + is used for string concatenation or addition. In this case, the first operand is a string, so the right side ((44334*(220*220))) is converted into a string as well. The result of the first + operator is a string and is used as the left side of another + string concatenation operation. the next operand ((81744*220)) gets converted to a string again.
You can put parentheses around the entire arithmetic expression to avoid that.
Right now, what you are doing is equivalent to:
System.out.println(("result="+(44334*220*220)) + (81744*220 + 39416) );
// = "result=2145765600" + 18023096
// = "result=214576560018023096"
Parentheses are important! Here is your code fixed:
System.out.println("result=" + (44334*220*220+ 81744*220 + 39416) );
// = "result=2163788696"
EDIT:
Also beware of automatic int casting. Use longs because your result is bigger than MAX_INT (but smaller than MAX_LONG which is 9223372036854775807).
(long)((long)44334*220*220 + (long)81744*220 + 39416)
Or put the suffix L after your numbers (so they're considered as longs).
The problem is due to the fact that the expression is evaluated from left to right. The first value is of type string, so the + operator then becomes the string concatenation operator instead of the mathmatical addition operator. The expressions (44334*(220*220)) and (81744*220) are then evaluated and converted to strings leading to an incorrect result. If you surround the entire expression with parentheses, the result is calculated properly and you see the correct result.
For the BigInteger version, try this, it will work correctly
BigInteger a = new BigInteger("44334").multiply(new BigInteger("220").multiply(new BigInteger("220")));
BigInteger b = new BigInteger("81744").multiply(new BigInteger("220"));
BigInteger c = new BigInteger("39416");
c = c.add(a).add(b);
System.out.println("resultVersA="+(44334*(220*220))+ (81744*220) + 39416 );
System.out.println("resultVersB="+ c);
The result will be:
resultVersA=21457656001798368039416
resultVersB=2163788696
The problem is that the + operator in Java is overloaded. It can mean either string concatenation or numeric addition. What is going on is that some of the + operations are being treated as string concatenations rather that numerical additions.
You need to either add a set of parentheses around the expression,
System.out.println("result="+((44334*(220*220))+ (81744*220) + 39416));
or use a temporary variable.
int res = (44334*(220*220))+ (81744*220) + 39416;
System.out.println("result="+res);
"The rules" that Java uses to determine the meaning of + are roughly as follows:
If the type of the left OR right operand is String, then the + means string concatenation.
If the types of both the left AND right operands are primitive numeric types or numeric wrapper types, then the + means a numeric addition.
Otherwise this is a compilation error.
The other problem here is that 2163788696 is greater than the largest int value - 2147483647. So to get the right answer (without overflow), you need to tell Java to use long arithmetic; e.g.
System.out.println("result=" + ((44334L * (220 * 220)) + (81744 * 220) + 39416));
If you don't then result will be a negative number ... in this example.
You could also use BigInteger, but it is a bit cumbersome, and long will do just fine here.
Just put an L after every number you write.
(44334L*(220L*220L))+ (81744L*220L) + 39416L
Related
I am trying to understand how the compiler views the following print statements. It is simple yet a bit intriguing.
This prints the added value. Convincing enough.
System.out.println(1+2); //output: 3
The output from the following looks convincing as well:
System.out.println(1+2+"3");//output: 33
My question (based on the behavior above) is here.
System.out.println("1"+2+3);//Should be 15 right? NO. It is 123.
I tried few other such statements which were along the same lines. I was able to see one two clear behaviors.
If integers are at the front, without the quotes, they are added and subsequent integers are just appended as suffix to the added values from the front.
if the statement starts with string, under quotes, then all other subsequent elements get appended as suffix.
Is this somewhere in the java api docs? Or just very obvious string or add operator behavior which I am not seeing. Any of your valuable insights will be appreciated.
Here is the code snippet:
public static void main(String[] args) {
System.out.println(1+2);
System.out.println(1+2+"3");
System.out.println("1"+2+3);
System.out.println("1"+2+"3");
System.out.println("1"+2);
}
// The Console output:
// 3
// 33
// 123
// 123
// 12
I guess the Java specification explains it best:
The + operator is syntactically left-associative, no matter whether it
is determined by type analysis to represent string concatenation or
numeric addition. In some cases care is required to get the desired
result. For example, the expression:
a + b + c
is always regarded as meaning:
(a + b) + c
So, if a was a String, then it concatenates with b. The result would be of String type, hence it continues to concatenate with c.
I also found this interesting. I haven't worked too much in java recently but I found out a little bit of info that might be helpful through playing with it.
I think this has to do with automatic Type-casting that java does.
System.out.println("1"+2+3);
Prints 123 as you said. Since "1" is casted as string, Java assumes since the first one was a string, the ones following will be a string for concatenation unless otherwise noted
Although, this result does print 15 when you define the type
System.out.println("1" + (int)(2+3));
In that case, it can complete the operation before concatenating.
So I think java is assuming if the first one is a String, that the rest are going to be strings and to concatenate them.
EDIT: you can see some info about automatic type-conversion on oracle's website here
The + operator is overloaded in the compiler. If both operands are numeric, + is addition. If either or both operands are String, + is string concatenation. (If one operand is String and the other is numeric, the number is cast to a String). Finally, + binds left-to-right.
All this causes a compound formula a + b + c + ... to do addition left-to-right until it hits the first string operand, at which point it switches to string concatenation for the remainder of the formula. So...
"1" + 2 + 3 + 4 = 1234 /* cat cat cat */
1 + "2" + 3 + 4 = 1234 /* cat cat cat */
1 + 2 + "3" + 4 = 334 /* add cat cat */
1 + 2 + 3 + "4" = 64 /* add add cat */
Thats interesting part of string.
When a String is added to any other data type, the resultant value is a String.The other variable is also converted to a String and then concatenated. However, when two integers are operated with a + sign, the + acts as an addition operator and not a concatenation operator.
If the expression within the println() or print() method contains parentheses, then the value within the parentheses is evaluated first. Consider the following example:
int a = 5;
int b = 6;
System.out.println(a + b); // Output will be: 11
System.out.println("5" + "6"); // Output will be: 56
System.out.println("" + a + b); // Output will be: 56
System.out.println(5 + 6 + a + " " + b + a); // Output will be: 16 65
System.out.println("Result: " + a + b); // Output will be: 56
System.out.println("Result: " + (a + b)); // Output will be: 11
You can see the difference between last two sysout statements
I have the following factorial operator declared:
Operator factorial = new Operator("!", 1, true, Operator.PRECEDENCE_POWER + 1) {
#Override public double apply(double... args) {
final long arg = (long) args[0];
if ((double) arg != args[0]) {
throw new IllegalArgumentException("Operand for factorial has to be an integer");
}
if (arg < 0) {
throw new IllegalArgumentException("The operand of the factorial can not " +
"be " +
"less than zero");
}
double result = 1;
for (int i = 1; i <= arg; i++) {
result *= i;
}
return result;
}
};
So, it works fine when you have simple expressions such as 5! and so on, but things start to break when you try to emulate normal calculator behavior. The following example throws an IllegalArgumentException():
5!+5
Why? I guess it has something to do with 2 adjacent operators or something, since using (5!)+5 works with no issues.
This is devastating for the project I'm working on. Someone has suggested converting the operator into a function but that would take too much time. I've tried changing all the constructor parameters but none of them changed the problem.
I found a workaround that will make the factorial behave as intended. The trick is to add a second variable and make the factorial a pseudo unrary operator, so:
Instead of: 5!+5 I used: 5!(1)+5. This required no refactoring in my program, as the only change made was the way the operator was being inputted.
This way, the parser works wonderfully. You also need to change the actual Operator declaration to this:
Operator factorial = new Operator("!", 2, true, Operator.PRECEDENCE_POWER + 1) {
#Override public double apply(double... args) {
final long arg = (long) args[0];
if ((double) arg != args[0]) {
throw new IllegalArgumentException("Operand for factorial has to be an integer");
}
if (arg < 0) {
throw new IllegalArgumentException("The operand of the factorial can not " +
"be " +
"less than zero");
}
double result = 1;
for (int i = 1; i <= arg; i++) {
result *= i;
}
return result;
}
};
I suppose one should avoid using unary operators altogether when using EXP4J.
It certainly has to do with there being two operators in a row.
Or, alternatively, it has to do with EXP4J being a poor implementation of an expression parser.
Anyway you look at it, there is no simple solution using EXP4J. It is simply not up to the task of handling postfix operators. (If you were prepared to use !5 to mean "5 factorial", there wouldn't be a problem; just make sure that you give it the same precedence as the other unary prefix operators. But the fact that you don't want to use a function suggests that you don't want to change the syntax of ! either.)
The big hint is that the Operator constructor does not have any way to specify whether an operator is prefix or postfix. (! is a postfix operator, because it follows its operand, unlike, say, unary - with is prefix.)
If the expression parser doesn't know, it certainly cannot validate the input, and there's good reason to believe that it can't accurately parse it either. [Note 1] Another hint is that custom operators need to be declared as taking 1 or 2 operands, which means that a custom operator cannot act like - which has both prefix and infix syntax.
The special-case hack for unary + and - operators interacts badly with the hack which doesn't attempt to check whether a unary operator is prefix or postfix. In 5!+5, the + immediately follows an operator, which EXP4J interprets as indicating that the + is a prefix unary +. So it parses that almost as if it were (5!)(+5) except that it does not insert the implicit multiplication that it would insert if you actually wrote (5!)(+5).
So you get the exception, because you can't have two value side-by-side without an operator between them.
Actually fixing this would require quite a bit of rewriting. You might well be better off using a different expression evaluator, or throwing your own together with a standard parser generator.
I am trying to understand how the compiler views the following print statements. It is simple yet a bit intriguing.
This prints the added value. Convincing enough.
System.out.println(1+2); //output: 3
The output from the following looks convincing as well:
System.out.println(1+2+"3");//output: 33
My question (based on the behavior above) is here.
System.out.println("1"+2+3);//Should be 15 right? NO. It is 123.
I tried few other such statements which were along the same lines. I was able to see one two clear behaviors.
If integers are at the front, without the quotes, they are added and subsequent integers are just appended as suffix to the added values from the front.
if the statement starts with string, under quotes, then all other subsequent elements get appended as suffix.
Is this somewhere in the java api docs? Or just very obvious string or add operator behavior which I am not seeing. Any of your valuable insights will be appreciated.
Here is the code snippet:
public static void main(String[] args) {
System.out.println(1+2);
System.out.println(1+2+"3");
System.out.println("1"+2+3);
System.out.println("1"+2+"3");
System.out.println("1"+2);
}
// The Console output:
// 3
// 33
// 123
// 123
// 12
I guess the Java specification explains it best:
The + operator is syntactically left-associative, no matter whether it
is determined by type analysis to represent string concatenation or
numeric addition. In some cases care is required to get the desired
result. For example, the expression:
a + b + c
is always regarded as meaning:
(a + b) + c
So, if a was a String, then it concatenates with b. The result would be of String type, hence it continues to concatenate with c.
I also found this interesting. I haven't worked too much in java recently but I found out a little bit of info that might be helpful through playing with it.
I think this has to do with automatic Type-casting that java does.
System.out.println("1"+2+3);
Prints 123 as you said. Since "1" is casted as string, Java assumes since the first one was a string, the ones following will be a string for concatenation unless otherwise noted
Although, this result does print 15 when you define the type
System.out.println("1" + (int)(2+3));
In that case, it can complete the operation before concatenating.
So I think java is assuming if the first one is a String, that the rest are going to be strings and to concatenate them.
EDIT: you can see some info about automatic type-conversion on oracle's website here
The + operator is overloaded in the compiler. If both operands are numeric, + is addition. If either or both operands are String, + is string concatenation. (If one operand is String and the other is numeric, the number is cast to a String). Finally, + binds left-to-right.
All this causes a compound formula a + b + c + ... to do addition left-to-right until it hits the first string operand, at which point it switches to string concatenation for the remainder of the formula. So...
"1" + 2 + 3 + 4 = 1234 /* cat cat cat */
1 + "2" + 3 + 4 = 1234 /* cat cat cat */
1 + 2 + "3" + 4 = 334 /* add cat cat */
1 + 2 + 3 + "4" = 64 /* add add cat */
Thats interesting part of string.
When a String is added to any other data type, the resultant value is a String.The other variable is also converted to a String and then concatenated. However, when two integers are operated with a + sign, the + acts as an addition operator and not a concatenation operator.
If the expression within the println() or print() method contains parentheses, then the value within the parentheses is evaluated first. Consider the following example:
int a = 5;
int b = 6;
System.out.println(a + b); // Output will be: 11
System.out.println("5" + "6"); // Output will be: 56
System.out.println("" + a + b); // Output will be: 56
System.out.println(5 + 6 + a + " " + b + a); // Output will be: 16 65
System.out.println("Result: " + a + b); // Output will be: 56
System.out.println("Result: " + (a + b)); // Output will be: 11
You can see the difference between last two sysout statements
Why does this print 1?
import java.util.*;
import java.lang.*;
import java.io.*;
class Main
{
public static void main (String[] args) throws java.lang.Exception
{
// your code goes here
System.out.println((byte)+(short)-(int)+(long)-1);
}
}
Can we mix casting and +,- unary operators? I know that we can do casting multiple times, but why doesn't putting + ,- unary operators in between produce an error?
You are not adding nor substracting. Those + and - operators are unary sign operators.
See documentation at The Unary Operators section.
The sequence at stake:
(byte)+(short)-(int)+(long)-1
is evaluated from right to left like this:
the initial value is -1
casting to long (which is still -1)
unary + sign (still -1)
casting to int (still -1)
unary - sign (now the value is 1)
so on (the value remains 1 until the end)
These + and - are unary ones.
More specifically, it is in fact:
System.out.println((byte) (+((short) (-((int) (+((long) -1)))))));
if you remove all casting from your example, because in this case it will do nothing
System.out.println((byte)+(short)-(int)+(long)-1);
will become
System.out.println( + - + -1);
now you can see that just the operators are still there and because minus and minus are plus your result will be 1
basically you can think of it like:
var mylong = +(long)-1; <- -1
var myint = -(int)mylong; <- 1
var myshort = +(short)myint; <- 1
var mybyte = (byte)myshort; <- 1
I know we can do casting multiple times. But putting + ,- unary operators in between doesn't give error?
It is simply a consequence of the consistency of Java's grammar. When you write
+ 1
what you actually wrote is a unary numeric expression which decomposes into two parts:
the unary plus operator: +
a numeric expression, in this case the int literal 1.
Another example of a numeric expression is a cast expression (also unary):
(int) 1
Therefore you can substitute this for the original 1 above:
+ (int) 1
Repeating the same consistent process we can end up with a nested unary expression of arbitrary complexity. To return to your key question:
why?
Because Java would actually need a specific rule against such expressions.
I was going through an AP Comp Sci practice test and found the following problem:
what is the output of:
System.out.println("1" + new Integer(2) + 3);
The answer was
123,
I am confused as the new Integer(2) has not been casted into a String and therefore why does the java compiler believe that the new Integer(2) + 3 statement is a String concatenation if both parts are integers?
Addition is left associative. a + b + c == (a + b) + c
Is the answer as simple as order of operations meaning that the statement is evaluated left to right so it could read.
System.out.println("1" + new Integer(2).toString() + 3.toString());
First, as the guy points out, addition is left-associative.
Second, the overload resolution of "1" + 2 is controlled by the left operand, which is a String. That forces concatenation, and the result is "12".
Now, "12" + 3 goes through the exact same overload resolution, and you get "123".
The original question was:
System.out.println("1" + new Integer(2) + 3);
and why does that give us "123"; I assume the questioner meant rather than 6 or "15"?
Let's simplify this and remove the new Integer bit to its equivalent:
System.out.println("1" + 2 + 3);
The Java Language Specification 12 gives the answer (4.2.2):
The string concatenation operator + (ยง15.18.1), which, when given a String
operand and an integral operand, will convert the integral operand to a String
(the decimal form of a byte, short, int, or long operand, or the character
of a char operand), and then produce a newly created String that is the
concatenation of the two strings. https://docs.oracle.com/javase/specs/
The 15.18.1 section is even more clear:
The additive operators have the same precedence and are syntactically left-associative
(they group left-to-right).
If the type of either operand of a + operator is String, then the operation is string
concatenation. https://docs.oracle.com/javase/specs/
So, since the operator + is used in both cases, it evaluates left-to-right, whether it is concatenation or addition, as stated in 15.18.1 and as other answerers have stated. The first operand "1" is a string and the second an integer 2, so according to the above rule, the integer 2 is converted to a string "2" and the plus is interpreted as concatenation, giving us a string "12". Then it has a string "12" and an integer 3, so the integer 3 is converted according to the above rule and the + is again interpreted as concatenation and we get a string "123".
If they had put parentheses around the 2 + 3:
System.out.println("1" + (2 + 3));
That, obviously, would force the 2 + 3 to be evaluated first. They are both integers, so you get an integer 5. Then we would have "1" + 5, which is a string plus an integer, so the integer is converted to a string "5" and they are concatenated, yielding "15".
If they had changed the order like this:
System.out.println(2 + 3 + "1");
Then, the 2 + 3 would be done first in accordance with the left-to-right rule, and since they are both integers, + would mean addition and that would yield an integer 5. Then we would have operators integer 5 and a string "1". According to the above rule, the integer 5 is converted to a string 5 and the + is interpreted as concatenation and we get a string "51".
So this all boils down to order of operations, the fact that all of these operations are really binary (you only take two at a time), and, when using a plus sign, if one operand is a string, the other is changed to a string if it is not already one, the plus sign is interpreted as concatenation, and the result is a string.