How to properly truncate a double - java

How to properly truncate a double in Java, so for example 1.99999999999999999 is always truncated to 1 and not rounded upto 2 as is the case in the sample below.
double d1 = 1.999999999999999999;
double d2 = 1.0;
long i1 = (long)Math.floor(d1);
long i2 = (long)Math.floor(d2);
System.out.println("i1="+i1 + " i2="+i2); //i1 == 2
Running sample here: http://www.browxy.com/SubmittedCode/42603
Solution
Use BigDecimal which has arbitary precision
BigDecimal bd = new BigDecimal("0.9999999999999999999999999999");
bd = bd.setScale(0, BigDecimal.ROUND_DOWN); //truncate

1.99999999999999999 is not rounded up to 2, it is 2.
System.out.println(1.999999999999999999); // 2
System.out.println(1.999999999999999999 == 2); // true
Floating-point numbers aren't infinitely precise. There aren't enough bits in the storage format Java uses (IEEE double) to distinguish between 1.999999999999999999 and 2.
If you need more accuracy than that, try a different number format, such as BigDecimal.

I think your d1 has too much precision to be expressed as a double.
If you print d1 directly to System.out you get 2.0.
So any call to floor or round has no effect.
If you need such a precision you should go for BigDecimal.

Some of the examples are explained here
Documentation
double d1 = 1.999999999999999999;
double d2 = 1.0;
long i1 = (long)Math.round(d1);
long i2 = (long)Math.floor(d2);
System.out.println("i1="+i1 + " i2="+i2);
Then the output will be
i1=2 i2=1

Related

keep trailing zeros for doubla value java [duplicate]

