Is there a checkstyle rule that will catch something like this:
double result = someInt / someOtherInt;
result is double (so clearly fractions are desired) yet the right-hand side would do integer division (rounding down).
Does something like this exist?
No, but findbugs can:
ICAST: Integral division result cast to double or float (ICAST_IDIV_CAST_TO_DOUBLE)
This code casts the result of an integral division (e.g., int or long division) operation to double or float. Doing division on integers truncates the result to the integer value closest to zero. The fact that the result was cast to double suggests that this precision should have been retained. What was probably meant was to cast one or both of the operands to double before performing the division.
There is nothing like this currently in Checkstyle.
You can always create your own check, but tracking variables may not come easy. See https://checkstyle.org/writingchecks.html
Also, Checkstyle isn't type aware tool. Knowing the actual type of the variables/fields may be impossible for it to know in certain situations. See https://checkstyle.org/writingchecks.html#Limitations
Related
I am trying to get exact calculated value (in my case it should be 66.66... not 66.0) but it prints 66.0
If I will get 66.66 then I can use Math.round(66.66) so that I will get 67
Below code after execution should return 66.66 but it returns 66.0
double d = (2*100)/3
Please suggest..
Regards
(2*100)/3 performs integer multiplication and division, which results in an integer.
You need to force floating point calculation by changing one of the operands to an double (or float):
double d = (2.0*100)/3
As other answers suggested , you can provide at least one floating number. Or if you don't want to change the numbers, you can add cast to the numerator
double d= (double)(2*100)/3;
System.out.println(d);
prints
66.66666666666667
As Eran says it's your expression perform integer arithmetic you need to perform like
double d = (double) (2*100)/3;
if needs format the result.
You are using all int values in your arithmetic operation so final result will always be int and when you put it into a double then it becomes 66.0. But since original result is int, so you loose precision.
You can use double d = (2.0*100.0)/3.0; or have at least one value with decimal point, so that you can get expected decimal points.
Number after decimal point is commonly known as precision. So, the issue which you talked about is commonly known as floating-point imprecision, and in your case you can call it as double-point imprecision.
Rule of thumb:
If either is of type double, the other is converted to double for arithmetic operation and final result will be a double.
Otherwise, if either is a float, the other is converted to float for arithmetic operation and final result will be a float.
Otherwise, if either is of type long, the other is converted to long for arithmetic operation and final result will be a long.
Otherwise, both operands are converted to int for arithmetic operation and final result will be a int.
A.) Does precision loss happens when one converts a float to a double in Java ?
B.) If I typecast a float to a float does that result in any precision loss or does Java simply intelligently ignores/skips such kind of typecasting ?
Question A is covered by the Java Language Specification, Widening Primitive Conversion.
"Conversions widening from float to double in strictfp expressions also preserve the numeric value exactly; however, such conversions that are not strictfp may lose information about the overall magnitude of the converted value."
The non-strictfp issue relates to numbers with extreme exponent values. The issue is discussed in FP-strict Expressions.
"Within an FP-strict expression, all intermediate values must be elements of the float value set or the double value set, implying that the results of all FP-strict expressions must be those predicted by IEEE 754 arithmetic on operands represented using single and double formats. Within an expression that is not FP-strict, some leeway is granted for an implementation to use an extended exponent range to represent intermediate results; the net effect, roughly speaking, is that a calculation might produce "the correct answer" in situations where exclusive use of the float value set or double value set might result in overflow or underflow."
If you want to be sure that conversions from float to double will be exact, use strictfp.
Question B is a question about Identity Conversions. I'm not sure whether an identity conversion can trigger a change in value set, involving the same strictfp vs. non-strict issue as for Question A.
Assume a double is a 64-bit bucket and a float a 32-bit bucket. If you empty the contents of a float into the double-bucket surely it will fit with more space to spare. However converting from double to float won't be the same because the float-bucket is just too small to hold the bigger content of a double. In case of float to float, they are all of the same size so you surely won't lose nothing and will fit perfectly into each other's buckets.
I can easily read 2e15 as "two quadrillion" at a glance, but for 2000000000000000 I have to count the zeroes, which takes longer and can lead to errors.
Why can't I declare an int or long using a literal such as 2e9 or 1.3e6? I understand that a negative power of 10, such as 2e-3, or a power of 10 that is less than the number of decimal places, such as 1.0003e3, would produce a floating point number, but why doesn't Java allow such declarations, and simply truncate the floating-point part and issue a mild warning in cases where the resulting value is non-integral?
Is there a technical reason why this is a bad idea, or is this all about type-safety? Wouldn't it be trivial for the compiler to simply parse a statement like
long x = 2e12 as long x = 2000000000000 //OK for long
and int y = 2.1234e3 as int y = 2123.4 //warning: loss of precision
It's because when you use the scientific notation you create a floating point number (a double in your example). And you can't assign a floating point to an integer (that would be a narrowing primitive conversion, which is not a valid assignment conversion).
So this would not work either for example:
int y = 2d; //can't convert double to int
You have a few options:
explicitly cast the floating point to an integer: int y = (int) 2e6;
with Java 7+ use a thousand separator: int y = 2_000_000;
Because it's a shortcoming of Java.
(Specifically, there is clearly a set of literals represented by scientific notation that are exactly represented by ints and longs, and it is reasonable to desire a way to express those literals as ints and longs. But, in Java there isn't a way to do that because all scientific notation literals are necessarily floats because of Java's language definition.)
You are asking about the rules on writing a integer literals. See this reference:
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
The capability to use scientific notation as an integer literal might make things easier indeed but has not been implemented. I do not see any technical reason that would prevent such a feature from being implemented.
I notice some issues with the Java float precision
Float.parseFloat("0.0065") - 0.001 // 0.0055000000134110451
new Float("0.027") - 0.001 // 0.02600000000700354575
Float.valueOf("0.074") - 0.001 // 0.07399999999999999999
I not only have a problem with Float but also with Double.
Can someone explain what is happening behind the scenes, and how can we get an accurate number? What would be the right way to handle this when dealing with these issues?
The problem is simply that float has finite precision; it cannot represent 0.0065 exactly. (The same is true of double, of course: it has greater precision, but still finite.)
A further problem, which makes the above problem more obvious, is that 0.001 is a double rather than a float, so your float is getting promoted to a double to perform the subtraction, and of course at that point the system has no way to recover the missing precision that a double could have represented to begin with. To address that, you would write:
float f = Float.parseFloat("0.0065") - 0.001f;
using 0.001f instead of 0.001.
See What Every Computer Scientist Should Know About Floating-Point Arithmetic. Your results look correct to me.
If you don't like how floating-point numbers work, try something like BigDecimal instead.
You're getting the right results. There is no such float as 0.027 exactly, nor is there such a double. You will always get these errors if you use float or double.
float and double are stored as binary fractions: something like 1/2 + 1/4 + 1/16... You can't get all decimal values to be stored exactly as finite-precision binary fractions. It's just not mathematically possible.
The only alternative is to use BigDecimal, which you can use to get exact decimal values.
From the Java Tutorials page on Primitive Data Types:
A floating-point literal is of type float if it ends with the letter F or f; otherwise its type is double and it can optionally end with the letter D or d.
So I think your literals (0.001) are doubles and you're subtracting doubles from floats.
Try this instead:
System.out.println((0.0065F - 0.001D)); // 0.005500000134110451
System.out.println((0.0065F - 0.001F)); // 0.0055
... and you'll get:
0.005500000134110451
0.0055
So add F suffixes to your literals and you should get better results:
Float.parseFloat("0.0065") - 0.001F
new Float("0.027") - 0.001F
Float.valueOf("0.074") - 0.001F
I would convert your float to a string and then use BigDecimal.
This link explains it well
new BigDecimal(String.valueOf(yourDoubleValue));
Dont use the BigDecimal double constructor though as you will still get errors
Long story short if you require arbitrary precision use BigDecimal not float or double. You will see all sorts of rounding issues of this nature using float.
As an aside be very careful not to use the float/double constructor of BigDecimal because it will have the same issue. Use the String constructor instead.
Floating point cannot accurately represent decimal numbers. If you need an accurate representation of a number in Java, you should use the java.math.BigDecimal class:
BigDecimal d = new BigDecimal("0.0065");
I have to do an operation with integers, very simple:
a=b/c*d
where all the variables are integer, but the result is ZERO whatever is the value of the parameters. I guess that it's a problem with the operation with this type of data (int).
I solved the problem converting first in float and then in integer, but I was wondering if there is a better method.
The / operator, when used with integers, does integer division which I suspect is not what you want here. In particular, 2/5 is zero.
The way to work around this, as you say, is to cast one or more of your operands to e.g. a float, and then turn the resulting floating point value back into an integer using Math.floor, Math.round or Math.ceil. This isn't really a bad solution; you have a bunch of integers but you really do want a floating-point calculation. The output might not be an integer, so it's up to you to specify how you want to convert it back.
More importantly, I'm not aware of any syntax to do this that would be more concise and readable than (for example):
a = Math.round((float)b / c * d)
In this case, you can reorder the expression so division is performed last:
a = (b*d)/c
Be careful that b*d won't ever be large enough to overflow an int. If it might be, you could cast one of them to long:
a = (int)(((long)b*d)/c)