NumberFormat doesn't like more than 340 decimal places - java

I want to format a double with a certain number of decimal places in Java. My code currently looks like this:
final NumberFormat format = NumberFormat.getInstance();
format.setMinimumFractionDigits(decimalPlaces);
format.setMaximumFractionDigits(decimalPlaces);
format.setGroupingUsed(false);
String s = format.format(value);
but when decimalPlaces is more than 340, this method just prints 340 digits and ignores the rest. Is there a way to work around this limitation?
Specifically in my case they're all 0s (and probably would be with any number after a certain point since the precision is not that high) but it seems wrong to me that the function just silently ignores what I want instead of throwing an exception or something.
Yes, I'm aware that a double can't actually hold that many decimal places, but it's also true that an int can't hold any decimal places at all yet I'm able to print it with some.

The documentation of setMinimumFractionDigits contains this statement:
The concrete subclass may enforce an upper limit to this value appropriate to the numeric type being formatted.
Most likely the subclass returned by NumberFormat.getInstance is DecimalFormat, which tells us in the JavaDocs
For formatting numbers other than BigInteger and BigDecimal objects, the lower of newValue and 340 is used. Negative input values are replaced with 0.
So to solve your problem, convert your number to a BigDecimal before formatting it.

In case of double the value is getting truncating. Use/declare value as BigDecimal
Try this sample code:
final NumberFormat format = NumberFormat.getInstance();
format.setMinimumFractionDigits(355);
format.setMaximumFractionDigits(400);
format.setGroupingUsed(false);
System.out.println(format.getMinimumFractionDigits());
BigDecimal bd=new BigDecimal(10L);
String s = format.format(bd);
System.out.println(s.length());
System.out.println(s);

Related

BigDecimal Java. How to append zeros in front

My question is basically the following:
When I use a value with BigDecimal, how do I append zeros in front of a random number?
Say I want to have a number <10 following an entirely random pattern. Now i want to add zeros in front of the number, so the actual amount adds up to 10 numbers.
Here's an example:
BigDecimal num = new BigDecimal(2353);
Now I want to have that ouput:
0000002353
Is there a function that appends numbers to a BigDecimal type?
I couldn't find any.
I tried using a while loop that checks whether the number is less than ten. But I don't understand the Big Decimal well enough to actually compare integral values to the BigDecimal types.
Thanks for any help in advance!
If you use a BigInteger instead (or any integer type, such as int or long) you can format the value with
String.format("%010d", BigInteger.valueOf(2353))
The leading 0 in the format strings means pad with 0, the following 10 is the desired length...
BigDecimal is meant to be used for storing large floating point numbers. Since in a floating-point number there isn't any difference between 0000002353 and 2353, there is no reasonable way to append leading 0's to a BigDecimal just as there is no reasonable way to append leading 0's to a normal float. According to the behavior you're looking for, I would suggest using a String to store your number, and then convert to and from BigDecimal when you want to perform any operations.
To compare an integral type to a BigDecimal, first convert the variable to a BigDecimal and then call BigDecimal's compareTo method. More info is in this question.
Since you're interested in formatting the number, you might want to look at DecimalFormat class, which allows to format floating point and integer numbers according to the specified pattern.
BigDecimal num = new BigDecimal(2353);
DecimalFormat f1 = new DecimalFormat("0000000000");
DecimalFormat f2 = new DecimalFormat("0,000,000,000");
System.out.println(f1.format(num));
System.out.println(f2.format(num));
Output:
0000002353
0,000,002,353
If the maximum number of digits is 10 and only whole numbers are allowed you don't need anything more than to use long with standard formatting:
long myNumber = 123456;
System.out.printf("%010d%n", myNumber);

How to convert money representation of different currency to a decimal value in java