This question already has answers here:
How to round a number to n decimal places in Java
(39 answers)
Closed 8 years ago.
If the value is 200.3456, it should be formatted to 200.34.
If it is 200, then it should be 200.00.
Here's an utility that rounds (instead of truncating) a double to specified number of decimal places.
For example:
round(200.3456, 2); // returns 200.35
Original version; watch out with this
public static double round(double value, int places) {
if (places < 0) throw new IllegalArgumentException();
long factor = (long) Math.pow(10, places);
value = value * factor;
long tmp = Math.round(value);
return (double) tmp / factor;
}
This breaks down badly in corner cases with either a very high number of decimal places (e.g. round(1000.0d, 17)) or large integer part (e.g. round(90080070060.1d, 9)). Thanks to Sloin for pointing this out.
I've been using the above to round "not-too-big" doubles to 2 or 3 decimal places happily for years (for example to clean up time in seconds for logging purposes: 27.987654321987 -> 27.99). But I guess it's best to avoid it, since more reliable ways are readily available, with cleaner code too.
So, use this instead
(Adapted from this answer by Louis Wasserman and this one by Sean Owen.)
public static double round(double value, int places) {
if (places < 0) throw new IllegalArgumentException();
BigDecimal bd = BigDecimal.valueOf(value);
bd = bd.setScale(places, RoundingMode.HALF_UP);
return bd.doubleValue();
}
Note that HALF_UP is the rounding mode "commonly taught at school". Peruse the RoundingMode documentation, if you suspect you need something else such as Bankers’ Rounding.
Of course, if you prefer, you can inline the above into a one-liner:
new BigDecimal(value).setScale(places, RoundingMode.HALF_UP).doubleValue()
And in every case
Always remember that floating point representations using float and double are inexact.
For example, consider these expressions:
999199.1231231235 == 999199.1231231236 // true
1.03 - 0.41 // 0.6200000000000001
For exactness, you want to use BigDecimal. And while at it, use the constructor that takes a String, never the one taking double. For instance, try executing this:
System.out.println(new BigDecimal(1.03).subtract(new BigDecimal(0.41)));
System.out.println(new BigDecimal("1.03").subtract(new BigDecimal("0.41")));
Some excellent further reading on the topic:
Item 48: "Avoid float and double if exact answers are required" in Effective Java (2nd ed) by Joshua Bloch
What Every Programmer Should Know About Floating-Point Arithmetic
If you wanted String formatting instead of (or in addition to) strictly rounding numbers, see the other answers.
Specifically, note that round(200, 0) returns 200.0. If you want to output "200.00", you should first round and then format the result for output (which is perfectly explained in Jesper's answer).
If you just want to print a double with two digits after the decimal point, use something like this:
double value = 200.3456;
System.out.printf("Value: %.2f", value);
If you want to have the result in a String instead of being printed to the console, use String.format() with the same arguments:
String result = String.format("%.2f", value);
Or use class DecimalFormat:
DecimalFormat df = new DecimalFormat("####0.00");
System.out.println("Value: " + df.format(value));
I think this is easier:
double time = 200.3456;
DecimalFormat df = new DecimalFormat("#.##");
time = Double.valueOf(df.format(time));
System.out.println(time); // 200.35
Note that this will actually do the rounding for you, not just formatting.
The easiest way, would be to do a trick like this;
double val = ....;
val = val*100;
val = Math.round(val);
val = val /100;
if val starts at 200.3456 then it goes to 20034.56 then it gets rounded to 20035 then we divide it to get 200.34.
if you wanted to always round down we could always truncate by casting to an int:
double val = ....;
val = val*100;
val = (double)((int) val);
val = val /100;
This technique will work for most cases because for very large doubles (positive or negative) it may overflow. but if you know that your values will be in an appropriate range then this should work for you.
Please use Apache commons math:
Precision.round(10.4567, 2)
function Double round2(Double val) {
return new BigDecimal(val.toString()).setScale(2,RoundingMode.HALF_UP).doubleValue();
}
Note the toString()!!!!
This is because BigDecimal converts the exact binary form of the double!!!
These are the various suggested methods and their fail cases.
// Always Good!
new BigDecimal(val.toString()).setScale(2,RoundingMode.HALF_UP).doubleValue()
Double val = 260.775d; //EXPECTED 260.78
260.77 - WRONG - new BigDecimal(val).setScale(2,RoundingMode.HALF_UP).doubleValue()
Double val = 260.775d; //EXPECTED 260.78
260.77 - TRY AGAIN - Math.round(val * 100.d) / 100.0d
Double val = 256.025d; //EXPECTED 256.03d
256.02 - OOPS - new DecimalFormat("0.00").format(val)
// By default use half even, works if you change mode to half_up
Double val = 256.025d; //EXPECTED 256.03d
256.02 - FAIL - (int)(val * 100 + 0.5) / 100.0;
double value= 200.3456;
DecimalFormat df = new DecimalFormat("0.00");
System.out.println(df.format(value));
If you really want the same double, but rounded in the way you want you can use BigDecimal, for example
new BigDecimal(myValue).setScale(2, RoundingMode.HALF_UP).doubleValue();
double d = 28786.079999999998;
String str = String.format("%1.2f", d);
d = Double.valueOf(str);
For two rounding digits. Very simple and you are basically updating the variable instead of just display purposes which DecimalFormat does.
x = Math.floor(x * 100) / 100;
Rounding a double is usually not what one wants. Instead, use String.format() to represent it in the desired format.
In your question, it seems that you want to avoid rounding the numbers as well? I think .format() will round the numbers using half-up, afaik?
so if you want to round, 200.3456 should be 200.35 for a precision of 2. but in your case, if you just want the first 2 and then discard the rest?
You could multiply it by 100 and then cast to an int (or taking the floor of the number), before dividing by 100 again.
200.3456 * 100 = 20034.56;
(int) 20034.56 = 20034;
20034/100.0 = 200.34;
You might have issues with really really big numbers close to the boundary though. In which case converting to a string and substring'ing it would work just as easily.
value = (int)(value * 100 + 0.5) / 100.0;

Double in 2 decimal format [duplicate]

This question already has answers here:
How to round a number to n decimal places in Java
(39 answers)
Closed 8 years ago.
If the value is 200.3456, it should be formatted to 200.34.
If it is 200, then it should be 200.00.
Here's an utility that rounds (instead of truncating) a double to specified number of decimal places.
For example:
round(200.3456, 2); // returns 200.35
Original version; watch out with this
public static double round(double value, int places) {
if (places < 0) throw new IllegalArgumentException();
long factor = (long) Math.pow(10, places);
value = value * factor;
long tmp = Math.round(value);
return (double) tmp / factor;
}
This breaks down badly in corner cases with either a very high number of decimal places (e.g. round(1000.0d, 17)) or large integer part (e.g. round(90080070060.1d, 9)). Thanks to Sloin for pointing this out.
I've been using the above to round "not-too-big" doubles to 2 or 3 decimal places happily for years (for example to clean up time in seconds for logging purposes: 27.987654321987 -> 27.99). But I guess it's best to avoid it, since more reliable ways are readily available, with cleaner code too.
So, use this instead
(Adapted from this answer by Louis Wasserman and this one by Sean Owen.)
public static double round(double value, int places) {
if (places < 0) throw new IllegalArgumentException();
BigDecimal bd = BigDecimal.valueOf(value);
bd = bd.setScale(places, RoundingMode.HALF_UP);
return bd.doubleValue();
}
Note that HALF_UP is the rounding mode "commonly taught at school". Peruse the RoundingMode documentation, if you suspect you need something else such as Bankers’ Rounding.
Of course, if you prefer, you can inline the above into a one-liner:
new BigDecimal(value).setScale(places, RoundingMode.HALF_UP).doubleValue()
And in every case
Always remember that floating point representations using float and double are inexact.
For example, consider these expressions:
999199.1231231235 == 999199.1231231236 // true
1.03 - 0.41 // 0.6200000000000001
For exactness, you want to use BigDecimal. And while at it, use the constructor that takes a String, never the one taking double. For instance, try executing this:
System.out.println(new BigDecimal(1.03).subtract(new BigDecimal(0.41)));
System.out.println(new BigDecimal("1.03").subtract(new BigDecimal("0.41")));
Some excellent further reading on the topic:
Item 48: "Avoid float and double if exact answers are required" in Effective Java (2nd ed) by Joshua Bloch
What Every Programmer Should Know About Floating-Point Arithmetic
If you wanted String formatting instead of (or in addition to) strictly rounding numbers, see the other answers.
Specifically, note that round(200, 0) returns 200.0. If you want to output "200.00", you should first round and then format the result for output (which is perfectly explained in Jesper's answer).
If you just want to print a double with two digits after the decimal point, use something like this:
double value = 200.3456;
System.out.printf("Value: %.2f", value);
If you want to have the result in a String instead of being printed to the console, use String.format() with the same arguments:
String result = String.format("%.2f", value);
Or use class DecimalFormat:
DecimalFormat df = new DecimalFormat("####0.00");
System.out.println("Value: " + df.format(value));
I think this is easier:
double time = 200.3456;
DecimalFormat df = new DecimalFormat("#.##");
time = Double.valueOf(df.format(time));
System.out.println(time); // 200.35
Note that this will actually do the rounding for you, not just formatting.
The easiest way, would be to do a trick like this;
double val = ....;
val = val*100;
val = Math.round(val);
val = val /100;
if val starts at 200.3456 then it goes to 20034.56 then it gets rounded to 20035 then we divide it to get 200.34.
if you wanted to always round down we could always truncate by casting to an int:
double val = ....;
val = val*100;
val = (double)((int) val);
val = val /100;
This technique will work for most cases because for very large doubles (positive or negative) it may overflow. but if you know that your values will be in an appropriate range then this should work for you.
Please use Apache commons math:
Precision.round(10.4567, 2)
function Double round2(Double val) {
return new BigDecimal(val.toString()).setScale(2,RoundingMode.HALF_UP).doubleValue();
}
Note the toString()!!!!
This is because BigDecimal converts the exact binary form of the double!!!
These are the various suggested methods and their fail cases.
// Always Good!
new BigDecimal(val.toString()).setScale(2,RoundingMode.HALF_UP).doubleValue()
Double val = 260.775d; //EXPECTED 260.78
260.77 - WRONG - new BigDecimal(val).setScale(2,RoundingMode.HALF_UP).doubleValue()
Double val = 260.775d; //EXPECTED 260.78
260.77 - TRY AGAIN - Math.round(val * 100.d) / 100.0d
Double val = 256.025d; //EXPECTED 256.03d
256.02 - OOPS - new DecimalFormat("0.00").format(val)
// By default use half even, works if you change mode to half_up
Double val = 256.025d; //EXPECTED 256.03d
256.02 - FAIL - (int)(val * 100 + 0.5) / 100.0;
double value= 200.3456;
DecimalFormat df = new DecimalFormat("0.00");
System.out.println(df.format(value));
If you really want the same double, but rounded in the way you want you can use BigDecimal, for example
new BigDecimal(myValue).setScale(2, RoundingMode.HALF_UP).doubleValue();
double d = 28786.079999999998;
String str = String.format("%1.2f", d);
d = Double.valueOf(str);
For two rounding digits. Very simple and you are basically updating the variable instead of just display purposes which DecimalFormat does.
x = Math.floor(x * 100) / 100;
Rounding a double is usually not what one wants. Instead, use String.format() to represent it in the desired format.
In your question, it seems that you want to avoid rounding the numbers as well? I think .format() will round the numbers using half-up, afaik?
so if you want to round, 200.3456 should be 200.35 for a precision of 2. but in your case, if you just want the first 2 and then discard the rest?
You could multiply it by 100 and then cast to an int (or taking the floor of the number), before dividing by 100 again.
200.3456 * 100 = 20034.56;
(int) 20034.56 = 20034;
20034/100.0 = 200.34;
You might have issues with really really big numbers close to the boundary though. In which case converting to a string and substring'ing it would work just as easily.
value = (int)(value * 100 + 0.5) / 100.0;

How do you reduce a java double to n significant digits?

I am looking to print small digits (doubles) for the purpose of printing the errors in using the Newton & Secant methods.
One of my errors is 5.433306166802499E-5
I'd like to print 5.4333E-5
I thought of using BigDecimal but I am not familiar with this class.
I am looking to print small digits (doubles)
System.out.printf("%.4e", 5.433306166802499E-5);
Result: 5.4333e-05
Note: it doesn't reduce the precision of your original value, it just prints it with a lower precision.
double d = 5.433306166802499E-5;
BigDecimal dc = new BigDecimal(d);
dc = dc .round(new MathContext(3)); // desired significant digits
double rounded = dc .doubleValue();
You can indeed use BigDecimal, it would then look as follows:
BigDecimal d = BigDecimal.valueOf(val).setScale(scale, RoundingMode.HALF_UP);
double scaled = d.doubleValue();
Or you could use:
Math.round(val*Math.pow(10, scale))/Math.pow(10, scale);
To answer the general question of reducing a double's significant digits, and not just the case of printing with System.out.printf:
If you're using Java: Double.parseDouble(String.format("%1.4e", 5.433306166802499E-5))
In Scala, you can use the f string interpolator, or the format method:
val a: Double = 5.433306166802499E-5
val reduced1: Double = f"$a%1.4e".toDouble
val reduced2: Double = "%1.4e".format(a).toDouble
Both are equal: 5.4333e-05

Difference of Two numbers - BigDecimal

I am just trying to learn more about BigDecimal, but below code makes me confuse.
Double x = 1.2;
String y = "1.2";
BigDecimal a = BigDecimal.ZERO;
BigDecimal b = BigDecimal.ZERO;
a = new BigDecimal(x);
b = new BigDecimal(y);
int res = res = b.compareTo(a);
if(res==1){
System.out.println("Die");
}else if(res ==0){
System.out.println("Live");
}else if (res==-1){
System.out.println("God Loves you");
}
Result = Die
I am not ready to "Die", why BigDecimal is hell bent on killing me.
This statement:
Double x = 1.2;
assigns the nearest double-representable value to 1.2 to x. That's just less than 1.2 - the value 1.2 itself can't be represented exactly in binary.
Now when you create a BigDecimal from that value, that "not quite 1.2" value is retained exactly. From the constructor's documentation:
Translates a double into a BigDecimal which is the exact decimal representation of the double's binary floating-point value.
... whereas when you use new BigDecimal("1.2") the result is exactly 1.2 - BigDecimal parses the string, and any decimal string representation can be represented exactly by BigDecimal, as that's the whole point of it.
1.2 is slightly bigger than "the nearest double representation of 1.2" hence res is 1.
a = new BigDecimal(x); // a= 1.1999999999999999555910790149937383830547332763671875
b = new BigDecimal(y); // b=1.2
This is due to conversion issue since translates a double into a BigDecimal which is the exact decimal representation.
int res = res = b.compareTo(a); //res= 1
Because 1.2 as double is not what you expect it to be.
Try this:
BigDecimal a = new BigDecimal(String.valueOf(x));
BigDecimal b = new BigDecimal(y);

Java : No matter which method I use, I cannot round a double to 4 decimals

I need to round some Doubles to 3 to 4 decimals. I tried 3 different methods, none of them work.
For most of the double I have, it works, but I keep having such doubles anyway :
0.12919999999999998
0.12365000000000001
36371.922099999996
I tried the following methods so far :
-- 1
(double) Math.round(someDouble * 10000) / 10000
-- 2
DecimalFormat twoDForm = new DecimalFormat("0.0000");
twoDForm.format(someDouble);
-- 3
BigDecimal bd = new BigDecimal(someDouble);
bd = bd.setScale(4, BigDecimal.ROUND_HALF_UP);
Does anyone have the magic solution I am looking for :) ?
Thank you !
NOTE :
Here is the full code :
// Processing
long start = System.nanoTime();
for (int i = 0; i < loopSize; i++) {
process();
}
// end timer
long absTime = System.nanoTime() - start;
double absTimeMilli = absTime * 1e-6;
DecimalFormat t = new DecimalFormat("###.####");
context.setTotalTime(Double.valueOf(t.format(absTimeMilli)));
context.setUnit(TimeUnit.SECONDS);
context.setMeanTime(Double.valueOf(t.format(absTimeMilli / Const.BENCH_LOOP_COUNT)));
context.setExecPerTimeUnit(Double.valueOf(t.format(loopSize / (absTimeMilli*1e-3))));
If you are storing the result back into a double type (your first example hints that you are), then this will happen. Double cannot store some numbers.
Once you have rounded, store the result in a BigDecimal or a String.
Updated - see comments below
May have misunderstood your comment, but something like this.
// this.totalTime += (1.0/someInteger)*myValue
BigDecimal ratio = BigDecimal.ONE.divide(new BigDecimal(someInteger));
totalTime = totalTime.add(ratio.multiply(myValue));
double val = 2.33333333;
DecimalFormat df2 = new DecimalFormat("###.####");
Try this.
A double cannot represent all possible decimal values due to the limitations in floating point representation (see http://en.wikipedia.org/wiki/Floating_point for more info or just google "floating ponint precision problem"). So if you need to process the rounded values simply store them in a BigDecimal, round it and keep working with that instead of going back to a double.
here is what i know so far ... to round a double you should use BigDecimal like this:
double yourDouble = 0.123456789;
int scale = 3;
double yourRoundedDouble = new BigDecimal(yourDouble).setScale(scale, RoundingMode.HALF_UP).doubleValue();
the result would be : 0.123.
note that "scale" is the number of digits you want to have after the point.
Hope this helps.
I am not sure what are you looking for, I do these sort of calculations like this
double p=36371.922099999996;
p=Math.round(p *10000.0000)/10000.0000;
System.out.println(p);
and I get 36371.9221
Try it

Categories

Resources