Rounding time up or down with Joda - java

I want to round a time up or down with Joda using the roundCeilingCopy or roundFloorCopy methods.
Rounding down seems to work properly, but when I try to round up, it doesn't work properly.
Below is my current code with the output and the desired output. But maybe I just don't understand how those joda methods work?
I'm fairly new to java and joda and got my original code from here
Code:
public static long RoundTime(long time, int amount) {
DateTime dt = new DateTime(time);
System.out.println("Rounding time: " + dt.toString());
DateTime up = dt.withMinuteOfHour((dt.getMinuteOfHour() / amount) * amount)
.minuteOfDay().roundCeilingCopy();
System.out.println("Finished Rounding Time Up (" + amount + "): "
+ up.toString());
DateTime down = dt.withMinuteOfHour((dt.getMinuteOfHour() / amount) * amount)
.minuteOfDay().roundFloorCopy();
System.out.println("Finished Rounding Time Down (" + amount + "): "
+ down.toString());
}
Output: (with amount=5)
Rounding time: 2014-01-21T13:12:00.000-07:00
Finished Rounding Time Up (5): 2014-01-21T13:10:00.000-07:00
Finished Rounding Time Down (5): 2014-01-21T13:10:00.000-07:00
Desired Output: (with amount=5)
Rounding time: 2014-01-21T13:12:00.000-07:00
Finished Rounding Time Up (5): 2014-01-21T13:15:00.000-07:00
Finished Rounding Time Down (5): 2014-01-21T13:10:00.000-07:00

(dt.getMinuteOfHour() / amount) * amount already rounds the minutes towards zero because it uses integer division. You'll have to modify that to get the ceiled value: ((int) Math.ceil(1. * dt.getMinuteOfHour() / amount) * amount (note the 1. * to force the expression to use double precision - you could alternatively cast any value to double as well).

Related

Floating point calculation error in Java

Help, I got a problem when adding double value with negative number
A sample program to show the problem:
double newX = 850.0;
double delta = -1.6994427191177073E12;
double total = delta + newX;
System.out.println("newX:" + newX);
System.out.println("delta:" + delta);
System.out.println("total:" + total);
but the given output is:
newX:850.0
delta:-1.6994427191177073E12
total:-1.6994427182677073E12
I would expect the total value to be around "848.30055729". How to handle this calculation?
Regards,
Dennis
The computation is correct.
Lets start by converting your number from scientific notation
-1.6994427191177073E12
to decimal fixed-point notation:
-1699442719117.7073
This is because E12 means that the number to the left of E is multiplied by 1012.
Once you perform the addition of that number and 850.0, you get the result
-1699442718267.7073
Once you convert it to scientific notation by bringing the decimal point all the way to the left, you get the result printed by your program.

How to narrow down a rounding issue in a Java program?

public class Rest {
public static void main(String[] args) {
double mealCost;
int tipPercent;
int taxPercent;
double totalCost;
Scanner scan = new Scanner(System.in);
mealCost = scan.nextDouble();
tipPercent = scan.nextInt();
taxPercent = scan.nextInt();
double tipInD = mealCost * (double)tipPercent / 100;
double taxInD = mealCost * (double)taxPercent / 100;
totalCost = (double)mealCost + (double)tipInD + (double)taxInD;
System.out.println("The total meal cost is "+(int)totalCost+" dollars.");
}
}
This is the program i have created and I have to pass 4 different input cases, 3 of which am passing with this code, but the fourth 1 am not able to.
input cases with expected o/p.
Input for 1st - 3rd cases
---------
12.00 20 8
----------
15.50 15 10
----------
20.75 10 3
Output for 1st - 3rd cases
---------
The total meal cost is 15 dollars.
---------
The total meal cost is 19 dollars.
---------
The total meal cost is 23 dollars.
For the 4th case, the code I have written is not able to give the wanted O/P for it.
Input
--------
10.25
17
5
Output Should Be
The total meal cost is 13 dollars.
And am Getting The total meal cost is 12 dollars.
Narrowing Primitive Conversion :
double to byte, short, char, int, long, or float
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 (§4.2.3). Then there are two cases:
If T is long, and this integer value can be represented as a long, then the result of the first step is the long value V.
Otherwise, if this integer value can be represented as an int, then the result of the first step is the int value V.
(int)totalCost => (int) 12.504999999999999 => 12 (decimal part stripped)
Instead you may want to use Math.round( totalCost ) to get the closest integral value.
Math.round( totalCost ) => Math.round( 12.504999999999999 ) => 13
I think, from what you do expect, you just want to print:
System.out.println("The total meal cost is " + Math.round(totalCost) + " dollars.");
instead of.
System.out.println("The total meal cost is " +(int)totalCost + " dollars.");
The first one will properly round based on the mathematical rules, the second one will just stripe of the floating point values. That´s why the last one results in 12 and not 13, because it doesn´t actually round.
Change the way you write the totalCost to:
System.out.println("The total meal cost is "+ Math.round(totalCost) +" dollars.");
This will actually round off your output as per it should be calculated rather than just strip the decimal value directly.
A working solution is changing your output to
System.out.println("The total meal cost is " + (int) Math.ceil(totalCost) + " dollars.");
Explanation can be found here
You are casting an double value to an integer value. Note that by doing so you cut of the number at the decimal point and there is no rounding involved. Your calculation is 10.25*0.17 + 10.25*0.05 + 10.25 = 12.505
By applying the cast you get 12 and not 13. Don't cast your value, and you will be fine.

