For which double value is a comparison with itself the fastest? - java

Just to put my question in context: I have a class that sorts a list in its constructor, based on some calculated score per element. Now I want to extend my code to a version of the class that does not sort the list. The easiest (but obviously not clean, I'm fully aware, but time is pressing and I don't have time to refactor my code at the moment) solution would be to just use a score calculator that assigns the same score to every element.
Which double value should I pick? I was personally thinking +Infinity or -Infinity since I assume these have a special representation, meaning they can be compared fast. Is this a correct assumption? I do not know enough about the low level implementation of java to figure out if I am correct.

In general avoid 0.0, -0.0 and NaN. Any other number would be fine. You may look into Double.compare implementation to see that they are handled specially:
if (d1 < d2)
return -1; // Neither val is NaN, thisVal is smaller
if (d1 > d2)
return 1; // Neither val is NaN, thisVal is larger
// Cannot use doubleToRawLongBits because of possibility of NaNs.
long thisBits = Double.doubleToLongBits(d1);
long anotherBits = Double.doubleToLongBits(d2);
return (thisBits == anotherBits ? 0 : // Values are equal
(thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)
1)); // (0.0, -0.0) or (NaN, !NaN)
However that depends on how your sorting comparator is implemented. If you don't use Double.compare, then probably it doesn't matter.
Note that except these special cases with 0.0/-0.0/NaN double numbers comparison is wired inside the CPU and really fast, thus you are unlikely to get any significant comparison overhead compared to the other code you already have.

No sure how this would fit in but have you considered writing your own?
It just seems a little concerning that you are looking for an object with specific performance characteristics that are unlikely to consistently appear in a general implementation. Even if you find a perfect candidate by experiment or even from source code you could not guarantee the contract.
static class ConstDouble extends Number implements Comparable<Number> {
private final Double d;
private final int intValue;
private final long longValue;
private final float floatValue;
public ConstDouble(Double d) {
this.d = d;
this.intValue = d.intValue();
this.longValue = d.longValue();
this.floatValue = d.floatValue();
}
public ConstDouble(long i) {
this((double) i);
}
// Implement Number
#Override
public int intValue() {
return intValue;
}
#Override
public long longValue() {
return longValue;
}
#Override
public float floatValue() {
return floatValue;
}
#Override
public double doubleValue() {
return d;
}
// Implement Comparable<Number> fast.
#Override
public int compareTo(Number o) {
// Core requirement - comparing with myself will always be fastest.
if (o == this) {
return 0;
}
return Double.compare(d, o.doubleValue());
}
}
// Special constant to use appropriately.
public static final ConstDouble ZERO = new ConstDouble(0);
public void test() {
// Will use ordinary compare.
int d1 = new ConstDouble(0).compareTo(new Double(0));
// Will use fast compare.
int d2 = ZERO.compareTo(new Double(0));
// Guaranteed to return 0 in the shortest time.
int d3 = ZERO.compareTo(ZERO);
}
Obviously you would need to use Comparable<Number> rather than Double in your collections but that may not be a bad thing. You could probably craft a mechanism to ensure that the fast-track compare is always used in preference (depends on your usage).

Related

Collections.sort() doesn't work for custom Objects

