How to cast to integer and don't lose precision - java

I have a double value which is very close to 1. How can I cast it to 1 ?
I do this
double myValue = 0.9999;
double a = Math.round(myValue);
int intValue = (int)a;
But it return 1 even if myValue is in the the range [0.5 , 1], so I lose precision. I want it return 1 only if myValuse is so close to 1 (exp : 0.999) and it should not return 1 when myValue is 0.6 for example.
Thank u for ur help

Math.round is specifically designed to do that. If you want to do something different, you'll have to code it yourself.
For instance, if you want .8 and higher to round to 1 instead of .5 and higher (see note below about negative numbers):
double myValue = 0.9999;
int base = (int)Math.floor(myValue);
double remainder = myValue - base;
int intValue = remainder >= .8 ? base + 1 : base;
Live Example
There, we:
Get the whole number part (Math.floor) into base, truncating the fractional portion
Get just the fractional portion into remainder
Add one to base if the fractional portion is >= .8
Obviously, you'll have to choose the point at which you round up, since you want something other than .5.
If you want to handle negative numbers, it's more complicated, since Math.floor will always go toward positive infinity. So you may have to branch on the sign of myValue and use Math.ceil instead when negative (and adjust the myValue - base accordingly). And then there's the entire question of whether the same kind of cutoff applies, or is it symmetrical? Should that cutoff be -0.8 or -0.2? I leave handling negative values in the manner you want as an exercise for you...
That said, this feels more complicated than it should be. Perhaps something like what's described in Dawood ibn Kareem's comment would work for what you're trying to do. (May have to be + 0.3 rather than - 0.3 when handling negatives. Or not.)