String to float/double Parsing

When I try to parse the following string into a float and into a double :
String abc = "8.40";
System.out.println("Double Value: " + Double.parseDouble(abc) * 100);
System.out.println("Float Value: " + Float.parseFloat(abc) * 100);
I get two different results.
Double Value: 840.0
Float Value: 839.99994
But when I try the same code with multiplying the float and double by 10 or 1000 I get the similar results for both of them.
String abc = "8.40";
System.out.println("Double Value: " + Double.parseDouble(abc) * 10);
System.out.println("Float Value: " + Float.parseFloat(abc) * 10);
I get two similar results.
Double Value: 84.0
Float Value: 84.0
And when I try this :
String abc = "8.40";
System.out.println("Double Value: " + Double.parseDouble(abc) * 1000);
System.out.println("Float Value: " + Float.parseFloat(abc) * 1000);
I get two similar results.
Double Value: 8400.0
Float Value: 8400.0
This will work fine:
System.out.println("Float Value: "+Math.round((float)Float.parseFloat(abc)*100));
So, this happens because of different representation of double and float, or more precise, about IEEE-754 rounding for float. Read about it here.
float has a smaller range and precision, so double would be better when you have memory (which you do today). But, they are both evil! There is a better option in Java called BigDecimal and you should use it, since it doesn't have problem with size and today we have strong computers so we will not have problems with memory and speed when dealing with a large number of decimal numbers needing max precision. For example, if you work on software that deals with a lot of money transactions, its a must to use BigDecimal.
It is true that double has more precision than float, but both of them suffer from the same problem: their value may not be exact, and they both have some (small) rounding error in their Least Significant Bit (LSB). This is clear in the first result you got: float value is not accurate. But when you multiply by 10 or 1000, the LSB is discarded from the result, and so you get the right answer for both float and double.

Correctly divide a double to be able to get back the correct amount

I have a input to a method that represents an amount of money, a total price of X items.
This can be an amount under a number of currencies and is represented by a double.
Question: I want to break this amount into the price for each of the X items. Considering that the amount itself is a double my concern is that if I simply do: amount/X I could get a number that number*X does not give me the amount exactly due to e.g. rounding. How can I do this correctly?
Note: Please give me help taking for granted that I can not change the amount to be something other than a double
As you already mentioned, this is not possible in every case. Usually, when the total price is really the product of the single item price and a quantity, the resulting double will have enough precision to do this calculation. But generally you have to store both prices.
I implemented a whole ERP, and we also have a feature where the user can specify the total line amount directly, maybe to round the sum after discussing with a customer. And this makes it possible to sell 7 items for 1000$. Then there is no way to create a precise representation of a price for a single item. And therefore we also store the item price rounded (cut after 4 digits).
To come back to your answer: Depending on context you will need the total and single item amount later anyway, so just store both.
You can use BigDecimal class:
double a=456.6556756;
BigDecimal amount=BigDecimal.valueOf(a);
BigDecimal priceOfEachItem=amount.divide(BigDecimal.valueOf(8));
BigDecimal amountAgain=priceOfEachItem.multiply(BigDecimal.valueOf(8));
System.out.println(amountAgain.doubleValue());
Output:456.6556756
As you can see you can get the exact original amount
You can do this by taking the single item price as double value which won't round off the value(Yes,you may limit the number of digits after decimal).
double totalPrice = 500.33;
int totalItems = 6;
double singleItemPrice = totalPrice/totalItems;
System.out.println("Single Item Price = " + singleItemPrice);
System.out.println("Total Price = " + (singleItemPrice * totalItems));
DecimalFormat df = new DecimalFormat("#.##");
Double formatted = Double.parseDouble(df.format(singleItemPrice * totalItems));
System.out.println("Formatted Value = "formatted);
Output:
Single Item Price = 83.38833333333334
Total Price = 500.33000000000004
Formatted Value = 500.33
Or use BigDecimal as mentioned by someone else(but maybe the above will have more precision, let us know about that):
import java.math.BigDecimal;
BigDecimal premium = BigDecimal.valueOf(1586.6d);
BigDecimal netToCompany = BigDecimal.valueOf(708.75d);
BigDecimal commission = premium.subtract(netToCompany);
System.out.println(commission + " = " + premium + " - " + netToCompany);
Output:
877.85 = 1586.6 - 708.75
Hope this was what you were looking for.
You can use Math.round for rounding. The problem you have is that you don't know what rounding for you amount/X you need. This is a problem whether you use double or BigDecimal
You can do this
public static double round2(double d) {
if (d < -Long.MAX_VALUE / 100 || d > Long.MAX_VALUE / 100)
return d;
return Math.round(d * 100) / 100.0;
}
public static void main(String[] args) throws IOException {
double amount = 1000.00;
int units = 9;
System.out.println("amount: " + amount );
System.out.println("units: " + units);
double perUnit = amount / units;
double amount2 = round2(perUnit * units);
System.out.println("perUnit: " + perUnit);
System.out.println("amount2: " + amount2);
}
prints
amount: 1000.0
units: 9
perUnit: 111.11111111111111
amount2: 1000.0

