Accuracy of double equality boolean when cast from Integer/int/Long/long - java

What is the accuracy of the equality test if the below datatypes are cast to Double (the .equals() test) or to double (the == test)?
Long
long
Integer
int
If the equality test is only accurate within a range of possible Long, long, Integer or int values, what is the precise range over which this accuracy holds?
For example;
Long longTest = Long.MAX_VALUE;
Long longTest2 = Long.MAX_VALUE;
double doubleTest = (double) longTest;
double doubleTest2 = (double) longTest2;
if(doubleTest == doubleTest2) //Is this accurate?
return true;

Think about it as follows:
Both double and long occupy 64 bits storage. For float and int, it is 32.
Because there are some bits spent on the exponent, you will always be in danger of loosing precision when casting a long to a double or an int to a float.
The only save thing is int -> double.
Anyway, as to your example: the double cannot hold the Long.MAX_VALUE with absolute precision, for the reason stated above. It will be an approximation. However, the approxiamtion should be the same every time, hence your example should return true.

Although it would have been possible for the creators of Java to have defined == overloads for all combinations of numeric types so that only things with the same numeric value would compare equal [implying, for example, that there would be no float value which compares equal to 16777217], or to have forbidden the use of == on any combination of types where that operator wouldn't behave as an equivalence relation, they did neither of those those things. Instead, they decided that it should be possible to compare operands with any combination of primitive types, whether or not that is meaningful, and such comparisons should use the same implicit conversions as exist in any other context (a decision I really dislike, btw).
Consequently, a comparison between e.g. a long and a float will be performed by performing an approximate conversion to float and comparing that, without regard for whether any precision was lost in the conversion. A comparison between float and double will be done by performing an exact conversion to double and comparing that. This leads to 16777216.0f == 16777217, and 16777217 == 16777217.0, but 167772176.0f != 16777217.0. There are times when one may want to know whether the float is the best float representation of the other value, and times one may want to know whether it's an exact representation, but the type ranking in Java is inconsistent with regard to which question the == operator answers.

Several cases...
If both types are wrappers, equals is always precise - but do mind that equals is type sensitive (e.g. Integer.equals(Long) always yields false, regardless of value). Otherwise...
If one type is a wrapper and the other is primitive, the wrapper will be unboxed and the comparison is done using == semantics the same as both types were primitives from the start.
Equality for primitives (==) is precise for any integer type (byte, short, int, long) - the smaller type will be cast to the larger type, then compared. For char, its cast to the larger type but unsigned.
Equality with one operand a floating point type (float, double) the other type is cast to the floating point type and there is potentially precision lost in that case. Float can represent any integer value that has <= 24 significant bits precisely, double has 53 bits of relevant precision (its determined by the number of mantissa bits in the type, see IEEE754 for dirty details).
So basically, float == (int) N is only precise when (approx.) abs(N) <= (1 << 23), and double = (long) N when abs(N) <= (1 << 52). If there are more significant bits in the integer type, the lowermost bits are lost when the type is cast to float/resp. double. Since double has more mantissa bits than int can have significant bits, comparisions between double and int are precise in that regard.

Related

IllegalArgumentException: Bound must be positive? [duplicate]

This question already has answers here:
Int division: Why is the result of 1/3 == 0?
(19 answers)
Closed 4 years ago.
This is a basic question but I can't find an answer. I've looked into floating point arithmetic and a few other topics but nothing has seemed to address this. I'm sure I just have the wrong terminology.
Basically, I want to take two quantities - completed, and total - and divide them to come up with a percentage (of how much has been completed). The quantities are longs. Here's the setup:
long completed = 25000;
long total = 50000;
System.out.println(completed/total); // Prints 0
I've tried reassigning the result to a double - it prints 0.0. Where am I going wrong?
Incidentally, the next step is to multiply this result by 100, which I assume should be easy once this small hurdle is stepped over.
BTW not homework here just plain old numskull-ness (and maybe too much coding today).
Converting the output is too late; the calculation has already taken place in integer arithmetic. You need to convert the inputs to double:
System.out.println((double)completed/(double)total);
Note that you don't actually need to convert both of the inputs. So long as one of them is double, the other will be implicitly converted. But I prefer to do both, for symmetry.
You don't even need doubles for this. Just multiply by 100 first and then divide. Otherwise the result would be less than 1 and get truncated to zero, as you saw.
edit: or if overflow is likely, if it would overflow (ie the dividend is bigger than 922337203685477581), divide the divisor by 100 first.
In Java
Integer/Integer = Integer
Integer/Double = Double//Either of numerator or denominator must be floating point number
1/10 = 0
1.0/10 = 0.1
1/10.0 = 0.1
Just type cast either of them.
Convert both completed and total to double or at least cast them to double when doing the devision. I.e. cast the varaibles to double not just the result.
Fair warning, there is a floating point precision problem when working with float and double.
If you don't explicitly cast one of the two values to a float before doing the division then an integer division will be used (so that's why you get 0). You just need one of the two operands to be a floating point value, so that the normal division is used (and other integer value is automatically turned into a float).
Just try with
float completed = 50000.0f;
and it will be fine.
As explain by the JLS, integer operation are quite simple.
If an integer operator other than a shift operator has at least one operand of type long, then the operation is carried out using 64-bit precision, and the result of the numerical operator is of type long. If the other operand is not long, it is first widened (§5.1.5) to type long by numeric promotion (§5.6).
Otherwise, the operation is carried out using 32-bit precision, and the result of the numerical operator is of type int. If either operand is not an int, it is first widened to type int by numeric promotion.
So to make it short, an operation would always result in a int at the only exception that there is a long value in it.
int = int + int
long = int + long
int = short + short
Note that the priority of the operator is important, so if you have
long = int * int + long
the int * int operation would result in an int, it would be promote into a long during the operation int + long
As your output results a double you should cast either completed variable or total variable or both to double while dividing.
So, the correct implmentation will be:
System.out.println((double)completed/total);