I'm trying to sort my List but this one doesn't work. Method collections.sort() does nothing.
public boolean schedule(){
List<Task> keys = new ArrayList<Task>(g.tasks.keySet());
for(int i = 0; i<keys.size();i++){
System.out.println(keys.get(i).getSize());
}
Collections.sort(keys);
for(int i = 0; i<keys.size();i++){
System.out.println(keys.get(i).getSize());
}
return true;
}
and this is my compareTo() method in Task class:
public int compareTo(Task t1) {
Integer csize = new Integer(t1.size);
int cmp = csize.compareTo(t1.size);
return cmp;
}
What is wrong in this method?
collections.sort doesn't work for custom objects
Sure it does, but it won't in your case because your compareTo method is broken. You're comparing t1's size to itself, not to the size of this
You've got:
public int compareTo(Task t1) {
Integer csize = new Integer(t1.size); // get t1's size
int cmp = csize.compareTo(t1.size); // ???? compare with t1's size ???
return cmp;
}
You need to change it to something like:
public int compareTo(Task t1) {
return Integer.compare(this.size, t1.size);
}
So now you're comparing the size of the parameter with the size of the current object.
You have an error in compareTo that has been pointed out in the accepted answer. I am supplying an additional answer only to provide a different idiom you might consider for defining natural order of a class:
class Task implements Comparable<Task> {
private static final Comparator<Task> ORDER = Comparator
.comparingInt(Task::getSize)
.reversed()
.thenComparing(Task::getPriority);
public int compareTo(Task other) {
return ORDER.compare(this, other);
}
}
The potential advantage of this delegation idiom is that on casual reading of a traditional compareTo implementation it's easy to miss things such as the order of arguments reversing the comparison. The declaration makes it very explicit. This also means that you have all the features of Comparator available (e.g. deciding if nulls are first or last).
Already answer was posted by #HoverCraft.
In addition to that
//For ASC
public int compareTo(Task t1) {
return (this.size - t1.size);
}
//For DESC
public int compareTo(Task t1) {
return (t1.size - this.size);
}

Using Generics of Subclasses of Number to Create a Rollover Counter

