Round double to number in interval, defining by step - java

I have some abstract double interval, defining by step f.e.:
0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 - where interval == 0.1
0.0, 0.25, 0.5, 0.75, 1.0 - where interval == 0.25
0.0, 0.5, 1.0 - where interval == 0.5
Does Java have some instrument to "round" some double to closest number, according to interval? f.e:
0.511111 - to 0.5 in first case
0.599999 - to 0.6 in first case
0.511111 - to 0.5 in second case
0.599999 - to 0.5 in second case
0.711111 - to 0.75 in second case
0.744444 - to 0.5 in third case
0.755555 - to 1.0 in third case
0.92222 - to 1.0 in third case

Java has instruments which can round numbers to n decimal places, see How to round a number to n decimal places in Java. For rounding to any interval you specified, you may have to manually use Math.round.
Formula:
Given an interval r and a double value x to round, a simple formula is:
x_rounded = Math.round(x/r)*r;
Examples:
double x = 0.59999;
double r = 0.25; // Quarters
x = Math.round(x/r)*r;
System.out.println(x); // Result is 0.5
double x = 0.59999;
double r = 0.1; // Tenths
x = Math.round(x/r)*r;
System.out.println(x); // Result is approximately 0.6
double x = 0.31421;
double r = 0.125; // Eighths
x = Math.round(x/r)*r;
System.out.println(x); // Result is exactly 0.375
Proof:
The interval r can be thought as the value of a fractional unit.
When r = 0.25, the fractional unit is a quarter.
The value x/r represents the number of fractional units that make up x.
When x = 0.75, r = 0.25, x/r == 3, because x contains three fractional unit, which is the quarter. x/r represents the number of quarters.
Math.round(x) rounds x to the nearest integral value. Similarly, Math.round(x/r) rounds x/r to the nearest integral multiple of that fraction.
For x = 0.7, r = 0.25, we have x/r = 2.8, representing 2.8 quarters. Math.round(x/r) therefore rounds the value to the nearest quarter, 3 quarters.
Math.round(x/r)*r therefore rounds x to the nearest fractional interval r. The multiplier is needed because r is the value of each fractional unit.
For x = 0.7, r = 0.25, Math.round(x/r) represents 3 quarters. It has to be multiplied by r=0.25 to get the rounded value of x.

Use BigDecimal and setScale() to round.
However it will not work with the 0.25 precision, but you might do a workaround, something like this:
public BigDecimal round( BigDecimal value, BigDecimal precision )
{
return value.divide(precision, BigDecimal.ROUND_HALF_UP)
.round(BigDecimal.ROUND_HALF_UP)
.multiply(precision, BigDecimal.ROUND_HALF_UP);
}

Related

I am trying to calculate sine of an angle without using the Math.sin() in java

I am trying to calculate sine of an angle without using the Math.sin(). I got stuck in it's equation as I keep getting the wrong results
note I have a method that changes the angle from degrees to radians
public static double sin(double x, int precision) {
//this method is simply the sine function
double answer = 1, power = 1;
int n = 2,factorial = 1;
while (n<=precision) {
power = (power * x * x *-1) +1 ;
factorial = (factorial * (n +1))* (n-1);
answer = answer + ((power/factorial ));
n = n + 2;
}
return answer;
}
It looks like you're attempting to calculate the sine of angle given in radians using the Maclaurin series, a special case of Taylor series.
sin(x) = x - x^3/3! + x^5/5! - x^7/7! + ...
Your initial answer is 1 when it should be x. Your initial power is 1 when it should be x also.
double answer = x, power = x;
For some reason you're adding one to the power part of the result when you shouldn't be.
power = (power * x * x * -1);
You'll also need to fix your factorial calculation. Multiply by n + 1 and n, not n + 1 and n - 1.
factorial = (factorial * (n + 1)) * (n);
With these fixes, testing:
for (double angle = 0; angle <= Math.PI; angle += Math.PI / 4)
{
System.out.println("sin(" + angle + ") = " + sin(angle, 10));
}
The results are pretty good considering the limitations of precision for floating point arithmetic.
sin(0.0) = 0.0
sin(0.7853981633974483) = 0.7071067811796194
sin(1.5707963267948966) = 0.999999943741051
sin(2.356194490192345) = 0.7070959900908971
sin(3.141592653589793) = -4.4516023820965686E-4
Note that this will get more inaccurate as the values of x get larger, not just because of the inaccuracy to represent pi, but also because of the floating point calculations for adding and subtracting large values.

Floating-point precision when dealing with trigonometric functions

I have a Java class that deals with a lot of trigonometric functions using java.lang.Math. The following code determines the average direction of 0 degrees and 180 degrees. The result should be NaN, since 0 degrees and 180 degrees are in opposite directions, canceling each other out. However, when I do:
double[] angles = {0, 180};
double sines = 0;
double cosines = 0;
double avg;
for (int i = 0; i < angles.length; i++) {
double rad = Math.toRadians(angles[i]);
sines += Math.sin(rad);
cosines += Math.cos(rad);
}
double sin = sines / angles.length;
double cos = cosines / angles.length;
System.out.println("Avg sin: " + sin + "\nAvg cos: " + cos); // sin != 0 but it should
double avgRad = Math.atan2(sin, cos);
avg = Math.toDegrees(avgRad);
System.out.println("Average: " + avg);
avg equals 90.0 instead of NaN. This is because the average sine of 180 degrees and 0 degrees results in a very small but positive number (due to the way floating-point precision works). If you run the above code you will see what I mean. How can I avoid this lack of precision? I know that I could round the average sines and cosines as well as the final result, but that seems a little inelegant to me.
I take it granted that you must have considered averaging angles directly (by using mod 360) before you went onto use sin/cos/tan. That being said, I think, you are in right direction in getting what you intended in your code (except possibly the negative sign flip in the last example).
~> java Main 0 180
Avg sin: 6.123233995736766E-17
Avg cos: 0.0
Average: 90.0
~> java Main 0 179
Avg sin: 0.00872620321864172
Avg cos: 7.615242180436521E-5
Average: 89.50000000000011
~> java Main 1 179
Avg sin: 0.017452406437283477
Avg cos: 0.0
Average: 90.0
~> java Main 1 180
Avg sin: 0.008726203218641817
Avg cos: -7.615242180436521E-5
Average: 90.49999999999991
~> java Main 1 181
Avg sin: 1.5959455978986625E-16
Avg cos: 0.0
Average: 90.0
~> java Main 1 182
Avg sin: -0.008723545132608694
Avg cos: 2.2843406864775373E-4
Average: -88.50000000000001

