Testing if two primitive wrapper Numbers represent equal primitive numbers - java

I am searching for a reliable way to test if two primitive wrapper Numbers (e.g. Integer, Float, Double etc.) represent equal primitive numbers.
For example the following if statement involving two primitive numbers yields true:
int i = 100;
double d = 100d;
if (i == d) {
System.out.println("equal");
}
But the following if statement is of course false since the Number instances are of different classes (Integer and Double):
int i = 100;
double d = 100d;
Number n1 = i;
Number n2 = d;
if (n1.equals(n2)) {
System.out.println("equal");
}
Is there some relialble generic test to see, if two instances of Number (of which I know are primitive wrappers) are equal in the sense that their primitive values are equal? In the same context: is there some reliable generic test to see how instances of Number compare to each other with the other conditional operators != >, <, >= and <=?
For now I came to the following solution, but I'm not sure if this is really reliable:
int i = 100;
double d = 100d;
Number n1 = i;
Number n2 = d;
if (n1.doubleValue() == n2.doubleValue()) {
System.out.println("equal");
}

That's ugly.
If I was given that assignment, and if I could not find a library to do it for me (I don't know of any such library off the top of my head), then I would write some ugly code:
I would use reflection to get the types of the two Numbers, and then I would look up in a table to find which of them could be cast to the other's type.
Then do the cast,
Then compare.
Your solution, cast everything to double, will work for most cases, but it will not work for comparing long values that are larger than about 2^56. The double data type does not have sufficient precision to represent all of the long values that are larger than that.

Related

Recursion sum with generics [duplicate]

I have two Numbers. Eg:
Number a = 2;
Number b = 3;
//Following is an error:
Number c = a + b;
Why arithmetic operations are not supported on Numbers? Anyway how would I add these two numbers in java? (Of course I'm getting them from somewhere and I don't know if they are Integer or float etc).
You say you don't know if your numbers are integer or float... when you use the Number class, the compiler also doesn't know if your numbers are integers, floats or some other thing. As a result, the basic math operators like + and - don't work; the computer wouldn't know how to handle the values.
START EDIT
Based on the discussion, I thought an example might help. Computers store floating point numbers as two parts, a coefficient and an exponent. So, in a theoretical system, 001110 might be broken up as 0011 10, or 32 = 9. But positive integers store numbers as binary, so 001110 could also mean 2 + 4 + 8 = 14. When you use the class Number, you're telling the computer you don't know if the number is a float or an int or what, so it knows it has 001110 but it doesn't know if that means 9 or 14 or some other value.
END EDIT
What you can do is make a little assumption and convert to one of the types to do the math. So you could have
Number c = a.intValue() + b.intValue();
which you might as well turn into
Integer c = a.intValue() + b.intValue();
if you're willing to suffer some rounding error, or
Float c = a.floatValue() + b.floatValue();
if you suspect that you're not dealing with integers and are okay with possible minor precision issues. Or, if you'd rather take a small performance blow instead of that error,
BigDecimal c = new BigDecimal(a.floatValue()).add(new BigDecimal(b.floatValue()));
It would also work to make a method to handle the adding for you. Now I do not know the performance impact this will cause but I assume it will be less than using BigDecimal.
public static Number addNumbers(Number a, Number b) {
if(a instanceof Double || b instanceof Double) {
return a.doubleValue() + b.doubleValue();
} else if(a instanceof Float || b instanceof Float) {
return a.floatValue() + b.floatValue();
} else if(a instanceof Long || b instanceof Long) {
return a.longValue() + b.longValue();
} else {
return a.intValue() + b.intValue();
}
}
The only way to correctly add any two types of java.lang.Number is:
Number a = 2f; // Foat
Number b = 3d; // Double
Number c = new BigDecimal( a.toString() ).add( new BigDecimal( b.toString() ) );
This works even for two arguments with a different number-type. It will (should?) not produce any sideeffects like overflows or loosing precision, as far as the toString() of the number-type does not reduce precision.
java.lang.Number is just the superclass of all wrapper classes of primitive types (see java doc). Use the appropriate primitive type (double, int, etc.) for your purpose, or the respective wrapper class (Double, Integer, etc.).
Consider this:
Number a = 1.5; // Actually Java creates a double and boxes it into a Double object
Number b = 1; // Same here for int -> Integer boxed
// What should the result be? If Number would do implicit casts,
// it would behave different from what Java usually does.
Number c = a + b;
// Now that works, and you know at first glance what that code does.
// Nice explicit casts like you usually use in Java.
// The result is of course again a double that is boxed into a Double object
Number d = a.doubleValue() + (double)b.intValue();
Use the following:
Number c = a.intValue() + b.intValue(); // Number is an object and not a primitive data type.
Or:
int a = 2;
int b = 3;
int c = 2 + 3;
I think there are 2 sides to your question.
Why is operator+ not supported on Number?
Because the Java language spec. does not specify this, and there is no operator overloading. There is also not a compile-time natural way to cast the Number to some fundamental type, and there is no natural add to define for some type of operations.
Why are basic arithmic operations not supported on Number?
(Copied from my comment:)
Not all subclasses can implement this in a way you would expect. Especially with the Atomic types it's hard to define a usefull contract for e.g. add.
Also, a method add would be trouble if you try to add a Long to a Short.
If you know the Type of one number but not the other it is possible to do something like
public Double add(Double value, Number increment) {
return value + Double.parseDouble(increment.toString());
}
But it can be messy, so be aware of potential loss of accuracy and NumberFormatExceptions
Number is an abstract class which you cannot make an instance of. Provided you have a correct instance of it, you can get number.longValue() or number.intValue() and add them.
First of all, you should be aware that Number is an abstract class. What happens here is that when you create your 2 and 3, they are interpreted as primitives and a subtype is created (I think an Integer) in that case. Because an Integer is a subtype of Number, you can assign the newly created Integer into a Number reference.
However, a number is just an abstraction. It could be integer, it could be floating point, etc., so the semantics of math operations would be ambiguous.
Number does not provide the classic map operations for two reasons:
First, member methods in Java cannot be operators. It's not C++. At best, they could provide an add()
Second, figuring out what type of operation to do when you have two inputs (e.g., a division of a float by an int) is quite tricky.
So instead, it is your responsibility to make the conversion back to the specific primitive type you are interested in it and apply the mathematical operators.
The best answer would be to make util with double dispatch drilling down to most known types (take a look at Smalltalk addtition implementation)

double vs Double as Floating Point Numbers in Eclipse

My question is two-part.
Why does the following work fine in Eclipse? Isn't "Double" a class?
Double h = 2.5;
double j = 2;
Why does "Double" above give me an error when I don't assign a decimal value to it, but "double" is fine whether or not I assign a decimal value to it?
As was already mentioned, the term is autoboxing. The object wrappers for the primitive types will automatically convert.
As to your second part,
Double a = 2;
Doesn't work since 2 is not a double and the auto boxing only works between the same types. In this case 2 is an int.
But if you cast it.
Double a = (double)2;
works just fine.
double a = 2;
works because an int can be automatically converted to a double. But going the
other way doesn't work.
int a = 2.2; // not permitted.
Check out the Section on conversions. In the Java Language Specification. Warning that it can sometimes be difficult to read.
Amended Answer.
In java you can cast up or down or have narrowing or widening casts (going from a 32 bit to 16 bit) value is narrowing. But I tend to think about it is losing vs not losing something. In most cases if you have the potential to lose part of value in assignment, you need to cast, otherwise you don't (See exceptions at end). Here are some examples.
long a = 2; // 2 is an integer but going to a long doesn't `lose` precision.
int b = 2L; // here, 2 is a long and the assignment is not permitted. Even
// though a long 2 will fit inside an int, the cast is still
// required.
int b = (int)2L; // Fine, but clearly a contrived case
Same for floating point.
float a = 2.2f; // fine
double b = a; // no problem, not precision lost
float c = b; // can't do it, as it requires a cast.
double c = 2.2f; // a float to a double, again a not problem.
float d = 2.2; // 2.2 is a double by default so requires a cast or the float designator.
float d = (float)2.2;
Exceptions
No cast is required when converting from int to float or long to double. However, precision can still be lost since the floats only have 24 bits of precision and doubles only have 53 bits of precision.
To see this for ints you can run the following:
for (int i = Integer.MAX_VALUE; i > Integer.MAX_VALUE-100; i--) {
float s = i;
int t = (int)s; // normal cast required
if (i != t) {
System.out.println (i + " " + t);
}
}
Double is a wrapper class, creating a new Double casts a primitive variable of the SAME type into a Object. For Double h = 2, you are wrapping a int into a Double. Since wrapping only works between same types, if you want your Double variable be 2, then you should use
Double h = 2.0;

The effect of assigning parameter types on integer overflow

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

Math floor mixing types error?

I have this:
String a = tonsescolhidos.getValue().toString();
int tons = Integer.parseInt(a);
float distlevel = 256/(tons - 1);
int temp;
temp = Math.floor(((float) (tons / distlevel) + 0.5)*distlevel);
tons = temp;
I get the error: "Incompatible types: possible lossy conversion from double to int" in the 5th line. How do i cast the variables in the right way.. what am I missing?
Math.floor only has one overload: double Math.floor(double). That always returns a double.
You would need to explicitly cast it to an int:
temp = (int) Math.floor(...);
But note that it is potentially lossy: double can store values too large to store in an int. So, you need to ensure that it's not a lossy operation by ensuring that the double's value is between Integer.MIN_VALUE and Integer.MAX_VALUE, by constraining the inputs appropriately.
Alternatively, rearrange your calculation so that you can do it all in integer math.

How can I accurately determine if a double is an integer? [duplicate]

This question already has answers here:
How to test if a double is an integer
(18 answers)
Closed 9 years ago.
Specifically in Java, how can I determine if a double is an integer? To clarify, I want to know how I can determine that the double does not in fact contain any fractions or decimals.
I am concerned essentially with the nature of floating-point numbers. The methods I thought of (and the ones I found via Google) follow basically this format:
double d = 1.0;
if((int)d == d) {
//do stuff
}
else {
// ...
}
I'm certainly no expert on floating-point numbers and how they behave, but I am under the impression that because the double stores only an approximation of the number, the if() conditional will only enter some of the time (perhaps even a majority of the time). But I am looking for a method which is guaranteed to work 100% of the time, regardless of how the double value is stored in the system.
Is this possible? If so, how and why?
double can store an exact representation of certain values, such as small integers and (negative or positive) powers of two.
If it does indeed store an exact integer, then ((int)d == d) works fine. And indeed, for any 32-bit integer i, (int)((double)i) == i since a double can exactly represent it.
Note that for very large numbers (greater than about 2**52 in magnitude), a double will always appear to be an integer, as it will no longer be able to store any fractional part. This has implications if you are trying to cast to a Java long, for instance.
How about
if(d % 1 == 0)
This works because all integers are 0 modulo 1.
Edit To all those who object to this on the grounds of it being slow, I profiled it, and found it to be about 3.5 times slower than casting. Unless this is in a tight loop, I'd say this is a preferable way of working it out, because it's extremely clear what you're testing, and doesn't require any though about the semantics of integer casting.
I profiled it by running time on javac of
class modulo {
public static void main(String[] args) {
long successes = 0;
for(double i = 0.0; i < Integer.MAX_VALUE; i+= 0.125) {
if(i % 1 == 0)
successes++;
}
System.out.println(successes);
}
}
VS
class cast {
public static void main(String[] args) {
long successes = 0;
for(double i = 0.0; i < Integer.MAX_VALUE; i+= 0.125) {
if((int)i == i)
successes++;
}
System.out.println(successes);
}
}
Both printed 2147483647 at the end.
Modulo took 189.99s on my machine - Cast took 54.75s.
if(new BigDecimal(d).scale() <= 0) {
//do stuff
}
Your method of using if((int)d == d) should always work for any 32-bit integer. To make it work up to 64 bits, you can use if((long)d == d, which is effectively the same except that it accounts for larger magnitude numbers. If d is greater than the maximum long value (or less than the minimum), then it is guaranteed to be an exact integer. A function that tests whether d is an integer can then be constructed as follows:
boolean isInteger(double d){
if(d > Long.MAX_VALUE || d < Long.MIN_VALUE){
return true;
} else if((long)d == d){
return true;
} else {
return false;
}
}
If a floating point number is an integer, then it is an exact representation of that integer.
Doubles are a binary fraction with a binary exponent. You cannot be certain that an integer can be exactly represented as a double, especially not if it has been calculated from other values.
Hence the normal way to approach this is to say that it needs to be "sufficiently close" to an integer value, where sufficiently close typically mean "within X %" (where X is rather small).
I.e. if X is 1 then 1.98 and 2.02 would both be considered to be close enough to be 2. If X is 0.01 then it needs to be between 1.9998 and 2.0002 to be close enough.

Categories

Resources