I'm trying to create a counter that will rollover whenever it reaches a preset ceiling and resets back to its floor value upon reaching said ceiling. I have implemented the class and it works just fine. However, on my way to my solution, I wanted to experiment with Java Generics. I want to try and extend my counter so that it doesn't only use integers, but instead can use any type of number. I know that counters typically call for just the use of integers anyway, but I wanted to see if it could be done.
I figured that the code would be similar to below. However, java.lang.Number doesn't have a "generic" way of getting/setting its value. Do I need to create my own number class to enable this? Also, I know that if I do get this working, I need to alter my equals checks so that they have an error threshold for floating point values, this is more or less a modified version of my int counter with what I figured would work for generics.
Edit:
It's been suggested that I take a mapping approach where I store an integer counter and keep a increment value so that when I want to spit out a number, I just multiply my current count by the increment value. However, I don't believe this will fill my exact needs because I don't want to necessarily increment by the same amount every time. The main focus of this counter is more of a way to have a fixed range number that, when added to or subtracted from, knows how to handle wrapping back around.
I guess the best way to describe it (although probably improperly) would be like an Integer that automatically handles over/underflow.
package com.math;
public class GenericRolloverCounter<T extends Number> {
private T value;
private T lowValue;
private T highValue;
public GenericRolloverCounter(T l_startValue, T l_highValue) {
this.lowValue = l_startValue;
this.highValue = l_highValue;
this.value = l_startValue;
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
public void increment(T valToIncrementBy) {
this.value += valToIncrementBy;
if (this.value > this.highValue) {
this.value = (this.lowValue + (this.value - (this.highValue + 1)));
}
}
public void increment() {
this.increment(1);
}
public void decrement(T valToDecrementBy) {
this.value -= valToDecrementBy;
if (this.value < this.lowValue) {
this.value = ((this.value + this.highValue + 1) - this.lowValue);
}
}
public void decrement() {
this.decrement(1);
}
#Override
public String toString() {
return Integer.toString(this.value);
}
}
You might want to also specify an amount by which to count. Default value would be 1.
You can get around some of this by using the Number method .doubleValue() and doing double arithmetic.
Here is one of the methods converted to use this idea.
public void decrement(double valToDecrementBy) {
double work = this.value.doubleValue();
work -= valToDecrementBy;
// should use some value related to incrementing amount
if ((this.value.doubleValue() - this.lowValue.doubleValue()) < 0.1D) {
work = ((this.value.doubleValue() + this.highValue.doubleValue() + 1) - this.lowValue.doubleValue());
}
// ... no way to put it back
}
But, there is still no way to put the value back that's clean and easy. Since 'Number' only has a few commonly used non-abstract subclasses, you could do some ugly instanceof stuff to store the value back. It would look something like this:
if (theValue instanceof Double) { // depends on it having a non-null value prior
theValue = (T)(new Double(work));
}
Or you could convert the starting values to double when you start and just work with doubles.
private double value;
private double lowValue;
private double highValue;
public GenericRolloverCounter(T l_startValue, T l_highValue) {
this.lowValue = l_startValue.doubleValue();
this.highValue = l_highValue.doubleValue();
this.value = l_startValue.doubleValue();
}
That does introduce the issues of incrementing floating point values and the rounding/evaluation problem there.
Oh ... and your toString() should be:
return value.toString();
To use the native toString() method on the T class.
#Crusher's comments suggest another way to do it. Map everything to 'int' and keep a multiplier. Here's some bits of code to show what I mean. (Thanks Crusher)
private int value;
private int lowValue;
private int highValue;
private double incr;
public GenericRolloverCounter(T l_startValue, T l_highValue, T incrementAmount) {
double incr = incrementAmount.doubleValue();
this.lowValue = Math.round(l_startValue.doubleValue() / incr);
this.highValue = Math.round(l_highValue.doubleValue() / incr);
this.value = Math.round(l_startValue.doubleValue() / incr);
}
public void increment(int valToIncrementBy) {
this.value += valToIncrementBy;
if (this.value > this.highValue) {
this.value = (this.lowValue + (this.value - (this.highValue + 1)));
}
}
#Override
public String toString() {
return String.valueOf(incr * this.value);
}

Java math DescriptiveStatistics remove value

I am new to Java and have been using it with Esper CEP engine. This question is however unrelated to Esper, its more of a Java question.
First, my class :-
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
import com.espertech.esper.epl.agg.AggregationSupport;
import com.espertech.esper.epl.agg.AggregationValidationContext;
public class CustomPercentiles extends AggregationSupport {
private List<Double> numbers = new ArrayList<Double>();
public CustomPercentiles(){
super();
}
public void clear() {
numbers.clear();
}
public void enter(Object arg0) {
Double value = (Double) (double) (Integer) arg0;
if (value > 0){
//Not interested in < 1
numbers.add(value);
}
}
public void leave(Object arg0) {
Double value = (Double) (double) (Integer) arg0;
if (value > 0){
//Not interested in < 1
numbers.remove(value);
}
}
public Object getValue() {
DescriptiveStatistics stats = new DescriptiveStatistics();
Map<String, Integer> result = new HashMap<String, Integer>();
for (Double number:numbers.subList(0, numbers.size())){
stats.addValue(number);
}
result.put("median", (int) stats.getPercentile(50));
result.put("pct90", (int) stats.getPercentile(90));
result.put("pct10", (int) stats.getPercentile(10));
result.put("mean", (int) stats.getMean());
result.put("std", (int) stats.getStandardDeviation());
return result ;
}
public Class getValueType() {
return Object.class;
}
#Override
public void validate(AggregationValidationContext arg0) {
// TODO Auto-generated method stub
}
}
Basically, Esper will call enter(value) and leave(value) whenever it wants based on logic irrelevant here. And it calls getValue() to get the results computed.
Since I want to calculate percentiles, I need all the numbers available to process this. To do this, I store it in a global list called numbers, and in getValue() I put all the numbers into a DescriptiveStatistics instance and then process the stats I need.
My presumption is that each time i put the list as a new DescriptiveStatistics object, it needs to do sorting. Is there some way i can maintain a DescriptiveStatistics-like object as my global object?
The only reason i use ArrayList vs DescriptiveStatistics as my global object is that DescriptiveStatistics does not have a remove method. I.e. i cannot remove an object by value.
In practice, there are hundreds of instances of this class running at any given time, and getValue() for each of them is called every 1 to 10 second. I don't have any performance issues at the moment, but am looking for some optimization help to avoid future problems.
Alternate explanation :-
What i am doing here is mantaining a list of numbers. Esper will call the enter() and leave() methods many times to tell me what numbers should remain in the list. This in my case is a time based aggregation. Ive told esper that I want to compute based on numbers from last 1 minute.
So on 00:00:00 esper calls enter(10)
my numbers becomes [10]
So on 00:00:05 esper calls enter(15)
my numbers becomes [10, 15]
So on 00:00:55 esper calls enter(10)
my numbers becomes [10, 15, 10]
So on 00:01:00 esper calls leave(10)
my numbers becomes [15, 10]
So on 00:01:05 esper calls leave(15)
my numbers becomes [15]
Now in this duration getValue() may have been called numerous times. Each time it is called, it is expected to return calculations based off the current contents of numbers.
getValue() calculates the 10th, 50th and 90th percentiles. In order to calculate percentiles, DescriptiveStatistics needs to sort the numbers. (10th percentile of 100 numbers would be the 10th number of the list after sorting it.).
So im looking for a way to be able to take out any arbitary number from DescriptiveStatistics instance. Or asking for recommendation for some other library that can give me medians and percentiles while having the ability to take out a number from the list while knowing the value.
DescriptiveStatistics has a removeMostRecentValue(), but thats not what I want to do.
To my understanding, you're asking for a way to use the DescriptiveStatistics-class as the list, instead of "numbers". Meaning, you want to dynamically add and remove numbers from the DescriptiveStatistics-variable.
As far as I can see, there's no better way to do this than what you're doing now.
Are you sure that you need the feature to remove a specific number from the list, before calculating the percentile again? Wouldn't it always be new numbers?
It sounds a bit like you would want to learn some more basics of Java.
Anyway, since I can't really give you a qualified answer to your question, I figured I would at least help you with correcting some of your code, to follow better practices:
public class CustomPercentiles extends AggregationSupport {
private List<Double> numbers = new ArrayList<Double>();
//Methods that are inherited from super-classes and interfaces
//should have the "#Override" annotation,
//both for the compiler to check if it really is inherited,
//but also to make it more clear which methods are new in this class.
#Override
public void clear() {
numbers.clear();
}
#Override
public void enter(Object value) {
double v = (double) value;
if (v > 0){
numbers.add(v);
}
}
#Override
public void leave(Object value) {
double v = (double) value;
if (v > 0){
numbers.remove(v);
}
}
#Override
public Object getValues() {
DescriptiveStatistics stats = new DescriptiveStatistics();
Map<String, Integer> result = new HashMap<String, Integer>();
//It is unnecessary to call number.subList(0, numbers.size())
//since it will just return the entire list.
for (Double number : numbers){
stats.addValue(number);
}
result.put("median", (int) stats.getPercentile(50));
result.put("pct90", (int) stats.getPercentile(90));
result.put("pct10", (int) stats.getPercentile(10));
result.put("mean", (int) stats.getMean());
result.put("std", (int) stats.getStandardDeviation());
return result ;
}
//Judgning from the API of AggregationSupport,
//I would say this method should return Double.class
//(it basically seems like a bad way of implementing generics).
//Are you sure it should return Object.class?
public Class getValueType() {
return Object.class;
}
#Override
public void validate(AggregationValidationContext arg0) {
// TODO Auto-generated method stub
}
}

Is there a Java data structure that is effectively an ArrayList with double indicies and built-in interpolation?

I am looking for a pre-built Java data structure with the following characteristics:
It should look something like an ArrayList but should allow indexing via double-precision rather than integers. Note that this means that it's likely that you'll see indicies that don't line up with the original data points (i.e., asking for the value that corresponds to key "1.5"). EDIT: For clarity, based on the comments, I'm not looking to change the ArrayList implementation. I'm looking for a similar interface and developer experience.
As a consequence, the value returned will likely be interpolated. For example, if the key is 1.5, the value returned could be the average of the value at key 1.0 and the value at key 2.0.
The keys will be sorted but the values are not ensured to be monotonically increasing. In fact, there's no assurance that the first derivative of the values will be continuous (making it a poor fit for certain types of splines).
Freely available code only, please.
For clarity, I know how to write such a thing. In fact, we already have an implementation of this and some related data structures in legacy code that I want to replace due to some performance and coding issues.
What I'm trying to avoid is spending a lot of time rolling my own solution when there might already be such a thing in the JDK, Apache Commons or another standard library. Frankly, that's exactly the approach that got this legacy code into the situation that it's in right now....
Is there such a thing out there in a freely available library?
Allowing double values as indices is a pretty large change from what ArrayList does.
The reason for this is that an array or list with double as indices would almost by definition be a sparse array, which means it has no value (or depending on your definition: a fixed, known value) for almost all possible indices and only a finite number of indices have an explicit value set.
There is no prebuilt class in Java SE that supports all that.
Personally I'd implement such a data structure as a skip-list (or similar fast-searching data structure) of (index, value) tuples with appropriate interpolation.
Edit: Actually there's a pretty good match for the back-end storage (i.e. everything except for the interpolation): Simply use a NavigableMap such as a TreeMap to store the mapping from index to value.
With that you can easily use ceilingEntry() and (if necessary) higherEntry() to get the closest value(s) to the index you need and then interpolate from those.
If your current implementation has complexity O(log N) for interpolating a value, the implementation I just made up may be for you:
package so2675929;
import java.util.Arrays;
public abstract class AbstractInterpolator {
private double[] keys;
private double[] values;
private int size;
public AbstractInterpolator(int initialCapacity) {
keys = new double[initialCapacity];
values = new double[initialCapacity];
}
public final void put(double key, double value) {
int index = indexOf(key);
if (index >= 0) {
values[index] = value;
} else {
if (size == keys.length) {
keys = Arrays.copyOf(keys, size + 32);
values = Arrays.copyOf(values, size + 32);
}
int insertionPoint = insertionPointFromIndex(index);
System.arraycopy(keys, insertionPoint, keys, insertionPoint + 1, size - insertionPoint);
System.arraycopy(values, insertionPoint, values, insertionPoint + 1, size - insertionPoint);
keys[insertionPoint] = key;
values[insertionPoint] = value;
size++;
}
}
public final boolean containsKey(double key) {
int index = indexOf(key);
return index >= 0;
}
protected final int indexOf(double key) {
return Arrays.binarySearch(keys, 0, size, key);
}
public final int size() {
return size;
}
protected void ensureValidIndex(int index) {
if (!(0 <= index && index < size))
throw new IndexOutOfBoundsException("index=" + index + ", size=" + size);
}
protected final double getKeyAt(int index) {
ensureValidIndex(index);
return keys[index];
}
protected final double getValueAt(int index) {
ensureValidIndex(index);
return values[index];
}
public abstract double get(double key);
protected static int insertionPointFromIndex(int index) {
return -(1 + index);
}
}
The concrete interpolators will only have to implement the get(double) function.
For example:
package so2675929;
public class LinearInterpolator extends AbstractInterpolator {
public LinearInterpolator(int initialCapacity) {
super(initialCapacity);
}
#Override
public double get(double key) {
final double minKey = getKeyAt(0);
final double maxKey = getKeyAt(size() - 1);
if (!(minKey <= key && key <= maxKey))
throw new IndexOutOfBoundsException("key=" + key + ", min=" + minKey + ", max=" + maxKey);
int index = indexOf(key);
if (index >= 0)
return getValueAt(index);
index = insertionPointFromIndex(index);
double lowerKey = getKeyAt(index - 1);
double lowerValue = getValueAt(index - 1);
double higherKey = getKeyAt(index);
double higherValue = getValueAt(index);
double rate = (higherValue - lowerValue) / (higherKey - lowerKey);
return lowerValue + (key - lowerKey) * rate;
}
}
And, finally, a unit test:
package so2675929;
import static org.junit.Assert.*;
import org.junit.Test;
public class LinearInterpolatorTest {
#Test
public void simple() {
LinearInterpolator interp = new LinearInterpolator(2);
interp.put(0.0, 0.0);
interp.put(1.0, 1.0);
assertEquals(0.0, interp.getValueAt(0), 0.0);
assertEquals(1.0, interp.getValueAt(1), 0.0);
assertEquals(0.0, interp.get(0.0), 0.0);
assertEquals(0.1, interp.get(0.1), 0.0);
assertEquals(0.5, interp.get(0.5), 0.0);
assertEquals(0.9, interp.get(0.9), 0.0);
assertEquals(1.0, interp.get(1.0), 0.0);
interp.put(0.5, 0.0);
assertEquals(0.0, interp.getValueAt(0), 0.0);
assertEquals(0.0, interp.getValueAt(1), 0.0);
assertEquals(1.0, interp.getValueAt(2), 0.0);
assertEquals(0.0, interp.get(0.0), 0.0);
assertEquals(0.0, interp.get(0.1), 0.0);
assertEquals(0.0, interp.get(0.5), 0.0);
assertEquals(0.75, interp.get(0.875), 0.0);
assertEquals(1.0, interp.get(1.0), 0.0);
}
#Test
public void largeKeys() {
LinearInterpolator interp = new LinearInterpolator(10);
interp.put(100.0, 30.0);
interp.put(200.0, 40.0);
assertEquals(30.0, interp.get(100.0), 0.0);
assertEquals(35.0, interp.get(150.0), 0.0);
assertEquals(40.0, interp.get(200.0), 0.0);
try {
interp.get(99.0);
fail();
} catch (IndexOutOfBoundsException e) {
assertEquals("key=99.0, min=100.0, max=200.0", e.getMessage());
}
try {
interp.get(201.0);
fail();
} catch (IndexOutOfBoundsException e) {
assertEquals("key=201.0, min=100.0, max=200.0", e.getMessage());
}
}
private static final int N = 10 * 1000 * 1000;
private double measure(int size) {
LinearInterpolator interp = new LinearInterpolator(size);
for (int i = 0; i < size; i++)
interp.put(i, i);
double max = interp.size() - 1;
double sum = 0.0;
for (int i = 0; i < N; i++)
sum += interp.get(max * i / N);
return sum;
}
#Test
public void speed10() {
assertTrue(measure(10) > 0.0);
}
#Test
public void speed10000() {
assertTrue(measure(10000) > 0.0);
}
#Test
public void speed1000000() {
assertTrue(measure(1000000) > 0.0);
}
}
So the functionality seems to work. I only measured speed in some simple cases, and these suggest that scaling will be better than linear.
Update (2010-10-17T23:45+0200): I made some stupid mistakes in checking the key argument in the LinearInterpolator, and my unit tests didn't catch them. Now I extended the tests and fixed the code accordingly.
In the Apache commons-math library, if you implement the UnivariateRealInterpolator and the return value of its interpolate method which is typed UnivariateRealFunction you'll be most of the way there.
The interpolator interface takes two arrays, x[] and y[]. The returned function has a method, value() that takes an x' and returns the interpolated y'.
Where it fails to provide an ArrayList-like experience is in the ability to add more values to the range and domain as if the List is growing.
Additionally, they look to be in need of some additional interpolation functions. There are only 4 implementations in the library for the stable release. As a commenter pointed out, it seems to be missing 'linear' or something even simpler like nearest neighbor. Maybe that's not really interpolation...
That's a huge change from ArrayList.
Same as Joachim's response above, but I'd probably implement this as a binary tree, and when I didn't find something I was looking for, average the value of the next smallest and largest values, which should be quick to traverse to.
Your description that it should be "like an ArrayList" is misleading, since what you've described is a one dimensional interpolator and has essentially nothing in common with an ArrayList. This is why you're getting suggestions for other data structures which IMO are sending you down the wrong path.
I don't know of any available in Java (and couldn't easily find one one google), but I think you should have a look at GSL - GNU Scientific Library which includes a spline interpolator. It may be a bit heavy for what you're looking for since it's a two dimensional interpolator, but it seems like you should be looking for something like this rather than something like an ArrayList.
If you'd like it to "look like an ArrayList" you can always wrap it in a Java class which has access methods similar to the List interface. You won't be able to actually implement the interface though, since the methods are declared to take integer indices.