Try something like:
final double threshold = 0.0001;
if (Math.abs(a - 1) < threshold)
intValue = 1;
else
intValue = 0;
This will set intValue to 1 when a is "close enough to 1" (ie. within threshold of 1), and will set intValue to 0 otherwise (assuming you want it rounded to 0 if it's not within the threshold).
You can adjust the value of the threshold to tighten or loosen the range around 1 that it'll handle.
Alternatively, if you want to round to 1 if it's just above a given value, you can do eg.:
if (a >= 0.9999)
intValue = 1;
else
intValue = 0;

Related

Efficient way of finding the number of decimals a double value has

I want to find an effiecient way of making sure that the number of decimal places in
double is not more than three.
double num1 = 10.012; //True
double num2 = 10.2211; //False
double num2 = 10.2; //True
Currently, what I do is just use a regex split and count index of . like below.
String[] split = new Double(num).toString().split("\\.")
split[0].length() //num of decimal places
Is there an efficient or better way to do this since I'll be calling this
function a lot?
If you want a solution that will tell you that information in a way that will agree with the eventual result of converting the double to a string, then efficiency doesn't really come into it; you basically have to convert to string and check. The result is that it's entirely possible for a double to contain a value that mathematically has a (say) non-zero value in (say) the hundred-thousandth place, but which when converted to string will not. Such is the joy of IEEE-754 double-precision binary floating point: The number of digits you get from the string representation is only as many as necessary to distinguish the value from its adjacent representable value. From the Double docs:
How many digits must be printed for the fractional part of m or a? There must be at least one digit to represent the fractional part, and beyond that as many, but only as many, more digits as are needed to uniquely distinguish the argument value from adjacent values of type double. That is, suppose that x is the exact mathematical value represented by the decimal representation produced by this method for a finite nonzero argument d. Then d must be the double value nearest to x; or if two double values are equally close to x, then d must be one of them and the least significant bit of the significand of d must be 0.
But if you're not concerned about that, and assuming limiting your value range to long is okay, you can do something like this:
private static boolean onlyThreePlaces(double v) {
double d = (double)((long)(v * 1000)) / 1000;
return d == v;
}
...which should have less memory overhead than a String-round-trip.
However, I'd be surprised if there weren't a fair number of times when that method and the result of Double.toString(double) didn't match in terms of digits after the decimal, for the reasons given above.
In a comment on the question, you've said (when I asked about the value range):
Honestly I'm not sure. I'm dealing with prices; For starters, I'll assume 0-200K
Using double for financial values is usually not a good idea. If you don't want to use BigDecimal because of memory concerns, pick your precision and use int or long depending on your value range. For instance, if you only need to-the-penny precision, you'd use values multiplied by 100 (e.g., 2000 is Ⓠ20 [or whatever currency you're using, I'm using Ⓠ for quatloos]). If you need precision to thousanths of a penny (as your question suggests), then multiply by 100000 (e.g., 2000000 is Ⓠ20). If you need more precision, pick a larger multiplier. Even if you go to hundred-thousanths of a penny (muliplier: 10000000), with long you have a range of Ⓠ-922,337,203,685 to Ⓠ922,337,203,685.
This has the side-benefit that it makes this check easier: Just a straight %. If your multiplier is 10000000 (hundred-thousandths of a penny), it's just value % 10000 != 0 to identify invalid ones (or value % 10000 == 0 to identify valid ones).
long num1 = 100120000; // 10.012 => true
// 100120000 % 10000 is 0 = valid
long num2 = 102211000; // 10.2211 => false
// 102211000 % 10000 is 1000 = invalid
long num3 = 102000000; // 10.2 => true
// 102000000 % 10000 is 0 = valid

Generating random integer between 1 and infinity

I would like to create an integer value between 1 and infinity. I want to have a probability distribution where the smaller the number is, the higher the chance it is generated.
I generate a random value R between 0 and 2.
Take the series
I want to know the smallest m with which my sum is bigger than R.
I need a fast way to determine m. This is would be pretty straightforward if i had R in binary, since m would be equal to the number of 1's my number has in a row from the most significant bit, plus one.
There is an upper limit on the integer this method can generate: integer values have an upper limit and double precision can also only reach so high in the [0;2[ interval. This is irrelevant, however, since it depends on the accuracy of the data representation method.
What would be the fastest way to determine m?
Set up the inequality
R <= 2 - 2**-m
Isolate the term with m
2**-m <= 2 - R
-m <= log2(2-R)
m >= -log2(2-R).
So it looks like you want ceiling(-log2(2-R)). This is basically an exponential distribution with discretization -- the algorithm for an exponential is -ln(1-U)/rate, where U is a Uniform(0,1) and 1/rate is the desired mean.
I think, straightforward solution will be OK as this series converges really fast:
if (r >= 2)
throw new IllegalArgumentException();
double exp2M = 1 / (2 - r);
int x = (int)exp2M;
int ans = 0;
while (x > 0) {
++ans;
x >>= 2;
}
return ans;

Double Values Increases Randomly

The double Value increases randomly.
for(double i=-1;i<=1;i+=0.1)
{
for(double j=-1;j<=1;j+=0.1)
{
//logic
system.out.print(i);
system.out.print(j);
}
}
Here, the value comes like:
-1, -0.9, -0.8, -0.69, -0.51 ....-0.099 , 1.007 (WHY, U ARE GREATER THAN 1)
The output is not same but kind of this.
But, I want the exact values only. WHat should I do ??
You can use an integer counter, and multiply to get the double:
for(int i = -10; i <= 10; i++) {
double iDouble = 0.1 * i;
....
}
The double will still have rounding error - that is inevitable - but the rounding error will not affect the loop count.
You can't get exact values do to the limitations of doubles. They can't always represent exactly the decimal you want, and they have precision errors. In your case you may want to cast the double to an int for the double comparison, but as #alex said you shouldn't be doing this.
This is due to the way that doubles are stored in memory, they are only exact if the fractional part is a negative power of two, e.g. 0, 1/2, 1/4, etc. This is also why you should never use equality statements for doubles, but rather > and <. For exact calculations, you could use BigDecimal:
BigDecimal bigDecimal = new BigDecimal(123.45);
bigDecimal = bigDecimal.add(new BigDecimal(123.45));
System.out.println(bigDecimal.floatValue()); // prints 246.9
As said here, floating-point variables must not be used as loop counters. Limited-precision IEEE 754 floating-point types cannot represent:
all simple fractions exactly
all decimals precisely, even when the decimals can be represented in a small number of digits.
all digits of large values, meaning that incrementing a large floating-point value might not change that value within the available precision.
(...) Using floating-point loop counters can lead to unexpected behavior.
Instead, use integer loop counter and increment another variable inside this loop like this:
for (int count = 1; count <= 20; count += 1) {
double x = -1 + count * 0.1;
/* ... */
}

Impose numerical limit using mathematics

I want to return a number that doesn't exceed a limit I set. For example I want to do the equivalent of:
if (number >= limit)
number = limit;
return number;
Is there a mathematical way of doing the equivalent of what I just described in just one line?
You could:
return Math.min(number, limit);
or:
return number >= limit ? limit : number;
There's also the following mathematical formula: (taken from here)
min(a,b) = 1/2 (a + b - |a - b|)
Code:
return ( number + limit - Math.abs(number - limit) ) / 2;
Now Math.abs looks pretty similar to Math.min (so there wouldn't be much point to using the above instead of simply Math.min), although you could easily replace that with the method presented here or here:
mask = n >> 31 // 11111111 for negative and 00000000 for positive
abs = (mask + n)^mask // convert negative to positive in 2's complement
// while not changing positive
Note:
If number + limit can overflow, this won't work. This can be changed to
number - Math.abs(...) + limit to avoid this, but then number - Math.abs(...) can still underflow - you just need to keep overflow in mind and select the option that would prevent over/underflow based on the range of the numbers, or go for the non-arithmetic option.
Also keep in mind that, assuming no over/underflow, if you're dealing with floating point values (float / double) rather than integral types, the result of the above won't necessarily return either of the values (because of the way floating point representation works).

Always Round UP a Double

How could I always round up a double to an int, and never round it down.
I know of Math.round(double), but I want it to always round up.
So if it was 3.2, it gets rounded to 4.
You can use Math.ceil() method.
See JavaDoc link: https://docs.oracle.com/javase/10/docs/api/java/lang/Math.html#ceil(double)
From the docs:
ceil
public static double ceil(double a)
Returns the smallest (closest to negative infinity) double value that is greater than or equal to the argument and is equal to a mathematical integer. Special cases:
If the argument value is already equal to a mathematical integer, then the result is the same as the argument.
If the argument is NaN or an infinity or positive zero or negative zero, then the result is the same as the argument.
If the argument value is less than zero but greater than -1.0, then the result is negative zero.
Note that the value of Math.ceil(x) is exactly the value of -Math.floor(-x).
Parameters:
a - a value.
Returns:
The smallest (closest to negative infinity) floating-point value that is greater than or equal to the argument and is equal to a mathematical integer.
In simple words,
Math.ceil will always round UP or as said above, in excess.
Math.round will round up or down depending on the decimals.
If the decimal is equal or higher than 5, then it's rounded up.
decimal => 5. (1,5 = 2)
If the decimal is less than 5, then it's rounded down.
decimal < 5. (1,45 = 1)
Examples of Math.ceil and Math.round:
The code Below would return:
Cost, without Ceil 2.2 and with Ceil 3 (int), 3.0 (double). If we round it: 2
int m2 = 2200;
double rate = 1000.0;
int costceil = (int)Math.ceil(m2/rate);
double costdouble = m2/rate;
double costdoubleceil = Math.ceil(m2/rate);
int costrounded = (int)Math.round(m2/rate);
System.out.println("Cost, without Ceil "+costdouble+" and with Ceil "+
costceil+"(int), "+costdoubleceil+"(double). If we round it: "+costrounded);
If we change the value of m2 to for example 2499, the result would be:
Cost, without Ceil 2.499 and with Ceil 3 (int), 3.0 (double). If we round it: 2
If we change the value of m2 to for example 2550, the result would be:
Cost, without Ceil 2.55 and with Ceil 3 (int), 3.0 (double). If we round it: 3
Hope it helps. (Information extracted from previous answers, i just wanted to make it clearer).
tl;dr
BigDecimal( "3.2" ).setScale( 0 , RoundingMode.CEILING )
4
BigDecimal
If you want accuracy rather than performance, avoid floating point technology. That means avoiding float, Float, double, Double. For accuracy, use BigDecimal class.
On a BigDecimal, set the scale, the number of digits to the right of the decimal place. If you want no decimal fraction, set scale to zero. And specify a rounding mode. To always round an fraction upwards, use RoundingMode.CEILING, documented as:
Rounding mode to round towards positive infinity. If the result is positive, behaves as for RoundingMode.UP; if negative, behaves as for RoundingMode.DOWN. Note that this rounding mode never decreases the calculated value. So for example, 1.1 becomes 2, and your 3.2 becomes 4.
BigDecimal bd = new BigDecimal( "3.2" ) ;
BigDecimal bdRounded = bd.setScale( 0 , RoundingMode.CEILING ) ;
String output = bdRounded.toString() ;
System.out.println( "bdRounded.toString(): " + bdRounded ) ; // 4
4
See this code run live at IdeOne.com.
private int roundUP(double d){
double dAbs = Math.abs(d);
int i = (int) dAbs;
double result = dAbs - (double) i;
if(result==0.0){
return (int) d;
}else{
return (int) d<0 ? -(i+1) : i+1;
}
}
Good job ! ;)
My method is relatively simple, hope it works for you.
In my case I have a row of objects that can only hold 3 items and I must adjust the number of rows I have to accommodate the items.
So I have some Double numberOfRows, I then use numberOfRows.intValue() to get an int value for numberOfRows.
if the int value I get is less than numberOfRows, I add 1 to numberOfRows to round it up, else the value I get from numberOfRows.intValue() is the answer I want.
I wrote this simple for loop to test it out:
for(int numberOfItems = 0; numberOfItems < 16; numberOfItems++) {
Double numberOfRows = numberOfItems / 3.0;
System.out.println("Number of rows are: " + numberOfRows);
System.out.println("Number of items are: " + numberOfItems);
if(numberOfRows.intValue() < numberOfRows) {
System.out.println("int number of rows are: " + (numberOfRows.intValue() + 1));
}
else {
System.out.println("int value of rows are: " + numberOfRows.intValue());
}
System.out.println();
System.out.println();
}
Short example without using Math.ceil().
public double roundUp(double d){
return d > (int)d ? (int)d + 1 : d;
}
Exaplanation:
Compare operand to rounded down operand using typecast, if greater return rounded down argument + 1 (means round up) else unchanged operand.
Example in Pseudocode
double x = 3.01
int roundDown = (int)x // roundDown = 3
if(x > roundDown) // 3.01 > 3
return roundDown + 1 // return 3.0 + 1.0 = 4.0
else
return x // x equals roundDown
Anyway you should use Math.ceil(). This is only meant to be a simple example of how you could do it by yourself.
Math.ceil did not work for me. It keeps rounding down when I cast back to long. Below is my hack:
long pages = (userCnt % size) == 0 ? (userCnt / size) : (userCnt / size) + 1;
Simply check if Even or Odd and if Odd, add 1 to the result.
Math.ceil() will give you the closest lowest value if you want it to be rounded to largest closest values you should use Math.floor()

Categories