If I have Ternary syntax like this, compiler does not throw any compilation error:
int s = 2;
Double sdf = (s > 3 ? new Double(12) : new Integer(12));
However if I have this, it is throwing compilation error:
Required type: Double Provided: Integer
Double sdf = (s > 3 ? new Integer(12) : new Integer(12));
This happens because if we use wrapped primitive values like in the question (Integer, Float, Double etc.) in a ternary operator, both values will be unboxed and coerced to a common type.
This may result in unexpected results as well.
In the first example, new Integer(12) would be converted to a double as it is the common type. Hence there are no compilation issue.
But in the second example both are Integer which is not compatible with the left hand side type Double.
Example taken from Sonar rule description S2154:
Integer i = 123456789;
Float f = 1.0f;
// Assume condition = true
Number n = (condition) ? i : f; // i is coerced to float. n = 1.23456792E8
To fix this, we need to do explicit casting:
Integer i = 123456789;
Float f = 1.0f;
// Assume condition = true
Number n = condition ? (Number) i : f; // n = 123456789
Additional suggestion: Do not use new Double() or new Integer() etc. These constructors are deprecated. Instead use valueOf method
According to the Conditional Operator ? : specification, in case if one operand is Integer and the other is Double binary numeric promotion is used to resolve the result type.
Based on the rules, in the first example, the result type is Integer but Double in the second one (unboxing + widening).
It's because internally type is pramoted. Integer can be pramoted to double. But double can't be demoted to Integer.
Pramotion happens in following way
Byte -->Short-->Interger-->Long-->Float -->Double
Related
I was going through some java interview questions MCQ where I found this code snippet, of which I didn't understand the output, though its only a 2 line code.
int a = 8;
System.out.println(((a<8)? 9.9 : (int)9));
Output is 9.0
I didn't understand why it is not 9 ?
Ternary operator has return type that is defined before the calculation of the value.
So, if the operator can return both float and int, then the both values are upcasted to the float.
Your answer is casted in this way:
(int)9 -> (int)9 -> (float)9.
Other situation: If you add float and int, you get float
int a = 2;
float b = 4.3f;
float c = a + b;
Because you are not casting all of them . you are just casting second result to int.
But don't forget first result is float so all of structure must be same type.
You need to cast all of them as same type like int or float.
int a = 8;
System.out.println(""+ (int)( (a<8)? 9.9 : 9));
output :
9
The return type of the ternary operator is determined according to quite complicated rules:
Java Language Specification. Specifically, in your case:
Otherwise, binary numeric promotion (ยง5.6.2) is applied to the operand types, and the type of the conditional expression is the promoted type of the second and third operands.
So in your case you get return type double.
The toComplie string contains all the definitions of the functions like sum, multiply, etc. appended by if ($a > 0) then (iaf:numeric-equal(iaf:numeric-multiply($b, $c), $d)) else (true())
The snippet executing this is :
XQueryExecutable queryExecutable = xqueryCompiler.compile(toCompile.toString());
XQueryEvaluator xqueryEvaluator = queryExecutable.load();
//setExternalVariables(): function used to set the variables for the test contains below line
xqueryEvaluator.setExternalVariable(new QName(memberName), value);
setExternalVariables(xqueryEvaluator,assertionExpression);
xqueryResult = xqueryEvaluator.evaluate();
Which throws an exception as below:
XPTY0004: Required item type of the first operand of '>' is numeric; supplied value has item type xs:string
Please let me know if any more information is needed to understand the question. Is this because of the else part, or something else?
EDIT:
In setExternalVariables(), I'm adding the variables using below line, using for-each loop. value variable is of type net.sf.saxon.s9api.XdmValue
xqueryEvaluator.setExternalVariable(new QName(memberName), value);
In setExternalVariables() method,
// FACT_VALUE_FORMAT:%s;%s -- where first string is value and second gives information about precision.
//current option
XdmAtomicValue atomicValue = new XdmAtomicValue(String.format(FACT_VALUE_FORMAT, fact.getValue(),getPrecision(fact.getDecimals())));
// alternative 1
atomicValue = new XdmAtomicValue(getDoubleValue(fact));
//alternative 2
atomicValue = new XdmAtomicValue(getStringValue(fact));
In getDoubleValue(),
String precision = fact.getDecimals();
BigDecimal value = new BigDecimal(fact.getValue());
if((precision != null ) && (precision.equals(INF_STRING) == false )){
if(Integer.parseInt(precision)>0){
NumberFormat nf = NumberFormat.getNumberInstance(Locale.US);
DecimalFormat df = (DecimalFormat)nf;
// If the decimal value is greater than 0, then we need the decimal precision correct to n places of decimal
df.setMaximumFractionDigits(Integer.parseInt(precision) + 1);
double doublePrecision = Math.pow(10,-Integer.parseInt(precision))/2;
df.setMaximumFractionDigits(Integer.parseInt(precision) + 1);
precision = df.format(doublePrecision);
System.out.println("doublePrecision\t:\t"+doublePrecision);
return (double) Math.round(value.doubleValue() * doublePrecision) / doublePrecision;
}else{
int scale = (int) Math.pow(10, -Integer.parseInt(precision));
System.out.println("scale\t:\t"+scale);
return (double) Math.round(value.doubleValue() * scale) / scale;
}
}
return value.doubleValue();
In getStringValue(),
String value = fact.getValue();
String decimal = fact.getDecimals();
String DOT = "\\.";
if(value.contains(".")){
final int parseInt = Integer.parseInt(decimal);
if(parseInt>0){
String[]split = value.split(DOT);
value = split[0];
if(parseInt>=value.length()){
return "0";
}
for (int i = 0; i < parseInt; i++) {
char[] array =value.toCharArray();
array[value.length()-i-1]="0".charAt(0);
value = new String(array);
}
}else{
final int parseNegativeInt = -Integer.parseInt(decimal);
String[]split = value.split(DOT);
String tempValue = split[1];
if(tempValue.length()>parseNegativeInt){
tempValue = tempValue.substring(0, parseNegativeInt);
}
value = split[0]+"."+tempValue;
}
}
return value;
Current implementation and alternative(2) does not work for the rule mentioned above, and when I'm returning double, it transforms big numbers into expression containing char E, for e.g. 5.12344E12, which fails in other rules.
Error on line 199 of module with no systemId:
FORG0001: Cannot convert string "1.089563E9" to xs:decimal: invalid character 'E'
at iaf:splitValueThreshold() (module with no systemId#20)
at iaf:numeric-equal() (module with no systemId#343)
Please suggest any other option.
Typically XPath > implicitly converts a string operand to a number, but you can force the conversion using the number() XPath function.
if (number($a) > 0) then (iaf:numeric-equal(iaf:numeric-multiply($b, $c), $d)) else (true())
Assuming you have your numeric values on the Java side as Strings in e.g. String value = "2179.125955"; then I would suggest to pass them as xs:decimals to XQuery/XPath by using new XdmAtomicValue(new BigDecimal(value)) as the value you pass to setExternalVariable e.g.
xqueryEvaluator.setExternalVariable(new QName(memberName), new XdmAtomicValue(new BigDecimal(value)));
I second Martin's suggestion (I had first overlooked BigDecimal vs. BigDecimalValue).
Some alternatives also come to my mind based on Saxon's documentation:
atomicValue = new XdmAtomicValue(
new BigDecimalValue(getDoubleValue(fact))
);
or to avoid going through doubles or BigDecimal, something like:
atomicValue = new XdmAtomicValue(
(BigDecimalValue)BigDecimalValue.makeDecimalValue(getStringValue(fact), true)
);
// potentially adding an "instance of BigDecimalValue" check in the middle
// or bypassing all checks with 'false' instead of 'true'
Note: I am not sure I fully understand the issue that arises in other rules if an xs:double is passed instead of an xs:decimal. I suspect that there may be some casting back to xs:string involved in these other rules, as this is where an E could be introduced. XPath comparisons between numeric values of any types should be seamless.
In general (but I am only guessing here as I do not know the details involved, apart from seeing usage of EBA's interval arithmetic functions in the rule), I think it is probably a nice idea to align the types used in or passed to XBRL Formula rules with the original XBRL concept types (use xs:decimal for xbrli:decimalItemType (r) or xbrli:monetaryItemType (m), but xs:double for xbrli:doubleItemType, etc), as the lexical spaces will then match those used in the XBRL instances.
I am getting the following error:
Both assertEquals(Object, Object) in Assert and assertEquals(double, double) in Assert match
For this line of code in my Junit tests, note that getScore() returns a double:
assertEquals(2.5, person.getScore());
This is my assert import:
import static org.junit.Assert.*;
What is causing this and how can I fix this?
Your getScore() returns Double, not double. Therefore compiler is confused: Should it convert both arguments to Object, or if it should convert only the Double to double?
double a = 2.0;
Double b = 2.0;
// assertEquals(a,b); // fails to compile
// the compiler is confused whether to use
assertEquals((Object) a,(Object) b); // OK
// or
assertEquals(a,(double) b); // OK
Anyway, I would set the method to return primitive type double.
If you specifically interested in using Assert.assertEquals(double, double) (the primitive version), try calling overridden method that allows deviation and setting allowed deviation to zero, like this:
assertEquals(2.5, person.getScore(), 0.0);
You might also want to have third parameter to be something other than zero if person.getScore() is allowed to be slightly different from 2.5. For example, if 2.500001 is acceptable, then your test becomes
assertEquals(2.5, person.getScore(), 0.000001);
If you specifically want to avoid casting AND use the primitive version, you can get the primitive result from a wrapper object. For example:
double a = 2.0;
Double b = 2.0;
assertEquals(a, b.doubleValue()); //Deprecated so use the one with delta
Integer c = 2;
int d = 2;
assertEquals(c.intValue(), d);
Long e = 2L;
long f = 2L;
assertEquals(e.longValue(), f);
I had the same error, I changed from this:
assertEquals("Server status code is: " + wmResp.getStatusCode() , 200, wmResp.getStatusCode());
To this
assertEquals("Server status code is: " + wmResp.getStatusCode() , Integer.valueOf(200), wmResp.getStatusCode());
This is happening because the first line compiler takes the 200 as primitive (integer not Integer class)
I am having difficulty of understanding the behavior of the java in the following scenario. For example, I have a multiply method, which simply multiplies two int value and print the result to the screen.
private static void multiply() {
int firstValue = Integer.MAX_VALUE;
int secondValue = 2; //double secondValue=2
double result = firstValue * secondValue;
System.out.println("Result is: " + result);
}
and because of the fact that Integer overflow, the result is -2. However, here the calculation result is assigned to a double, which accepts much bigger value than than multiplication of firstValue and secondValue.
My questions to this issue are;
1- Why is Integer overflow happening, although the result is assigned to a double?
2- When I change the type of secondValue to double (mentioned in the comment), the result is correct. Why do Java behave differently when the type of one of the multiplier is changed to double?
Java does not support target type casting.
private static void multiply() {
int firstValue = Integer.MAX_VALUE;
int secondValue = 2;
double one = 1.0;
double result = one * firstValue * secondValue;
System.out.println("Result is: " + result);
}
Target Type casting means casting the value of result to the type of the variable it has to be assigned to.
So it does not know that the result has to be assigned to a double variable. In this case, int is the biggest data type, so the expression is calculated in int data type.
if you multiply it with double one, the expression is calculated in double type and the answer is correct.
The result of multiplying two ints is an int, which may or may not overflow, depending on the value of the multiplication. Once this result is produced, it's only then promoted to a double, after the overflow may have occurred.
If one of the operands is a double, the result of the multiplication would be a double, which allows for a much larger range than an int.
this is expected because when you are multiplying 2 integers the result is an integer only. It works with the otherway when you use double as one of the field the result will be considerd as a double value. the receivers data type doesn't matter here
This question already has answers here:
Division of integers in Java [duplicate]
(7 answers)
Closed 8 years ago.
I tried of finding answer by googling as well as debugging variable behavior, but unfortunately I dint find any proper answer. Its a question related to Java for instance.
Question :
Why 'double' type variable behaves like 'int' type in below condition :
double PI = 22/7 which returns 3
but, double PI = 22.0/7 or 22/7.0 returns 3.14xxxxxxx ?
Help appreciated...Thanks.
Because that's how Java (and some other programming languages) have been implemented.
Since both are integers, the expected result will be an integer as well:
int/int = int
In the other hand, when one operator is double, the result will also be double
double/int = double
int/double = double
Because in java arithmetic operations output gives the result in terms of highest data type among all involved variables or constants(Applied only on primitive data types).
For example if in any arithmetic operation like below:
Scenario 1=> var1 is int, var 2 is float, var3 is double: You will get result in double
Scenario 2=> var1 is short, var2 is long and var3 is float: you will get result in float
Scenario 3=> var1 is int, var2 is long, var3 is double: you will get result in double
Note: float family data type(float & double) always dominate to int family data types even both have same size, like in case of long and float output will be in float.
Because by default in java numerals are integer data type, so, when you are doing numeric operation with integers, the result also will be integer. When you assign that integer to a double variable, it is promoted to a double, but its value is kept. So you end up with a double with the exact same value as the result integer -- in this case, 3.0.
In your first case, both are integers, so the result also an integer, and you have assigned to double. But the conversion(integer to double) happened before assignment to double.
In the second or third case, one in double, so the operation done on double, So the result also a double value.
Or 'Pi= 22D / 7D' does it too. Here 22 and 7 are declared as 'double', not 'int'.
public static void main(String[] args) {
double d = 22 / 7; // same as double d = (int)22 / (int) 7
System.out.println(d); // so prints 3.0
double dd = 22.0/7; // same as double dd = (double)22 / (int) 7
System.out.println(dd);//prints 3.14xxxx
}