Type Conversion in Java Double to Int

I am trying to convert a double value of 2147483648 to integer, After typecasting it, I get output as 2147483647, the number is reduced by 1. I know that this is happening because of overflow, but is there a way where I can convert it to int type without loosing its precision?
As aforementioned in previous answers, you can use the long primitive data type, or the BigInteger reference type. Using integral data types rather than floating points would be better for representing integers exactly.
As a side note, since Java SE 8, one can use the Integer class to use int for unsigned arithmetic. Per the Oracle doc - "Use the Integer class to use int data type as an unsigned integer". Unsigned integers have a greater maximum value than int. This question can be of use: Declaring an unsigned int in Java.
This is my first answer, hope you solved your problem! :)
I can think of 2 options.
Long
Unlike int, which is a 32-bit signed integer data type, long is a 64-bit signed integer data type. This means that the largest value it can store is 9223372036854775807. The number that you are trying to store, 2147483648, is well inside that range.
BigInteger
This is a reference type that represents an "immutable arbitrary-precision integer". You can create a BigInteger instance that represents 2147483648 by doing
new BigInteger("2147483648")
Learn more about it here: https://docs.oracle.com/javase/7/docs/api/java/math/BigInteger.html
Max Values
The maximum integer, as indicated in the Integer class by the static final int MAX_VALUE, is 2^31-1 (2,147,483,647). This value is the maximum integer as it is the largest 32-bit signed integer.
The maximum double, as indicated in the Double class by the static final int MAX_VALUE, is (2-2^(-52))(2^1023). The double data type follows the double-precision 64-bit IEEE 754 floating point format to express a wide range of dynamic numerical values.
Narrowing Primitive Conversion
In you're observation, you have a double with a value 2,147,483,648 which you attempt to convert to an integer by type casting.
double d = 2147483648;
int i = (int) d;
Casting between primitive types allows your to convert the value of one primitive type to another. Converting from a double to an integer is known as a Narrowing Primitive Conversion, wherein you:
"may lose information about the overall magnitude of a numeric value and may also lose precision and range."
The narrowing conversion of a floating-point number to an int is as follows:
If the floating-point number is NaN, the result is an int of 0.
Otherwise, if the floating-point number is not an infinity, the floating-point number is rounded to an integer value V, rounding toward zero using IEEE 754 round-toward-zero mode. If this integer value can be represented as an int, then the result is V.
Otherwise, one of the following two cases must be true: a. The value must be too small and the result is the smallest representable value of type int or b. The value must be too large and the result is the largest representable value of type int.
With the integer value of the double value larger than the Integer.MAX_VALUE, in order to allow for representation as an integer the value of Integer.MAX_VALUE is used.
Avoid Loss
To avoid the loss of precision you will need to either cast to a primitive type or a numeric Object wherein the maximum value is greater than 2147483648 (and resolution allows for accuracy to be maintained).
The long primitive type has a maximum value of 2^63-1 (9.223372e+18), which would be a good choice if you want to use numbers within the numeric integer space. Note that while the Long.MAX_VALUE is very large, Double.MAX_VALUE is MUCH larger due to the floating-point format.
double d = 2147483648;
long i = (long) d;
Converting from a double to an int will lose precision for numbers greater than Integer.MAX_VALUE or less that Integer.MIN_VALUE. There is no way to represent numbers outside that range as an int. It is mathematically impossible.
Converting from a double to an long will also lose precision. This will occur for all integers outside of Long.MIN_VALUE through Long.MAX_VALUE. But a second problem is that double itself is not able to represent all integers in that range ... so there will be loss of precision before the conversion1.
Moral:
Don't use floating point numbers if you need to represent integers precisely. Use an integral type (byte, short, char, int or long) ... or BigInteger.
1 - A double is a 64 bit IEE floating point number, which has 52 bits of precision and a sign bit. By contrast, a long has 64 bits of precision (including sign).

