Is there a Java Library function which can be used to truncate a number to an arbitrary number of decimal places?
For Example.
SomeLibrary.truncate(1.575, 2) = 1.57
Thanks
Try setScale of BigDecimal like so:
public static double round(double d, int decimalPlace) {
BigDecimal bd = new BigDecimal(d);
bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP);
return bd.doubleValue();
}
Incredible no one brought this up yet, Java API has had DecimalFormat for ages now for this exact purpose.
For most numbers, you won't be able to get an exact representation of xxx.yyyy unless you use a decimal class with guaranteed accuracy, such as BigDecimal.
There's one in commons-math. Check out http://commons.apache.org/math/apidocs/org/apache/commons/math/util/MathUtils.html:
public static double round(double x,
int scale)
It's implemented using BigDecimal, and is overloaded to allow specifying a rounding method, so you can use it to truncate, like this:
org.apache.commons.math.util.MathUtils.round(1.575, 2,
java.math.BigDecimal.ROUND_DOWN);
Update:
In the last version (Math3), this method is in the class Precision.
org.apache.commons.math3.util.Precision.round(double x, int scale, int roundingMethod)
Simply remove the fractional portion
public double trunk(double value){
return value - value % 1;
}
Use this simple function
double truncateDouble(double number, int numDigits) {
double result = number;
String arg = "" + number;
int idx = arg.indexOf('.');
if (idx!=-1) {
if (arg.length() > idx+numDigits) {
arg = arg.substring(0,idx+numDigits+1);
result = Double.parseDouble(arg);
}
}
return result ;
}
I just want to add to ubuntudroid's solution.
I tried it and it wouldn't round down, so I had to add
df.setRoundingMode(RoundingMode.FLOOR);
for it to work.
here is a short implementation which is many times faster than using BigDecimal or Math.pow
private static long TENS[] = new long[19];
static {
TENS[0] = 1;
for (int i = 1; i < TENS.length; i++) TENS[i] = 10 * TENS[i - 1];
}
public static double round(double v, int precision) {
assert precision >= 0 && precision < TENS.length;
double unscaled = v * TENS[precision];
if(unscaled < Long.MIN_VALUE || unscaled > Long.MAX_VALUE)
return v;
long unscaledLong = (long) (unscaled + (v < 0 ? -0.5 : 0.5));
return (double) unscaledLong / TENS[precision];
}
Delete the assert'ions to taste. ;)
Actually, this sort of thing is easy to write:
public static double truncate(double value, int places) {
double multiplier = Math.pow(10, places);
return Math.floor(multiplier * value) / multiplier;
}
Note that it's Math.floor, because Math.round wouldn't be truncating.
Oh, and this returns a double, because that's what most functions in the Math class return (like Math.pow and Math.floor).
Caveat: Doubles suck for accuracy. One of the BigDecimal solutions should be considered first.
To do it 100% reliably, you'd have to pass the argument as string, not as floating-point number. When given as string, the code is easy to write. The reason for this is that
double x = 1.1;
does not mean that x will actually evaluate to 1.1, only to the closest exactly representable number.
created a method to do it.
public double roundDouble(double d, int places) {
return Math.round(d * Math.pow(10, (double) places)) / Math.pow(10, (double)places);
}
Related
In my PL-SQL work, I've come to regularly use the TRUNC function to check higher-position values in numeric IDs. for example:
if trunc(idValue,-3)=254000 then...
Is there a similar method available for int/Integer variables in Java?
You could take advantage of integer division here:
public int trunc(int value, int places) {
// places should be positive, not negative
int divisor = Math.pow(10, places);
int tempVal = value / divisor;
int finalVal = tempVal * divisor;
return finalVal;
}
(somewhere in your code)
if (trunc(idValue,3)==254000)
I got curious about a rounding algorithm, because in CS we had to emulate an HP35 without using the Math library. We didn't include a rounding algorithm in our final build, but I wanted to do it anyway.
public class Round {
public static void main(String[] args) {
/*
* Rounds by using modulus subtraction
*/
double a = 1.123599;
// Should you port this to another method, you can take this as a parameter
int b = 5;
double accuracy = Math.pow(10, -b);
double remainder = a % accuracy;
if (remainder >= 5 * accuracy / 10) // Divide by ten is important because remainder is smaller than accuracy
a += accuracy;
a -= remainder;
/*
* Removes round off error done by modulus
*/
String string = Double.toString(a);
int index = string.indexOf('.') + b;
string = string.substring(0, index);
a = Double.parseDouble(string);
System.out.println(a);
}
}
Is this a good algorithm, or are there any better ones? I don't care about the ones defined in the Java API, I just wanted to know how it was done.
[EDIT]
Here's the code I came up with after looking over EJP's answer
public class Round {
public static void main(String[] args) {
double a = -1.1234599;
int b = 5;
boolean negative = a < 0;
if (negative) a = -a;
String string = Double.toString(a);
char array[] = string.toCharArray();
int index = string.indexOf('.') + b;
int i = index;
int value;
if (Character.getNumericValue(array[index +1]) >= 5) {
for (; i > 0; i--) {
value = Character.getNumericValue(array[i]);
if (value != -1) {
++value;
String temp = Integer.toString(value)
array[i] = temp.charAt(temp.length()-1);
if (value <= 9) break;
}
}
}
string = "";
for (int j=0; j < index + 1 ; j++) {
string += array[j];
}
a = Double.parseDouble(string);
if (negative) a =-a;
System.out.println(a);
}
}
Floating-point numbers don't have decimal places. They have binary places, and the two are not commensurable. Any attempt to modify a floating-point variable to have a specific number of decimal places is doomed to failure.
You have to do the rounding to a specified number of decimal places after conversion to a decimal radix.
There are a different ways to round numbers. The RoundingMode documentation for Java (introduced in 1.5) should give you a brief introduction to the different methods people use.
I know you said you don't have access to the Math functions, but the simplest rounding you can do is:
public static double round(double d)
{
return Math.floor(d + 0.5);
}
If you don't want to use any Math functions, you could try something like this:
public static double round(double d)
{
return (long)(d + 0.5);
}
Those two probably behave differently in some situations (negative numbers?).
I'm making a simple calculator (I'm a beginner), and I was wondering why when I divide 1 by 4, I get 0. I know it has something to do with the type of number. Here is my code:
private static void calc(int a, int b,String op){
if (op.equals("add")){
double ans = a+b;
System.out.println(ans);
}
if(op.equals("subtract")){
double ans=a-b;
System.out.println(ans);
}
if(op.equals("multiply")){
double ans=a*b;
System.out.println(ans);
}
if(op.equals("divide")){
double ans=a/b;
System.out.println(ans);
}
}
I can't get my variable (ans) to have more than one decimal spot. And when the answer requires one (like 1/4), it just returns 0.
Help please.
You need to divide on a double since all your result values in double.
private static void calc(int a, double b,String op){
}
Or simply :
if(op.equals("divide")){
double ans=(double)a/b;
System.out.println(ans);
}
Although the other comments and answers are correct, they do not give enough detail (IMO).
Although ans is a double, the value of the right side of the equation is still an int.
double ans = a / b;
// equiv to:
// double ans = (double)(a / b);
So when you evaluate this you get:
double ans = (double)(1/4);
= (double)(0);
= 0.0d;
To get around this, you will need to cast one or both of the operands to a double.
double ans = ( (double) a ) / ( (double) b );
= ( (double) 1 ) / ( (double) 4 );
= 1.0d / 4.0d;
~= 0.25d;
Also note with regards to #Salah's answer that the cast from integer to double has just been moved. Since you can implicitly convert an int to a double, calling the function with an integer (such as the literal 1) will automatically convert the integer to a double. However, you may not want to allow non-integral numbers to be passed to your function, and if so, then this solution would not be correct.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to round a number to n decimal places in Java
I want to set a specified number of decimal digits in a float (or double), with a method in this form
public float decimalDigits(int x, float n){
....
}
for example
->if I have
float n1=36.58529
the line
float n2=decimalDigits(2, n1);
should return
n2=36.59
->if n1 is:
float n1=36.58329
the line
float n2=decimalDigits(2, n1);
should return
n2=36.58
the line
float n2=decimalDigits(1, n2);
should return
n2=36.6
etc
Use this
public float decimalDigits(int decimaldigits, float x){
final NumberFormat numFormat = NumberFormat.getNumberInstance();
numFormat.setMaximumFractionDigits(decimaldigits);
final String resultS = numFormat.format(x);
String parsable=resultS.replace(".", "");
parsable=resultS.replace(",", ".");
float ris=Float.parseFloat(parsable);
return ris;
}
I have added the String replacement to the code to avoid Parsing issue caused by the dot convention (for example 1234.34 becomes 1.234,34 after the formatting causing error in reparsing in float)
If the your is simply a format visualization problem, you could also use the String and doesn't matter that floating point variables don't have decimal places, so this is another valid method:
public String decimalDigits(int decimaldigits, float x){
final NumberFormat numFormat = NumberFormat.getNumberInstance();
numFormat.setMaximumFractionDigits(decimaldigits);
final String resultS = numFormat.format(x);
return resultS;
}
If someone has doubts about validity of this solution, should ask for details or try to compile the code and test it before downvote, thanks. The code is tested and works like a charm.
WARNING
Clearly you have to pass float because the method use Float.parseFloat, if you want to pass a double you have to use a cast to float before pass it in the method, otherwise you have to change all the method primitive and parse from float to double. Double and float are different.
It is impossible for a routine that returns a float or a double to return correctly rounded values such as 36.59 or 36.6 because these values are not representable in binary floating-point. Binary floating-point can only return values that are close, such as 36.60000000000000142108547152020037174224853515625. There is no bit pattern in binary floating-point that represents the value 36.6.
If you want decimal values, you must use a decimal radix, such as DecimalFormat or BigDecimal.
Possible pseudo code is below:
public class test {
/**
* #param args
*/
public static void main(String[] args) {
System.out.println(decimalDigits(10.09872, 4));
}
static double decimalDigits(double value, int n)
{
double decimal = value - ((int) value);
System.out.println(decimal);
double short_decimal = 0;
for(int i = 0; i < n; i++)
{
/* current digit on decimal */
decimal = decimal * 10;
System.out.println(decimal);
short_decimal += (Math.pow(10, n - i - 1) * (int)decimal);
/* find further */
decimal = decimal - (int)decimal;
}
return (int)value + (double)(short_decimal / Math.pow(10, n));
}
}
Will a double equal to an integer always cast to that integer (assuming the double is not one that causes an overflow). Example: Math.ceil() will return a double that is equal to an integer. Assuming no overflow, will it always cast to the same integer that it is supposedly equal to?
If not, how can I round up a double to an int or long?
Since Java types are fixed and Java doubles have a 52 bit mantissa, they can (with ease) represent a 32-bit Java int without rounding.
Yes, it will convert exactly. This is described in Section 5.1.3 of the JLS, which mentions
Otherwise, if the floating-point number is not an infinity, the
floating-point value is rounded to an integer value V, rounding toward
zero using IEEE 754 round-toward-zero mode...
Since your double exactly equals the int, the "rounded" value is just the exact same value, but you can read the spec for details.
All possible int values can be represented by a double without error. The simplest way to round up is to use Math.ceil() e.g.
double d =
long l = (long) Math.ceil(d); // note: could overflow.
Empirically, the answer seems to be yes - note that it also works with i2 = (int) d;.
public static void main(String[] args) {
for (int i = Integer.MIN_VALUE + 1; i < Integer.MAX_VALUE; i++) {
double d = i;
int i2 = (int) Math.ceil(d);
if (i != i2) {
System.out.println("i=" + i + " and i2=" + i2); //Never executed
}
}
}
I believe so, but you might test it yourself:
public static void main(String... args) throws Exception {
int interactions = Integer.MAX_VALUE;
int i = Integer.MIN_VALUE;
double d = Integer.MIN_VALUE;
long init = System.currentTimeMillis();
for (; i < interactions; i++, d++)
if (!(i == (int) Math.ceil(d)))
throw new Exception("something went wrong with i=" + i + " and d=" + d + ", Math.ceil(d)="+Math.ceil(d));
System.out.println("Finished in: "+(System.currentTimeMillis() - init)+"ms");
}