Safely casting long to int in Java

What's the most idiomatic way in Java to verify that a cast from long to int does not lose any information?
This is my current implementation:
public static int safeLongToInt(long l) {
int i = (int)l;
if ((long)i != l) {
throw new IllegalArgumentException(l + " cannot be cast to int without changing its value.");
}
return i;
}
A method was added in Java 8:
import static java.lang.Math.toIntExact;
long foo = 10L;
int bar = toIntExact(foo);
Will throw an ArithmeticException in case of overflow.
See: Math.toIntExact(long)
Several other overflow safe methods have been added to Java 8. They end with exact.
Examples:
Math.incrementExact(long)
Math.subtractExact(long, long)
Math.decrementExact(long)
Math.negateExact(long),
Math.subtractExact(int, int)
I think I'd do it as simply as:
public static int safeLongToInt(long l) {
if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) {
throw new IllegalArgumentException
(l + " cannot be cast to int without changing its value.");
}
return (int) l;
}
I think that expresses the intent more clearly than the repeated casting... but it's somewhat subjective.
Note of potential interest - in C# it would just be:
return checked ((int) l);
With Google Guava's Ints class, your method can be changed to:
public static int safeLongToInt(long l) {
return Ints.checkedCast(l);
}
From the linked docs:
checkedCast
public static int checkedCast(long value)
Returns the int value that is equal to value, if possible.
Parameters:
value - any value in the range of the int type
Returns:
the int value that equals value
Throws:
IllegalArgumentException - if value is greater than Integer.MAX_VALUE or less than Integer.MIN_VALUE
Incidentally, you don't need the safeLongToInt wrapper, unless you want to leave it in place for changing out the functionality without extensive refactoring of course.
With BigDecimal:
long aLong = ...;
int anInt = new BigDecimal(aLong).intValueExact(); // throws ArithmeticException
// if outside bounds
here is a solution, in case you don't care about value in case it is bigger then needed ;)
public static int safeLongToInt(long l) {
return (int) Math.max(Math.min(Integer.MAX_VALUE, l), Integer.MIN_VALUE);
}
DONT: This is not a solution!
My first approach was:
public int longToInt(long theLongOne) {
return Long.valueOf(theLongOne).intValue();
}
But that merely just casts the long to an int, potentially creating new Long instances or retrieving them from the Long pool.
The drawbacks
Long.valueOf creates a new Long instance if the number is not within Long's pool range [-128, 127].
The intValue implementation does nothing more than:
return (int)value;
So this can be considered even worse than just casting the long to int.
I claim that the obvious way to see whether casting a value changed the value would be to cast and check the result. I would, however, remove the unnecessary cast when comparing. I'm also not too keen on one letter variable names (exception x and y, but not when they mean row and column (sometimes respectively)).
public static int intValue(long value) {
int valueInt = (int)value;
if (valueInt != value) {
throw new IllegalArgumentException(
"The long value "+value+" is not within range of the int type"
);
}
return valueInt;
}
However, really I would want to avoid this conversion if at all possible. Obviously sometimes it's not possible, but in those cases IllegalArgumentException is almost certainly the wrong exception to be throwing as far as client code is concerned.
Java integer types are represented as signed. With an input between 231 and 232 (or -231 and -232) the cast would succeed but your test would fail.
What to check for is whether all of the high bits of the long are all the same:
public static final long LONG_HIGH_BITS = 0xFFFFFFFF80000000L;
public static int safeLongToInt(long l) {
if ((l & LONG_HIGH_BITS) == 0 || (l & LONG_HIGH_BITS) == LONG_HIGH_BITS) {
return (int) l;
} else {
throw new IllegalArgumentException("...");
}
}
(int) (longType + 0)
but Long can not exceed the maximum :)
One other solution can be:
public int longToInt(Long longVariable)
{
try {
return Integer.valueOf(longVariable.toString());
} catch(IllegalArgumentException e) {
Log.e(e.printstackstrace());
}
}
I have tried this for cases where the client is doing a POST and the server DB understands only Integers while the client has a Long.

Categories