Suppose I have money value represented as 10.000,00 in congo currency and I want it to be converted to a decimal amount like 10000.00. The money representation can be any from deferent countries and the outcome should be a decimal amount.
How do I achieve this in java?
It is better to keep money in integer format in minimal possible coin value - f.e. in US dollars - if you have 1$ and 25 cents - just save it as int 125 cents - it helps to avoid very common problems with java float/doubles precision errors.
You can use replace for example :
money.replace(",", "#").replace(".", "").replace("#", ".")
This will gives you:
10000.00
If you want to get the decimal value then you can use :
String money = "10.000,00";
NumberFormat format = NumberFormat.getInstance(Locale.FRANCE);
Number number = format.parse(money.replace(".", ""));
System.out.println(number);
double d = number.doubleValue();
System.out.println(d);
This will gives you:
10000.0
The method NumberFormat.getCurrencyInstance(Locale)
is made exactly for this purpose.
It takes care for all country-specific formatting (decimal point or comma, currency name, currency before or after number, thousands grouping, ...).
You use it like this, for example for Congo (Democratic Republic):
Locale locale = new Locale("", "CD");
NumberFormat currencyFormat= NumberFormat.getCurrencyInstance(locale);
String s = currencyFormat.format(10000.0);
Result is "CDF 10,000.00"
Note: For the following, I assume it will not necessarily be known beforehand which currency/locale to expect.
I did that just recently like this: Split the string by all possible markers (.,' should be enough). Then join the parts except for the last one. Before you add that, you add whatever decimal-sign you need. So, "10.000,00" => [[10],[000],[00]] => 10000.00. This can then be converted to BigDecimal.
(Don't use float or double for monetary values.)
The reason for doing it that way: You can handle most formats like
1.234,56
1,234.56
1'234.56
1234.567
And you automatically can handle numbers of fraction digits != 2.
You'd only have to be careful with whitespaces and currencies with no fractions (split array will be of size = 1). Also be careful with currencies with 3 fraction digits. It can be cumbersome to tell amounts apart using this approach that are not using a decimal at all and those that do ("1.234" =>"1234.000" and "1.234,567" => "1234.567"). You might need a little additional validation & correction for those cases.
I don't know if that's interesting for you, but Java 8 has a Currency class, that can give you number of fraction digits.
I also suggest writing a unit test, so you can be sure all expected input formats will end up in your desired format. And of course I suggest extensive documentation of what formats are accepted / allowed.

Java Math.pow() Rounding Error

I'm having trouble with (what I suspect is) a rounding error.
I have a string, 0.686357E-01, which I'm trying to convert to a double. I've been able to split it up using the Pattern.split() function, and I'm capturing the base and the exponent values just fine. However, once I try to multiply them appropriately, I get this as a result: 0.06863570000000001.
Here's my relevant code:
pattern = Pattern.compile("E\\+?");
String[] number = pattern.split(string);
double base = Double.parseDouble(number[0]);
int exponent = Integer.parseInt(number[1]);
number= base*Math.pow(10, exponent);
So, how do I avoid the rounding error? (There are ways that I can work around it, but if it's possible to do, then I'd like to know how to fix the issue)
Thanks.
You don't need to split it, Double.parseDouble can handle those kinds of numbers just fine.
double number = Double.parseDouble("0.686357E-01");
See? It works!
0.0686357 is not exactly representable as a double-precision value.
Two solutions:
Use e.g. BigDecimal.
Limit the displayed precision to a certain number of significant figures when converting back to human-readable.
Floating point numbers do not have perfect precision. If that is an issue, use BigDecimal:
String string = "0.686357E-01";
BigDecimal number = new BigDecimal(string);
System.out.println(number);
Double will print always like that, but the value will remain correct. You'll need to format the output to get the correct value. See DecimalFormat class.

setting decimal places to a float value

float a= (float) 1846.4;
NumberFormat df = DecimalFormat.getInstance();
df.setMinimumFractionDigits(2);
df.setMaximumFractionDigits(2);
float b = Float.parseFloat( df.format(a));
What would be the best way to set decimal places for a float (I just want to set 2 decimal places of a float value which can be 2013.43452 or 2392.2) ? Now I am getting exception like Exception in thread "main" java.lang.NumberFormatException: For input string: "1,846.40".
I think the direct problem causing the NFE is the thousand separators in the string, not the number of decimal places. You have both a ',' and a '.' in the string, and parseFloat doesn't like that.
Note, however, that you can't fix the number of decimal places in a float value - it is entirely a formatting issue. Specifically, trailing 0's have no significance in floating point values, thus will not be shown by default. You need to format the value according to your wishes at the point of output (when converting it into a displayable String e.g. by using DecimalFormat as you did above).
To get your formatting + parsing to work, just use df again:
float b = df.parse( df.format(a));
However, I still don't see any sense in that. You can't define the number of decimal places in a floating point number. 1846.40 is the same as 1846.4 or 1846.400, the trailing zeros are totally irrelevant.
Those digits come into play when you have output, e.g. writing the number to a string. But there are other facilities to do that, e.g. a string format pattern.
If you need to restrict the number of fraction digits internally use BigDecimal where you can set the scale and thus define the number of fraction digits it represents.
Sounds like you simply want to round to two decimal places.
Number format and mucking around with strings isn't where you want to go.
Try this:
float b = Math.round(a * 100)/100.0f;
What would be the best way to set decimal places for a float
There isn't one. Floats don't have decimal places. They have binary places.
If you want decimal places you have to use a decimal radix, either a BigDecimal or the result of DecimalFormat.format().

What is decimal format exactly doing?

This is my code:
float result=(float) ( (new Float(result1)*0.3)+(new Float(result2)*0.7));
String a=dec.format(result);
vprosvasis.setText(a);
If I use vprosvasis somewhere else in my app, it will have the price a.
For example, if my result is 12,34, a will be 12,3 so vprosvasis will be 12,3 if I write
float genikosvathmos = ((new Float(vprosvasis.getText().toString()) +
new Float(vprosvasis2.getText().toString()) +
new Float(vprosvasis3.getText().toString()) +
new Float(vprosvasis4.getText().toString()) +
new Float(vprosvasis5.getText().toString()) +
new Float(vprosvasis6.getText().toString())) / 6);
Would suggest using primitives (specifically, double) rather than Object wrappers (unless you have some need that you're not showing here).
Then look at the Double javadoc, especially the static utility methods:
http://download.oracle.com/javase/6/docs/api/java/lang/Double.html
double myDouble = Double.parseDouble(myString);
String s = Double.toString(myDouble);
The purpose of DecimalFormat is to format numbers as text in a locale-specific way. (It can also be used to parse a locale-specific number format to a suitable Number type.) For example, in the American English locale, a period ('.') is used as a decimal point, rather than a comma (',').
It is important to note that the String produced by a DecimalFormat is very likely to be incompatible with the format required for the Float(String) constructor. The string format consumed by Float is not locale-specific; it is a fixed format that is the same as that specified by the Java Language Specification for float literals in Java source code.
If you are doing calculations with money, don't use a floating-point type like float or double. Use instances of java.math.BigDecimal instead. This type performs exact arithmetic, and when rounding is performed, you can control the rounding to conform with your accounting practices.
Like Daniel, I'm not quite sure what you're trying to get from this post. But I will answer the question you asked in your title at face value.
You don't include the code where dec is declared, or any code where it's operated on, but from context it seems to be an instance of the DecimalFormat class. If so, it's taking result, which is a float, and doing the following things:
widening it to long
using the method format(double number) inherited from NumberFormat to get the String representation of result
storing the result in a

Categories

Resources