Retrieve number after point in BigDecimal number without RoundingMode - java

how to keep only 3 value after point in BigDecimal ?
i found a solution but it requirt a RoundingMode
BigDecimal d = BigDecimal.valueOf(0.5649);
System.out.println(d.remainder(BigDecimal.ONE));
System.out.println(d.remainder(BigDecimal.ONE).divide(BigDecimal.valueOf(1), 3, RoundingMode.CEILING));
i want to keep a number exact without rounding.

Just use setScale and RoundingMode.DOWN
Rounding mode to round towards zero. Never increments the digit prior
to a discarded fraction (i.e., truncates).
for example
BigDecimal.valueOf(0.5649).setScale(3, RoundingMode.DOWN)

BigDecimal isn't intended to be used with such limitations. Only ever wanting 3 decimals is a strange requirement. Maybe you only want to present 3 decimals to the users?
If so I suggest using: java.text.DecimalFormat
If you really want to make sure that you never do calculations with higher precission than 3 decimals I suggest making your own reprensentation/class. Internally you hold the value as a long (or appropriate class/primitive) but at a value 1000 times the actual value. All calculations are done with the internal reprensentation and when asked for a value, divide the internal value with 1000.0d and convert to double (or appropriate) and return.

I would use double for this.
double d = 0.5649;
d = (long) (d * 1000) / 1000.0; // round down.
System.out.println(d);
prints
0.564
or
d = (long) (d * 1000 + 0.5) / 1000.0; // round half up.

Related

Is there a way to remove the even-odd rule of rounding for 5 and round up?

