As pkpnd stated in their comment, there is a known difference between one int and the next (ex. 4 and 5 are one integer apart). However, how far apart are two arbitrary doubles, an ulp?
One suggestion that I have to emulate a range is to use a NavigableMap:
enum Range {
LIGHT, MODERATE, VIGOROUS, UNKNOWN
}
NavigableMap<Double, Range> map = new TreeMap<>();
map.put(Double.NEGATIVE_INFINITY, Range.UNKNOWN);
map.put(0D, Range.LIGHT);
map.put(3D, Range.MODERATE);
map.put(6D, Range.VIGOROUS);
System.out.println(map.floorEntry(4D).getValue());
Output:
MODERATE
You're free to handle out-of-range values however you'd like, as well a Double.NaN.
Videos
I fully concur with @TimothyTruckle on format, follow his advice.
Using binaries is restrictive (only two states), and not user-friendly. I don't like byte arithmetics, its quite un-Java like. I suppose you come from C/C++ background.
In more Java-like syntax, I propose a fluent interface on a Range class:
public class Range {
private static enum RangeType{ INCLUSIVE, EXCLUSIVE, INFINITE };
private static class RangeStart {
private final RangeType startType;
private final Double startValue;
private RangeStart(RangeType type, Double value){
this.startType = type;
this.startValue = value;
}
public Range toInclusive(double endValue) {
// Optionally check endValue >= startValue and throw something
return new Range(startType, startValue, RangeType.INCLUSIVE, endValue);
}
public Range toExclusive(double endValue) {
// Optionally check endValue >= startValue and throw something
return new Range(startType, startValue, RangeType.EXCLUSIVE, endValue);
}
public Range toInfinity() {
return new Range(startType, startValue, RangeType.INFINITY, 0.);
}
}
public static RangeStart fromInfinity() {
retur new RangeStart(RangeType.INFINITY, 0.)
}
public static RangeStart fromInclusive(double fromValue) {
retur new RangeStart(RangeType.INCLUSIVE, fromValue)
}
public static RangeStart fromExclusive(double fromValue) {
retur new RangeStart(RangeType.EXCLUSIVE, fromValue)
}
private final RangeType startType;
private final Double startValue;
private final RangeType endType;
private final Double endValue;
private Range(RangeType startType, Double startValue, RangeType endType, Double endValue) {
this.startType = startType;
this.startValue = startValue;
this.endType = endType;
this.endValue = endValue;
}
public boolean contains(double value){
// Do your thing here, I'm not doing all the work! ;-)
}
}
This creates a re-usable Range object to check values. The Pattern used is similar to the Builder Pattern (I named the Builder RangeStart).
Example usage:
Range range5i7e = Range.fromInclusive(5).toExclusive(7);
range5i7e.contains(5); // true
range5i7e.contains(5); // false
Range.fromInclusive(-10).toInfinity().contains(3720); // true Range.fromInclusive(5).toExclusive(3); // Throws something ?
Style improvements:
You may want to make inclusive the standard and use Range.from(1).to(2) to make a closed Range. It's much less verbose.
You could also make the Range infinite-ended on both sides unless otherwise told, like Range.to(5) would be ]Inf, 5] etc.
Should I throw exceptions if range_a is less than range_b?
This depends on your requirements. - Does the user of this function have to provide the input in correct order because a wrong order is a follow up of serious problem in her preceding code? Then you should throw an exception and this might even be a checked custom type to make the user aware of it. - Or is the wrong order something that is likely to happen and no problem outside your method? The reordering and going on inside your method is appropriate.
Should I throw exceptions if range_a is less than range_b?
This also must be specified by the requirements. If there was no requirement add a Javadoc comment explaining that and why you (not) return true in this situation.
I'm using camelcase for methods and variables
as expected by the java naming conventions.
Underscore is used to show that values are connected. and used together:
Example: pos_x, pos_y or range_a, range_b
Why not posX, posY and rangeX, rangeY
or even better: since Java is an object oriented language, why not using objects to group things that belong together?
class Tupel {
long a,b;
Tupel(int a, int b){
this.a = a;
this.b = b;
}
}
Tupel pos = new Tupel(10,30);
Tupel range = new Tupe(5,59);
// ...
if (range.a > range.b) {
range = new Tupel(range.b,range.a);
// ...
Why isn't checkMode an enumeration? – Alexander
The good thing about Java enums is that they can hold logic. The enum constants are classes that extend the enum class. This way enums can improve your code by resolving if/else cascades or switch constructs with polymorphism.
You don't need to access the enum's raw values.[...] – Alexander
With that in mind you have only 2 enum constants
enum CompareMode{
RANGE_EXCLUSIVE{
@Override
protected abstract boolean isInRange(long value, long range_a, long range_b){
return value > range_a && value < range_b;
}
},
RANGE_INCLUSIVE{
@Override
protected abstract boolean isInRange(long value, long range_a, long range_b){
return value >= range_a && value =< range_b;
}
};
public boolean inRange(long value, long range_a, long range_b){
if(range_a > range_b)
return isInRange( value,range_b,range_a);
else // <- not needed but her for readability
return isInRange( value,range_a,range_b);
};
}
you complete logic is inside the enum, no extra method needed.
Now lets join that with the Tupel class:
enum CompareMode{
RANGE_EXCLUSIVE{
@Override
protected abstract boolean isInRange(long value, Tupel range){
return value > range.a && value < range.b;
}
},
RANGE_INCLUSIVE{
@Override
protected abstract boolean isInRange(long value, Tupel range){
return value >= range.a && value =< range.b;
}
};
public boolean inRange(long value, Tupel range){
if(range.a > range.b)
range=new Tupel(range.b,range.a);
return isInRange( value,range_a,range_b);
};
}
The benefit of that solution is:
- the parameter list is shorter and has no more possibility to mix the values passed in accidentally.
- if you later add another CompareMode (which is hard to imaging, but try...) the only thing you have to change is the lines for the new mode and the code where you decide which mode to use. The code that actually needs the result does not need to change.
Also, how are you calling methods in enum? – Michael
like this:
Tupel range = new Tupel(4,5);
for(CompareMode compareMode : CompareMode.values()){
System.out.println(4+" is in range with compareMode "+compareMode +" ="+compareMode.inRange(4,range);
System.out.println(5+" is in range with compareMode "+compareMode +" ="+compareMode.inRange(5,range);
}
Java's Primitive Data Types
boolean: 1-bit. May take on the values true and false only.
byte: 1 signed byte (two's complement). Covers values from -128 to 127.
short: 2 bytes, signed (two's complement), -32,768 to 32,767
int: 4 bytes, signed (two's complement). -2,147,483,648 to 2,147,483,647.
long: 8 bytes signed (two's complement). Ranges from -9,223,372,036,854,775,808 to +9,223,372,036,854,775,807.
float: 4 bytes, IEEE 754. Covers a range from 1.40129846432481707e-45 to 3.40282346638528860e+38 (positive or negative).
double: 8 bytes IEEE 754. Covers a range from 4.94065645841246544e-324d to 1.79769313486231570e+308d (positive or negative).
char: 2 bytes, unsigned, Unicode, 0 to 65,535
Java's Double class has members containing the Min and Max value for the type.
2^-1074 <= x <= (2-2^-52)·2^1023 // where x is the double.
Check out the Min_VALUE and MAX_VALUE static final members of Double.
(some)People will suggest against using floating point types for things where accuracy and precision are critical because rounding errors can throw off calculations by measurable (small) amounts.
I’ve tried looking for definitive answers but the only difference I see seems to be based on the precision of the numbers?
Which data type is larger and which one is smaller?
Double.MIN_VALUE represents the minimum positive value. (That is, a positive value close to zero.)
From the documentation:
A constant holding the smallest positive nonzero value of type double, 2-1074.
This is the reason why
System.out.println(inRange(new BigDecimal("0.0")));
System.out.println(inRange(new BigDecimal("-987.0")));
outputs false. None of the provided values are (strictly) greater than 0.
The solution
Since the range of doubles are symmetrical around origo (as opposed to integers, which stretches one step further on the negative side) you can get the minimum (negative) value by writing -Double.MAX_VALUE. That is
BigDecimal DOUBLE_MIN = BigDecimal.valueOf(-Double.MAX_VALUE);
If you see the javadoc for Double.MIN_VALUE it says
A constant holding the smallest **positive nonzero** value of type
<code>double</code>
You could add spacing ;)
if (i > 0 && i < 100)
For those using commons lang an option is to use Range:
Range<Integer> myRange = Range.between(100, 500);
if (myRange.contains(200)){
// do something
}
Also see: how to construct a apache commons 3.1 Range<Integer> object