Generating decimal random numbers in Java in a specific range?

How can I generate a random whole decimal number between two specified variables in java,
e.g. x = -1 and y = 1 would output any of -1.0, -0.9, -0.8, -0.7,….., 0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.9, 1.0?
Note: it should include 1 and -1 ([-1,1]) . And give one decimal number after point.
Random r = new Random();
double random = (r.nextInt(21)-10) / 10.0;
Will give you a random number between [-1, 1] with stepsize 0.1.
And the universal method:
double myRandom(double min, double max) {
Random r = new Random();
return (r.nextInt((int)((max-min)*10+1))+min*10) / 10.0;
}
will return doubles with step size 0.1 between [min, max].
If you just want between -1 and 1, inclusive, in .1 increments, then:
Random rand = new Random();
float result = (rand.nextInt(21) - 10) / 10.0;

Android - How to customize rounding value?

Hi i really bad at rounding. i am trying to round up a value to the rounding of my country currency.
The rounding example will be :
1.01 > 1.00
1.02 > 1.00
1.03 > 1.05
1.04 > 1.05
1.06 > 1.05
1.07 > 1.05
1.08 > 1.10
1.09 > 1.10
How can i do this kind of rounding? Thanks a lot .
Looks like you're rounding by 0.05 = 1/20th. So the following works:
public static double roundCurrency( double value ) {
return Math.round(value * 20.0 ) / 20.0;
}
This seems to give you the correct mappings - you may need to tweak it when you decide exactly where the cutoffs are.
public void test() {
double [] tests = new double[] {1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9};
for ( double d : tests) {
System.out.println(" "+d + " -> "+round(d, .05, 0.5));
}
}
double round(double d, double fraction, double bias) {
return Math.floor(d / fraction + bias) * fraction;
}
This prints:
1.01 -> 1.0
1.02 -> 1.0
1.03 -> 1.05
1.04 -> 1.05
1.05 -> 1.05
1.06 -> 1.05
1.07 -> 1.05
1.08 -> 1.1
1.09 -> 1.1
double roundedvalue= Math.round( YourValue* 100.0 ) / 100.0;
double roundedvalue= Math.round( YourValue* 2.0 ) / 2.0;
Math.round lets you round a number to the nearest integer. It looks like you're trying to round to the nearest multiple of 0.5. The general way to solve problems like that is
roundedValue = Math.round (X / M) * M;
to round to the nearest multiple of M. So in your case that would be
roundedValue = Math.round (X / 0.5) * 0.5;
which is the same as
roundedValue = Math.round (X * 2.0) / 2.0;
Similarly, if you wanted to round something to the nearest multiple of, say, 0.01, one of these would work:
roundedValue = Math.round (X / 0.01) * 0.01;
roundedValue = Math.round (X * 100.0) / 100.0;
EDIT: It looks like you've changed your question, so what I said earlier about rounding to the nearest multiple of 0.5 isn't correct any more, and now you're rounding to the nearest multiple of 0.05. Anyway, the general method I've discussed still works.
Take a look at the http://docs.oracle.com/javase/6/docs/api/java/lang/Math.html documentation on the Math Class. It lets you perform operations such as Math.round(double x) and
Math.ceil(double x) and Math.floor(double x) . You can use these in combination with an if else statement such as
double value = 1.6;
String valueToString = Double.toString(value);
String [] numbers = valueToString.split(".");
String decimalNums = numbers[1];
int decimal = Integer.parseInt(decimalNums);
if(decimal > 0 && decimal < 5){
decimal = Math.floor(decimal);
}else if(decimal >= 5 && decimal < 8){
decimal = 5;
}else{
decimal = Math.ceil(decimal);
}
This will only work for values that have one decimal place. But its a start. Hope it helps a little.

Very unusual rounding

Did you ever make a rounding like that:
[0.95,1) rounds to 1
[0.90,0.95) rounds to 0.95
[0.85,0.90) rounds to 0.90
[0.80,0.85) rounds to 0.85
I tried to do like this:
double rounded = Math.round(x * 20.0) / 20.0;
But it rounds a bit different, for example it rounds 0.91 to 0.90 and I rather need it to round 0.91 to 0.95
The number you're looking for can be found by
Multiplying your number by 20.
Computing the floor of your number.
Dividing your number by 20.
Adding 0.05
For example, ⌊ 0.95 * 20 ⌋ / 20 + 0.05 = ⌊ 19 ⌋ / 20 + 0.05 = 0.95 + 0.05 = 1.00.
In Java:
double result = Math.floor(x * 20.0) / 20.0 + 0.05;
Hope this helps!

Categories