Java conversion code - why does the division not return the same result? [duplicate]

This question already has answers here:
Int division: Why is the result of 1/3 == 0?
(19 answers)
Closed 4 years ago.
This is a basic question but I can't find an answer. I've looked into floating point arithmetic and a few other topics but nothing has seemed to address this. I'm sure I just have the wrong terminology.
Basically, I want to take two quantities - completed, and total - and divide them to come up with a percentage (of how much has been completed). The quantities are longs. Here's the setup:
long completed = 25000;
long total = 50000;
System.out.println(completed/total); // Prints 0
I've tried reassigning the result to a double - it prints 0.0. Where am I going wrong?
Incidentally, the next step is to multiply this result by 100, which I assume should be easy once this small hurdle is stepped over.
BTW not homework here just plain old numskull-ness (and maybe too much coding today).
Converting the output is too late; the calculation has already taken place in integer arithmetic. You need to convert the inputs to double:
System.out.println((double)completed/(double)total);
Note that you don't actually need to convert both of the inputs. So long as one of them is double, the other will be implicitly converted. But I prefer to do both, for symmetry.
You don't even need doubles for this. Just multiply by 100 first and then divide. Otherwise the result would be less than 1 and get truncated to zero, as you saw.
edit: or if overflow is likely, if it would overflow (ie the dividend is bigger than 922337203685477581), divide the divisor by 100 first.
In Java
Integer/Integer = Integer
Integer/Double = Double//Either of numerator or denominator must be floating point number
1/10 = 0
1.0/10 = 0.1
1/10.0 = 0.1
Just type cast either of them.
Convert both completed and total to double or at least cast them to double when doing the devision. I.e. cast the varaibles to double not just the result.
Fair warning, there is a floating point precision problem when working with float and double.
If you don't explicitly cast one of the two values to a float before doing the division then an integer division will be used (so that's why you get 0). You just need one of the two operands to be a floating point value, so that the normal division is used (and other integer value is automatically turned into a float).
Just try with
float completed = 50000.0f;
and it will be fine.
As explain by the JLS, integer operation are quite simple.
If an integer operator other than a shift operator has at least one operand of type long, then the operation is carried out using 64-bit precision, and the result of the numerical operator is of type long. If the other operand is not long, it is first widened (§5.1.5) to type long by numeric promotion (§5.6).
Otherwise, the operation is carried out using 32-bit precision, and the result of the numerical operator is of type int. If either operand is not an int, it is first widened to type int by numeric promotion.
So to make it short, an operation would always result in a int at the only exception that there is a long value in it.
int = int + int
long = int + long
int = short + short
Note that the priority of the operator is important, so if you have
long = int * int + long
the int * int operation would result in an int, it would be promote into a long during the operation int + long
As your output results a double you should cast either completed variable or total variable or both to double while dividing.
So, the correct implmentation will be:
System.out.println((double)completed/total);

Performant way to check java.lang.Double for equality

