How to round a number as follows:
If it's 7.3 I want the rounding to go up to 7.5 , but if it's 7.77 I want it to go up to 8
Another example is if it's 13.1 I want it to go to 13.5, but if it's 13.9 I want it to go to 14.
This in Java-Android, any ideas?
Thanks!
These are the common Rounding Modes for Java.
But you can make something like this answer, and create your own custom rounding strategy.
Something like:
static BigDecimal myRound(BigDecimal value) {
BigInteger fractPart = value.remainder(BigDecimal.ONE).movePointRight(bd.scale()).abs().toBigInteger();
if (fractPart.compareTo(BigInteger.valueOf(3) == 0) {
// change value to .5
} else {
// change value to .77
}
return value;
}
Related
I have an array with lat and lng in the custom model . i want to sort the array so that minimum distance from my location comes at the top position and so on.
Here is what i have tried
myLocation = new Location("");
myLocation.setLatitude(Double.valueOf(MyApplication.getInstance().getLatitude()));
myLocation.setLongitude(Double.valueOf(MyApplication.getInstance().getLongitude()));
Collections.sort(pings, new DistanceComparator());
private class DistanceComparator implements java.util.Comparator<PingModel>
{
#Override
public int compare(PingModel lhs, PingModel rhs)
{
Location lhsLocation = new Location("");
lhsLocation.setLatitude(Double.valueOf(lhs.latloc));
lhsLocation.setLongitude(Double.valueOf(lhs.lngloc));
Location rhsLocation = new Location("");
rhsLocation.setLatitude(Double.valueOf(lhs.latloc));
rhsLocation.setLongitude(Double.valueOf(lhs.lngloc));
return (int)rhsLocation.distanceTo(myLocation) - (int)lhsLocation.distanceTo(myLocation);
}
}
The result is not sure what kind of sorting it is doing but its not according to distance.
You have a copy-paste error. Change these 2 lines:
rhsLocation.setLatitude(Double.valueOf(lhs.latloc));
rhsLocation.setLongitude(Double.valueOf(lhs.lngloc));
to:
rhsLocation.setLatitude(Double.valueOf(rhs.latloc)); // It's rhs!
rhsLocation.setLongitude(Double.valueOf(rhs.lngloc)); // It's rhs!
Apart from this, you shouldn't convert to int before subtracting the distances. In fact, you should avoid using subtraction as the return value of a comparator. This has some well-known flaws, in particular, as distances are float values, they might not fit into an int. And what is more important, the result of the subtraction might not fit into an int. This means that the int you'd be returning might overflow, leading to unexpected results.
I'd recommend you to use clear, understandable code, instead of smartish, tricky code. Consider changing the last line of your comparator to a common tri-state if:
float lhsDistance = lhsLocation.distanceTo(myLocation);
float rhsDistance = rhsLocation.distanceTo(myLocation);
if (lhsDistance < rhsDistance) {
return -1;
} else if (lhsDistance > rhsDistance) {
return 1;
} else {
return 0;
}
Note: if the values you're comparing are in fact equal, then you must return 0 in your comparator. Otherwise, you might experience subtle, nasty bugs, as explained in this answer.
Not sure if this will help, but I was working on a similar project and found this link to be very helpful : http://www.geodatasource.com/developers/java .
Basically if you have you location; use the distance function to calculate new position - your position, and then sort based on this. Loop through the array of locations, and sort based on results.
Hope it helps.
Dan.
Can you try following
return Float.compare(lhsLocation.distanceTo(myLocation), rhsLocation.distanceTo(myLocation))
Converting to int before substraction might not always work. For example, if your distanceTo() function return km and the distance from your point and the data points is within 1 km then the result of subtraction may be 0.
Instead of
return (int)rhsLocation.distanceTo(myLocation) - (int)lhsLocation.distanceTo(myLocation);
Try
return (rhsLocation.distanceTo(myLocation) - lhsLocation.distanceTo(myLocation)) > 0 ? 1 : -1;
I have been trying to write a java code to Round a value to the below requirement.
If x=63.88 => roundedValue= 64.00;
If x=63.50 => roundedValue= 64.00
If x=63.32 => roundedValue= 63.32
I tried with the different roundingModes like CEILING, DOWN, FLOOR, HALFDOWN.
I also tried Math.round();
But I'm unable to get the expected output.
My input is a string and output is a string.
Please find the code snippet I tried below
BigDecimal value1 = new BigDecimal(input);
value1=value1.setScale(2, RoundingMode.HALF_EVEN);
//float rounded=Math.round(amount);
String finalValue=String.valueOf(value1);
I'm unable to get the desired output. Please let me know how to achieve this?
ps: should i consider using float or BigDecimal??
if(x%1 >= .5)
{ x = Math.round(x) }
else //do nothing
This seems like it would give you the desired output you are looking for. So if you really wanted to you could override or create your own method to call for the rounding
What you want to do with this, is providing your own MathContext to specify the behavior of the rounding you want to perform.
The closest you will get to your current requirements is either: using RoundingMode.HALF_UP or RoundingMode.UNNECESSARY
For that you will have to use BigDecimal anyways, since Double and Float do not expose rounding.
public static void main(String args[]) {
Double d = 63.18;
DecimalFormat df = new DecimalFormat("00.00");
if(d % 1 >= 0.5)
System.out.println(df.format(Math.round(d)));
else
System.out.println(d);
}
As in your post, using BigDecimal is the way to go, if you want to use decimal rounding.
If you want to round up for numbers >= X.5 and avoid rounding for numbers < X.5 then you can use this code:
import java.math.BigDecimal;
import java.math.RoundingMode;
public class Round {
public static void main(String[] args) {
System.out.println(round("63.88"));
System.out.println(round("63.50"));
System.out.println(round("63.32"));
}
private static BigDecimal round(String input) {
BigDecimal value = new BigDecimal(input);
BigDecimal rounded = value.setScale(0, RoundingMode.HALF_UP);
if (rounded.compareTo(value) > 0)
return rounded.setScale(2);
return value;
}
}
The output is:
64.00
64.00
63.32
I have a GUI which works like the following: there are 2 buttons and 1 textField. The textField is used to hold double/float values, 1 of the buttons adds a value (in this case, 0.1) and the other one subtracts (adds -0.1).
Here is my following problem: after pressing one of the buttons many times, the resulting value is not behaving the way I would like. In other words, instead of "1.5" turning into "1.6", it will be something like "1.5999998". I have tried many changes (like changing the variables types and the value to add/subtract), but none of these worked. Here's a piece of my code:
public void sumTextField(){
try{
if(textField.getText() == "")
textField.setText("0.1");
else{
float aux = Float.parseFloat(textField.getText());
aux += 0.10000000;
textField.setText(String.valueOf(aux));
}
}
catch(NumberFormatException nfe){
nfe.printStackTrace();
JOptionPane.showMessageDialog(null, "Please, provide a valid value in the text field!", "Impossible sum", JOptionPane.INFORMATION_MESSAGE);
}
}
public void subtractTextField(){
try{
if(textField.getText() == "")
textField.setText("-0.1");
else{
float aux = Float.parseFloat(textField.getText());
aux -= 0.10000000;
textField.setText(String.valueOf(aux));
}
}
catch(NumberFormatException nfe){
nfe.printStackTrace();
JOptionPane.showMessageDialog(null, "Please, provide a valid value in the text field!", "Impossible subtraction", JOptionPane.INFORMATION_MESSAGE);
}
}
Any ideas are welcome
Your problem is due to the way in which double and float work.
In floating-point arithmetic, the computer only calculates to a certain precision, i.e. after so many decimal places, it just rounds the number off. 0.1 may seem like a nice round number in decimal, but in binary it is recurring - 0.0001100110011 and so on. With each calculation, the rounding-off makes the result a bit more inaccurate. Have a look at this page for a more thorough explanation.
double is more precise than float, but it will still display rounding errors like this.
To circumvent the problem, you could do one of two things. First, as Jon Skeet said in the comments, you could use arbitrary-precision arithmetic like BigDecimal.
Alternatively, you could print out only a couple of decimal places like this:
String answer = String.format("%.2f", myNumber);
This will round off the printed value to 2 decimal places.
Hope this helps!
public class Dummy {
public static void main(String args[]) {
String x = "1.234.567,89 EUR";
String e = " EUR";
List<BigDecimal> totals = new ArrayList<BigDecimal>();
totals.add( new BigDecimal(x.replaceAll(" EUR","").replaceAll("\\.","").replaceAll(",",".")));
System.out.println(totals.get(0).add(new BigDecimal(0.10).setScale(3,0)));
}
}
With current code I get 1234567.991 and setting it to setScale(2,0) I get 1234568.00 what I am looking for is 1234567.99. Any help?
Use
System.out.println(totals.get(0).add(new BigDecimal(0.10)
.setScale(2, BigDecimal.ROUND_HALF_UP)));
Out put
1234567.99
I think there must be an inbuilt Java function for this. But otherwise, you can do it with simple mathematics.
You can multiply the number with 100. And then use ceiling or floor function of Java. And then divide it with 100. You got your desired result.
Do not use
new BigDecimal(0.10)
which is both inprecise and does not give a precision/scale of 2.
But use
new BigDecimal("0.10")
This preserves the scale.
This will give desired output.
If you want to go with double at that time we can use DecimalFormat but in bigdecimal setScale is used.
BigDecimal.valueOf(1234567.991).setScale(2, BigDecimal.ROUND_HALF_UP)
.doubleValue();
OUTPUT
1234567.99
In my app, I handle numbers as BigDecimal and store them as NUMBER(15,5). Now I'd need to properly check on Java if the BigDecimal values would fit the column, so that I can generate proper error messages without executing the SQL, catching exceptions and verifying the vendor error code. My database is Oracle 10.3, and such errors cause error 1438.
After some googling, I found no such code for that, so I came up with my own. But I'm really unsatisfied with this code... simple, but at the same time simple enough to doubt its correctness. I tested it with many values, random ones and boundaries, and it seems to work. But as I'm really bad with numbers, I'd like some more robust and well-tested code.
//no constants for easier reading
public boolean testBigDecimal(BigDecimal value) {
if (value.scale() > 5)
return false;
else if (value.precision() - value.scale() > 15 - 5)
return false;
else
return true;
}
Edit: Recent tests did not got an exception for numbers out of scale, just got silently rounded, and I'm not sure what is different between not and when I made these first tests. Such rounding is unacceptable because the application is financial, and any rounding/truncation must be explicit (through BigDecimal methods). Exception-is-gone aside, this test method must assure that the number is not too large for the desired precision, even if by non-significant digits. Sorry about the late clarification.
Thanks for your time.
I'm still curious about this question. My code is still running, and I haven't got some "proof" of correctness or fail situation, or some standard code for this kind of test.
So, I'm putting a bounty on it, hopefully getting any of these.
The following regexp would do the trick too:
public class Big {
private static final Pattern p = Pattern.compile("[0-9]{0,10}(\\.[0-9]{0,5}){0,1}");
public static void main(String[] args) {
BigDecimal b = new BigDecimal("123123.12321");
Matcher m = p.matcher(b.toString());
System.out.println(b.toString() + " is valid = " + m.matches());
}
}
This could be another way to test your code or it could be the code. The regexp requires between 0 and 10 digits optionally followed by a decimal point and 0 to 5 more digits. I didn't know if a sign was needed or not, as I think about it. Tacking something like [+-]{0,1} to the front will do.
Here is a better class, maybe, and a test class with a partial set of tests.
public class Big {
private static final Pattern p = Pattern.compile("[0-9]{0,10}(\\.[0-9]{0,5}){0,1}");
public static boolean isValid(String s) {
BigDecimal b = new BigDecimal(s);
Matcher m = p.matcher(b.toPlainString());
return m.matches();
}
}
package thop;
import junit.framework.TestCase;
/**
* Created by IntelliJ IDEA.
* User: tonyennis
* Date: Sep 22, 2010
* Time: 6:01:15 PM
* To change this template use File | Settings | File Templates.
*/
public class BigTest extends TestCase {
public void testZero1() {
assertTrue(Big.isValid("0"));
}
public void testZero2() {
assertTrue(Big.isValid("0."));
}
public void testZero3() {
assertTrue(Big.isValid("0.0"));
}
public void testZero4() {
assertTrue(Big.isValid(".0"));
}
public void testTooMuchLeftSide() {
assertFalse(Big.isValid("12345678901.0"));
}
public void testMaxLeftSide() {
assertTrue(Big.isValid("1234567890.0"));
}
public void testMaxLeftSide2() {
assertTrue(Big.isValid("000001234567890.0"));
}
public void testTooMuchScale() {
assertFalse(Big.isValid("0.123456"));
}
public void testScientificNotation1() {
assertTrue(Big.isValid("123.45e-1"));
}
public void testScientificNotation2() {
assertTrue(Big.isValid("12e4"));
}
}
one of the problems with your function is that in some cases it may be too restrictive, consider:
BigDecimal a = new BigDecimal("0.000005"); /* scale 6 */
a = a.multiply(new BigDecimal("2")); /* 0.000010 */
return testBigDecimal(a); /* returns false */
As you can see, the scale is not adjusted down. I can't test right now if something similar happens with high-end precision (1e11/2).
I would suggest a more direct route:
public boolean testBigDecimal(BigDecimal value) {
BigDecimal sqlScale = new BigDecimal(100000);
BigDecimal sqlPrecision = new BigDecimal("10000000000");
/* check that value * 1e5 is an integer */
if (value.multiply(sqlScale)
.compareTo(value.multiply(sqlScale)
.setScale(0,BigDecimal.ROUND_UP)) != 0)
return false;
/* check that |value| < 1e10 */
else if (value.abs().compareTo(sqlPrecision) >= 0)
return false;
else
return true;
}
Update
You've asked in a comment if the database would throw an error if we try to insert 0.000010. In fact the database will never throw an error if you try to insert a value with too much precision, it will silently round the inserted value.
The first check is therefore not needed to avoid an Oracle error, I was assuming that you were performing this test to make sure that the value you want to insert is equal to the value you actually inserted. Since 0.000010 and 0.00001 are equal (with BigDecimal.compareTo) shouldn't they both return the same result?
Instead if looping over thousands of random numbers, you could write test cases that stress the 'edges' - the maximum value +.00001, the maximum value, the maximum value - .00001, 0, null, the minimum value -.00001, the minimum value, the minimum value + .00001, and values with 4, 5, and 6 values to the right of the decimal point. There are probably many more.
If you have those in junit, you're good.
Well, since nobody came up with another solution, I'm leaving the code as it is.
I couldn't make this precision/scale test fail, and it always matched the regex solution, so maybe both are correct (I tested the boundaries and with over 5M randomly generated values). I'll use the precision/scale solution, as it is over 85% faster, and may it fail I replace it.
Thanks for your replies Tony.
My previous "answer", still here for history purposes, but I'm looking for a real answer =)