Double in place of Float and Float rounding

Edit:
This question covers two topics:
The efficiency of using in double in place of float
Float precision following rounding
Is there any reason why I should not always use Java double instead of float?
I ask this question because this test code when using floats is failing and not clear why since the only difference is the use of float instead of double.
public class BigDecimalTest {
#Test public void testDeltaUsingDouble() { //test passes
BigDecimal left = new BigDecimal("0.99").setScale(2,BigDecimal.ROUND_DOWN);
BigDecimal right = new BigDecimal("0.979").setScale(2,BigDecimal.ROUND_DOWN);
Assert.assertEquals(left.doubleValue(), right.doubleValue(), 0.09);
Assert.assertEquals(left.doubleValue(), right.doubleValue(), 0.03);
Assert.assertNotEquals(left.doubleValue(), right.doubleValue(), 0.02);
Assert.assertNotEquals(left.doubleValue(), right.doubleValue(), 0.01);
Assert.assertNotEquals(left.doubleValue(), right.doubleValue(), 0.0);
}
#Test public void testDeltaUsingFloat() { //test fails on 'failing assert'
BigDecimal left = new BigDecimal("0.99").setScale(2,BigDecimal.ROUND_DOWN);
BigDecimal right = new BigDecimal("0.979").setScale(2,BigDecimal.ROUND_DOWN);
Assert.assertEquals(left.floatValue(), right.floatValue(), 0.09);
Assert.assertEquals(left.floatValue(), right.floatValue(), 0.03);
/* failing assert */ Assert.assertNotEquals(left.floatValue() + " - " + right.floatValue() + " = " + (left.floatValue() - right.floatValue()),left.floatValue(), right.floatValue(), 0.02);
Assert.assertNotEquals(left.floatValue(), right.floatValue(), 0.01);
Assert.assertNotEquals(left.floatValue(), right.floatValue(), 0.0);
}}
Fail Message:
java.lang.AssertionError: 0.99 - 0.97 = 0.01999998. Actual: 0.9900000095367432
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failEquals(Assert.java:185)
at org.junit.Assert.assertNotEquals(Assert.java:230)
at com.icode.common.BigDecimalTest.testDeltaUsingFloat(BigDecimalTest.java:34)
Any idea why this test fails and why I shouldn't just always use double instead of float? of course a reason other than a double is wider than a float.
Edit:
The funny things is that Assert.assertNotEquals(double,double,delta) takes double in both cases so the returned floats in the failing test are getting widened as doubles anyway so why the test failure then?
Edit:
May be this other question is related, not sure though:
hex not the same
Edit:
From the answer to this question hex not the same it can be concluded that the scientific representation IEEE 754 for .99 for float is different from double for the same value. This is due the rounding.
Hence we get this:
0.99 - 0.97 = 0.01999998 //in float case
0.99 - 0.97 = 0.020000000000000018 //in double case
Since the max delta in the above unit test is 0.02 and 0.01999998 (in the failing test) is below the delta value meaning that the numbers are seen to be the same but the test is asserting they are not hence failing.
Guys do you agree with all this?
The documentation for BigDecimal is silent about how floatValue() rounds. I presume it uses round-to-nearest, ties-to-even.
left and right are set to .99 and .97, respectively. When these are converted to double in round-to-nearest mode, the results are 0.9899999999999999911182158029987476766109466552734375 (in hexadecimal floating-point, 0x1.fae147ae147aep-1) and 0.9699999999999999733546474089962430298328399658203125 (0x1.f0a3d70a3d70ap-1). When those are subtracted, the result is 0.020000000000000017763568394002504646778106689453125, which clearly exceeds .02.
When .99 and .97 are converted to float, the results are 0.9900000095367431640625 (0x1.fae148p-1) and 0.9700000286102294921875 (0x1.f0a3d8p-1). When those are subtracted, the result is 0.019999980926513671875, which is clearly less than .02.
Simply put, when a decimal numeral is converted to floating-point, the rounding may be up or down. It depends on where the number happens to lie relative to the nearest representable floating-point values. If it is not controlled or analyzed, it is practically random. Thus, sometimes you end up with a greater value than you might have expected, and sometimes you end up with a lesser value.
Using double instead of float would not guarantee that results similar to the above do not occur. It is merely happenstance that the double value in this case exceeded the exact mathematical value and the float value did not. With other numbers, it could be the other way around. For example, with double, .09-.07 is less than .02, but, with float, .09f - .07f` is greater than .02.
There is a lot of information about how to deal with floating-point arithmetic, such as Handbook of Floating-Point Arithmetic. It is too large a subject to cover in Stack Overflow questions. There are university courses on it.
Often on today’s typical processors, there is little extra expense for using double rather than float; simple scalar floating-point operations are performed at nearly the same speeds for double and float. Performance differences arise when you have so much data that the time to transfer them (from disk to memory or memory to processor) becomes important, or the space they occupy on disk becomes large, or your software uses SIMD features of processors. (SIMD allows processors to perform the same operation on multiple pieces of data, in parallel. Current processors typically provide about twice the bandwidth for float SIMD operations as for double SIMD operations or do not provide double SIMD operations at all.)
Double can represent numbers with a larger number of significant digits, with a greater range and vice versa for float. Double computations are more costly in terms of CPU. So it all depends on your application.
Binary numbers cannot exactly represent a number such as 1/5. These numbers end up being rounded, thereby introducing errors that are certainty at the origin of you failed asserts.
See http://en.m.wikipedia.org/wiki/Floating_point for more details.
[EDIT]
If all else fails run a benchmark:
package doublefloat;
/**
*
* #author tarik
*/
public class DoubleFloat {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
long t1 = System.nanoTime();
double d = 0.0;
for (long i=0; i<1000000000;i++) {
d = d * 1.01;
}
long diff1 = System.nanoTime()-t1;
System.out.println("Double ticks: " + diff1);
t1 = System.nanoTime();
float f = 0.0f;
for (long i=0; i<1000000000;i++) {
f = f * 1.01f;
}
long diff2 = System.nanoTime()-t1;
System.out.println("Float ticks: " + diff2);
System.out.println("Difference %: " + (diff1 - diff2) * 100.0 / diff1);
}
}
Output:
Double ticks: 3694029247
Float ticks: 3355071337
Difference %: 9.175831790592209
This test was ran on a PC with an Intel Core 2 Duo. Note that since we are only dealing with a single variable in a tight loop, there is no way to overwhelm the available memory bandwidth. In fact one of the core was consistently showing 100% CPU during each run.
Conclusion: The difference is 9% which might be considered negligible indeed.
Second test involves the same test but using a relatively large amount of memory 140MB and 280MB for float and double respectively:
package doublefloat;
/**
*
* #author tarik
*/
public class DoubleFloat {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
final int LOOPS = 70000000;
long t1 = System.nanoTime();
double d[] = new double[LOOPS];
d[0] = 1.0;
for (int i=1; i<LOOPS;i++) {
d[i] = d[i-1] * 1.01;
}
long diff1 = System.nanoTime()-t1;
System.out.println("Double ticks: " + diff1);
t1 = System.nanoTime();
float f[] = new float[LOOPS];
f[0] = 1.0f;
for (int i=1; i<LOOPS;i++) {
f[i] = f[i-1] * 1.01f;
}
long diff2 = System.nanoTime()-t1;
System.out.println("Float ticks: " + diff2);
System.out.println("Difference %: " + (diff1 - diff2) * 100.0 / diff1);
}
}
Output:
Double ticks: 667919011
Float ticks: 349700405
Difference %: 47.64329218950769
Memory bandwidth is overwhelmed, yet I can still see the CPU peaking at 100% for a short period of time.
Conclusion:
This benchmark somewhat confirms that using double takes 9% more time that float on CPU intensive applications and about 50% more time in data intensive applications. It also confirms Eric Postpischil note, that CPU overhead is relatively negligible (9%) in comparison with the performance impact of limited memory bandwidth.

Categories