What is the most performant way to check double values for equality.
I understand that
double a = 0.00023d;
double b = 0.00029d;
boolean eq = (a == b);
is slow.
So I'm using
double epsilon = 0.00000001d;
eq = Math.abs(a - b) < epsilon;
The problem is that Infinitest is complaning about tests taking too much time. It's not a big deal (1 sec top), but it made me curious.
Additional info
a is hard coded since it's the expected value, b is computed by
// fyi: current = int, max = int
public double getStatus()
{
double value = 0.0;
if (current != 0 && max != 0)
value = ((double) current) / max;
return value;
}
Update
java.lang.Double does it that way
public boolean equals(Object obj) {
return (obj instanceof Double)
&& (doubleToLongBits(((Double)obj).value) ==
doubleToLongBits(value));
}
so one could assume that is the best practice.
JUnit has a method of checking a Double for 'equality' with a given delta:
Assert.assertEquals(0.00023d, 0.00029d, 0.0001d);
See this API documentation.
As noted in the comments, JUnit actually most likely is slower than comparing manually with a given delta. JUnit first does a Double.compare(expected, actual) followed (if not equal) by a Math.abs(expected - actual) <= delta.
Hopefully this answer still is useful for people not aware that JUnit actually provides a way for inexact Double equality testing.
Actually, comparing two float/double values for equality is a bad practice in itself, because floating point numbers suffer from rounding errors.
Two numbers which would be equal in symbolic maths may be different to the computer, depending on how they are computed.
The best practice is the second option you used: Math.abs(a - b) < epsilon.
I understand it may be slower than you'd like, but it's the right way to do it. Bitwise comparison may result in two numbers being considered as different even though they're the same, from the point of view of the application (they would be equal if you had computed them by hand, but they are bitwise different due to rounding errors).
java.lang.Double
As shown in the question java.lang.Double.equals() calls public static long doubleToLongBits(double value), which
/**
* Returns a representation of the specified floating-point value
* according to the IEEE 754 floating-point "double
* format" bit layout.
and then checks for equality with ==.
(doubleToLongBits internally calls public static native long doubleToRawLongBits(double value), so it is platform dependent).
Here the way the primitive type works.
primitive type double
The floating-point types are float and double, which are conceptually associated with the single-precision 32-bit and double-precision 64-bit format IEEE 754 values and operations as specified in IEEE Standard for Binary Floating-Point Arithmetic, ANSI/IEEE Standard 754-1985 (IEEE, New York).JLS-4.2.3
Operators on floating-point numbers behave as specified by IEEE 754 (with the exception of the remainder operator (§15.17.3)).
JLS-4.2.4
So the fastest way would be using primitive types and possibly performing a 'delta check' depending on the needed accuracy. If that's not possible using the methods provided by Double.
One should not use the JUnit assert method, since it performs more checks, one would be better off doing sth like:
boolean eq = Double.valueOf(5.0d).equals(Double.valueOf(2.0d));
Assert.assertTrue(eq);

Why does Java implicitly (without cast) convert a `long` to a `float`?

Every time I think I understand about casting and conversions, I find another strange behavior.
long l = 123456789L;
float f = l;
System.out.println(f); // outputs 1.23456792E8
Given that a long has greater bit-depth than a float, I would expect that an explicit cast would be required in order for this to compile. And not surprisingly, we see that we have lost precision in the result.
Why is a cast not required here?
The same question could be asked of long to double - both conversions may lose information.
Section 5.1.2 of the Java Language Specification says:
Widening primitive conversions do not
lose information about the overall
magnitude of a numeric value. Indeed,
conversions widening from an integral
type to another integral type do not
lose any information at all; the
numeric value is preserved exactly.
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.
Conversion of an int or a long value
to float, or of a long value to
double, may result in loss of
precision-that is, the result may lose
some of the least significant bits of
the value. In this case, the resulting
floating-point value will be a
correctly rounded version of the
integer value, using IEEE 754
round-to-nearest mode (§4.2.4).
In other words even though you may lose information, you know that the value will still be in the overall range of the target type.
The choice could certainly have been made to require all implicit conversions to lose no information at all - so int and long to float would have been explicit and long to double would have been explicit. (int to double is okay; a double has enough precision to accurately represent all int values.)
In some cases that would have been useful - in some cases not. Language design is about compromise; you can't win 'em all. I'm not sure what decision I'd have made...
The Java Language Specification, Chapter 5: Conversion and Promotion addresses this issue:
5.1.2 Widening Primitive Conversion
The following 19 specific conversions
on primitive types are called the
widening primitive conversions:
byte to short, int, long, float, or double
short to int, long, float, or double
char to int, long, float, or double
int to long, float, or double
long to float or double
float to double
Widening primitive conversions do not lose information about the overall magnitude of a numeric value.
...
Conversion of an int or a long value to float, or of a long value to double, may result in loss of precision-that is, the result may lose some of the least significant bits of the value. In this case, the resulting floating-point value will be a correctly rounded version of the integer value
To put it another way, the JLS distinguishes between a loss of magnitude and a loss of precision.
int to byte for example is a (potential) loss of magnitude because you can't store 500 in a byte.
long to float is a potential loss of precision but not magnitude because the value range for floats is larger than that for longs.
So the rule is:
Loss of magnitude: explicit cast required;
Loss of precision: no cast required.
Subtle? Sure. But I hope that clears that up.
Though you're correct that a long uses more bits internally than a float, the java language works on a widening path:
byte -> short -> int -> long -> float -> double
To convert from left to right (a widening conversion), there is no cast necessary (which is why long to float is allowed). To convert right to left (a narrowing conversion) an explicit cast is necessary.
Somewhere I heard this. Float can store in exponential form as is we write it. '23500000000' is stored as '2.35e10' .So, float has space to occupy the range of values of long. Storing in exponential form is also the reason for precision loss.

Categories