Making a application for ordering tickets. For the total, I added the subtotal, hst, and service fees together, and decimal formatted the sum for the total. If the total is x.85, it rounds down to x.8 but I want x.9
Is there a way to remove the even-odd rule for rounding 5 and round up?
I have tried BigDecimal but it doesn't seem to work for me.
DecimalFormat df = new DecimalFormat("$#,###.00");
grandTotal = subTotal + hst + serviceFees;
System.out.printf("%-40s%11s\n", "TOTAL:", df.format(grandTotal));
I expect the output to round up when there is a 5 to round, but it just rounds based on the even-odd rule.
You need only 1 fraction digit.
You current code is rounding correctly, just too many fraction digits.
The rounding mode you are asking for is called HALF UP, which is a default for DecimalFormat and the only possible rounding mode for printf().
(You can also use format $#,###.# if you don't want to display zeros as fraction.)
Therefore you can use your decimal format just fine or even System.out.printf() but limit number of fraction digits to 1:
DecimalFormat df = new DecimalFormat("$#,###.0"); //set MIN and MAX fraction digits to 1
df.setRoundingMode(RoundingMode.HALF_UP); //default but showing usage if needed
System.out.println(df.format(123454.84d));
System.out.println(df.format(123454.85d));
System.out.printf("$%,.1f", 123454.85d); //HALF UP rounding the only option
prints:
$123,454.8
$123,454.9
$123,454.9
You are using floating point (double), which is just an approximation of real values.
Especially with a list and a total, you will always have trouble to get everything right.
You have no control, whether the total is 2.35 (actually never) or 2.349999998, the latter which would round down.
Use BigDecimal with String constructors: new BigDecimal("1.20"), having a fraction of 2 decimals.
Mind you must use add/multiply i.o. +/*.
Guys i just switched the double data type into a float type and it worked ayyyyy
!!!!!!!

Rounding double strangeness

it might be too late in the night, but I can't understand the behavior of this code:
public class DT {
static void theTest(double d){
double e = Math.floor(d/1630)*1630;
System.out.println(e-d);
}
public static void main(String[] args) {
theTest(2*1630);
theTest(2*1631);
theTest(2*1629);
theTest(8.989779443802325E18);
}
}
in my understangind, all 4 cases should be NON-positive, i.e. "e" is always <= "d",
but I do get following output:
0.0
-2.0
-1628.0
1024.0
Why??.
as this is same with FastMath, I suspect something double-specific? but could anyone explain me this?
When you get up into huge numbers, the doubles are spaced more widely than integers. When you do a division in this range, the result can be rounded up or down. So in your fourth test case, the result of the division d/1630 is actually rounded up to the nearest available double. Since this is a whole number, the call to floor does not change it. Multiplying it by 1630 then gives a result that is larger than d.
Edit
This effect kicks in at 2^52. Once you get past 2^52, there are no more non-integer doubles. Between 2^52 and 2^53, the doubles are just the integers. Above 2^53, the doubles are spaced more widely than the integers.
The result of the division in the question is 5515202112762162.576... which is between 2^52 and 2^53. It is rounded to the nearest double, which is the same as the nearest integer, which is 5515202112762163. Now, the floor does not change this number, and the multiplication by 1630 gives a result that is larger than d.
In summary, I guess the first sentence of the answer was a little misleading - you don't need the doubles to be spaced more widely than the integers for this effect to occur; you only need them to be spaced at least as widely as the integers.
With a value of d between 0 and 2^52 * 1630, the program in the question will never output a positive number.
NOTE: I think you are looking for the operation called fmod in other languages and % in Java. The e - d that you wish to compute could be computed allways of the correct sign and always lower than 1630 as -(d % 1630.0).
all 4 cases should be NON-positive
For an arbitrary double d, it is likely that Math.floor(d/1630)*1630 would be less than d, but not necessary.
In order:
d/1630 is the double nearest to the real d / 1630. It can be up to one half ULP above the real d / 1630, and it can be arbitrarily close to an integer.
When d is large enough, d/1630 is always an integer, because any large enough double is an integer. In other words, when d is large enough, Math.floor(d/1630) is identical to d/1630. This applies to your last example.
d / 1630 * 1630 is the double nearest to the real multiplication of d / 1630 by 1630. It is one half ULP from the real result.
The two rounding operations in d / 1630 * 1630 can both round up, and in this case, d / 1630 * 1630 is larger than d. It wouldn't be expected to be larger than d by more than one ULP(d).
If you want to compute a number that is guaranteed to be below the real d / 1630, you should either change the rounding mode to downward (not sure if Java lets you do this), or subtract one ULP from the result of d / 1630 computed in the default round-to-nearest rounding mode. You can do the latter with the function nextAfter.

Android/Java: Rounding up a number to get no decimal

How to round up a decimal number to a whole number.
3.50 => 4
4.5 => 5
3.4 => 3
How do you do this in Java? Thanks!
With the standard rounding function? Math.round()
There's also Math.floor() and Math.ceil(), depending on what you need.
You can use
int i = Math.round(f);
long l = Math.round(d);
where f and d are of type float and double, respectively.
And if you're working with only positive numbers, you can also use int i = (int)(d + 0.5).
EDIT: if you want to round negative numbers up (towards positive infinity, such that -5.4 becomes -5, for example), you can use this as well. If you want to round to the higher magnitude (rounding -5.4 to -6), you would be well advised to use some other function put forth by another answer.
Java provides a few functions in the Math class to do this. For your case, try Math.ceil(4.5) which will return 5.
new BigDecimal(3.4);
Integer result = BigDecimal.ROUND_HALF_UP;
Or
Int i = (int)(202.22d);
Using Math.max you can do it like this:
(int) Math.max(1, (long) Math.ceil((double) (34) / 25)
This would give you 2

java - remove float leftovers elegantly

In brief - I am having a hard time with the float left overs
(i.e. 10.00000123 instead of 10)
Here I go :
I need to generate list of floats with constant gap as follows
(actually its a map , I need to retreive the object nut nevermind that)
List A: 0.25, 0.5, 0.75, 1, ...
or
List B: 0.01, 0.02, 0.03, 0.04, ...
every time I get a number and I round it to the neerest cell in the list.
lets say I get 0.051 to retreive a cell in list A - I return 0.05.
lets say I get 0.21 to retreive a cell in list B - I return 0.25.
So I started be doing this
float a = Math.round(Value / step) * step;
but than I get a lot of time 0.2500001 (float leftovers )
I need a smart way to round it .
Maybe by taking the number of digits after the dot and doing again
Math.round(Value / 100) * 100;?
Is there a smarter way?
I tried doig this
final float factor = Math.round(1 / step);
final float value = (float) Math.round(value * factor) / factor;
but I sometimes have a list like this
List A: 10, 15 , 20, 25, 30, ...
and when I get 22 I retreive the cell of 20.
the problem is that When I get a gap of 10
Math.round(1 / baseAssetStep)
returns 0 - and I get NaN
Use BigDecimal instead of float.
From the Java Tutorials of Primitive Data Types:
float: [...] This data type should never be used for precise values, such as currency. For that, you will need to use the
java.math.BigDecimal class instead. Numbers and Strings covers
BigDecimal and other useful classes provided by the Java platform.
Firstly, I would use double or long instead as these have much more digits of accuracy. If you really need to, use BigDecimal, but its pretty rare to find a real world situation where double or long would not do the job.
double d = 10.00000123;
double r = Math.round(d * 10000) / 10000.0;
or using long with fixed point precision.
long l = 100000; // the actual value * 10000
A common use case for fixed point precision is money. Instead of using dollars with double use cents with long or even int instead.
In short, "these are not the numbers you're looking for."
Floating points are represented as binary fractional numbers, and some numbers that can be easily represented in base-10 (0.01, for instance) can't be represented with a finite number of binary digits. This is similar to how 1/3 is easy in base 3 (it's just 0.1), but requires an infinite number of digits in base 10 (0.333...).
If you tried to represent 1/3 with a finite number of digits in base 10, you'd get an approximation. Similarly, if you try to represent 1/10 with a finite number of digits in base 2 (which is what float and double do), you'll get an approximation, and similarly with 1/100. What you think is 0.01 in the code is actually a number that's very close, but not exactly equal to, 1/100.
There are many resources out there concerning floating points and the difficulty in working with them. http://floating-point-gui.de/ is a good place to start.
you need a constant gap, so maybe try another solution. Take your gap, let's name it G. Draw a randow int - let's call it R, (if you know maximum number in your list you can draw it properly). Now the only thing to do would be R*G which will give you a number from your list - of course with some precision because this is inevitable using float - to print it just use format. You can also combine this with BigDecimal ;)

How do you trim the BigDecimal division results

BigDecimal numerator = new BigDecimal(numerator);
BigDecimal denominator = new BigDecimal(denominator);
double result = numerator.divide(denominator).doubleValue();
Division on certain conditions results in a zero at the end (e.g. 0.0060).
Dividing equal numbers results in a zero at the end (e.g 1.0).
I would prefer to trim the trailing zero in both cases. How should I do this?
How about keeping the result as a BigDecimal and then you can set the scale on it to only represent the significant figures that you want.
An easy way to do this, for some numbers, is to use BigDecimal#stripTrailingZeros(). However, if the number is an integer with trailing zeros you'll get an engineering representation e.g. 600.0 will give you 6E+2. If this isn't what you want, you'll have to detect this condition and manually use BigDecimal#setScale() to set the scale appropriately.
If you need to keep to a restricted maximum number of decimal digits you'll need to use alternative formatting/rounding mechanisms before applying this technique.
It's also a good idea to only do this on values that you're going to display, not on the internal values of your model. Treat it as a view/presentation layer modification.
If you must convert to a double, then it's only the formatted representation you can alter. In this case, if you've got a variable number of decimal places that you want to format to, I'd just drop it into a string/character array, scan backwards for the first non-zero character and truncate it there. Not the most performant means, but simple and reliable.
You could even use a regex for this purpose.
you can do this by using DecimalFormat. something like:
DecimalFormat df = new DecimalFormat(".0");
double formatResult = df.format(result);
will create something of 1.0 if the result is 1.278494890. there are many possible patterns that could be used here
Ok, so you've got this code:
BigDecimal numerator = new BigDecimal(numerator);
BigDecimal denominator = new BigDecimal(denominator);
double result = numerator.divide(denominator).doubleValue();
and you want more control over your output. Since result is a double, which is a primitive, you won't have much control.
From my understanding, you don't want to do any rounding to n decimal places, you want original precision paired with desired formatting.
You have few options.
BigDecimal numerator = new BigDecimal(numerator);
BigDecimal denominator = new BigDecimal(denominator);
BigDecimal div = numerator.divide(denominator);
If you stay with BigDecimal, your output will be better. If you put 10 as the numerator and denominator in above code, System.out.println(div) will yield 1.
Generally, be careful of using above code because some combinations of numerator and denominator will throw
java.lang.ArithmeticException: "Non-terminating decimal expansion; no exact representable decimal result."
If you want to avoid such situations, and not worry about precision beyond double's internal representation, use double directly.
System.out.println(2312 / 2.543); //909.1624066063704
System.out.println(1.0 / 1.0); //1.0
System.out.println(1 / 1); //1
When using double numbers, you might get a 0 at the end, such as 0.0060 in your case. If you want to be sure what you're getting, you'll have to convert your result to a String using
String dec = String.valueOf(10.0/10.0); //1.0
and then using
String newDec = dec.endsWith("0") ? dec.substring(0, dec.length() - 1) : dec;
to eradicate that last 0. Of course, if your string ends with .0, you have a choice based on your preferences whether you want to leave that leading . or not.

Categories

Resources