Java: Simple format standard for various precision data - java

I'm trying to format output for user/report appeal, and there are two criteria I'm finding to be in a bit of conflict.
First, the decimal values should line up (format on "%12.10f", predicted integer value range 0-99)
Second, the decimal shouldn't trail an excessive series of zeroes.
For example, I have output that looks like
0.5252772000
0.2053628186
10.5234500000
But using a general formatting, I also end up with:
0.53260000000
0.52630000000
12.43540000000
In certain cases, and it looks kind of garbage.
Is there a simple way to solve this problem? The only solution I can come up with at the moment involves pre-interrogating the data before printing (instead of formatting it during print) which, while technically not expensive, just bugs me as being redundant data handling (ie I have to go through all data once to find the extrema of trailing zeroes to parse against it, and then set the format so that it can go through the data again to parse it)

You can set a DecimalFormat:
DecimalFormat format = new DecimalFormat("0.#");
for (float f : yourFloats){
System.out.println(format.format(f));
}
This also works on doubles.

Related

How to cast from String to BigDecimal with the separator as a comma? [duplicate]

This question already has answers here:
Java BigDecimal can have comma instead dot?
(3 answers)
Closed 3 months ago.
I have a method to set a BigDecimal number that is given as String:
private Client mapClient(Client client){
ClientRequest clientRequest = new ClientRequest();
// Code
clientRequest.setCashAmount(castStringToBigDecimal(client.getCashAmount()));
// More Code
}
My castStringToBigDecimal method is the follosing:
public BigDecimal castStringToBigDecimal(String value){
BigDecimal response = null;
if(value != null && !value.equals("")){
value = value.replaceAll("[.]", ",");
response = new BigDecimal(value);
}
return response;
}
An example of the input value is "1554.21"
I need that the bigDecimal separator to be a comma, not a dot. But this is giving me an exception.
EDIT
The value is the following:
And the exception is:
java.lang.NumberFormatException: Character , is neither a decimal digit number, decimal point, nor "e" notation exponential mark.
BigDecimal doesn't represent a rendering. In other words, whether to use a comma or a dot as separator is not part of the properties a BigDecimal object has.
Hence, you do not want to call .replaceAll. (And separately, you'd want .replace(".", ",") - replace replaces all, and replaceAll also replaces all and interprets the first arg as a regex, and is therefore needlessly confusing here). Just pass it with the dot.
To render a BigDecimal, don't just sysout it, that will always show a dot and there is nothing you can do about that. toString() is almost never the appropriate tool for the job of rendering data to a user - it's a debugging aid, nothing more. Use e.g. String.format("%f"), specifying the appropriate locale. Or use NumberFormat. The javadoc of BigDecimal explicitly spells this out.
There are various other issues with your code:
"cast" is the technical name for the syntactic construct: (Type) expr; - and this construct does 3 utterly different things, hence using it to describe a task, i.e. use it in a method name, is a very bad idea. In particular, only one of the 3 things it does converts anything, and you clearly use it here in the 'convert something' meaning. This is misleading; only if it's all primitives does the cast operator convert, and BigDecimal isn't primitive. Call it convertTo or whatever you please, not "cast".
BigDecimal is an extremely complicated tool for the job and usually not the right tool if you want to represent financial data. Instead, represent the atomary unit in a long and call the appropriate rendering method whenever you need to show it to a user. For example, for euros, the atomary unit is the eurocent. If something costs €1,50, you'd store "150", in a long. Before you think: But, wait, I want to divide, and then I'd lose half a cent! - yes, well, you can't exactly send your bank a request to transfer half a cent, either. Also, try to divide 4 cents by 3 with a BigDecimal and see what happens. Dividing financial amounts is tricky no matter what you use, BD isn't a catch-all solution to this problem.
I looked up the source code for Java 8's implementation of BigDecimal (https://github.com/frohoff/jdk8u-dev-jdk/blob/master/src/share/classes/java/math/BigDecimal.java), and the period character is hard-coded in that source as the decimal point. I would not have thought this of a language for which internationalization has been so thoroughly designed in, but there it is, line 466.
Given that the author(s) of BigDecimal failed to take locale into account in such a basic way -- the use of comma instead of period as the decimal separator in Europe is well-known -- I'd have to say you cannot use that BigDecimal constructor on unaltered Strings that are otherwise formatted correctly but which (might) have a comma separator. There are other options -- the previous SO post referred to in one of the comments has one -- but it appears you cannot convert your String this way.
(One minor point -- you are not "casting" anything. That word has a specific meaning in OO programming, and a more specific one in Java, and has very little to do with your question. It is incorrect to refer to conversion as casting.)

How do I format a JSR-385 Quantity with fixed number of decimal digits?

I'm trying to convert hard-coded formatting to a Java Units API implementation.
The existing code outputs (for this example, the temperature value in degrees) with two decimal places. For example, 38.70°C. While I'd like to allow the user to specify their own formatting code (which is the end-goal of the change), I think it would be useful to keep the legacy behavior to give people a chance to migrate.
The existing code looks like:
return String.format("%.2f\u00B0C", this.temperature);
The code I'm trying to use looks like:
DecimalFormat numberFormat = (DecimalFormat) DecimalFormat.getInstance();
numberFormat.setMinimumFractionDigits(2);
numberFormat.setMaximumFractionDigits(2);
NumberDelimiterQuantityFormat formatter =
NumberDelimiterQuantityFormat.builder()
.setNumberFormat(numberFormat)
.setDelimiter("")
.setUnitFormat(SimpleUnitFormat.getInstance())
.build();
return formatter.format(temperature);
It does format, but not with the specified precision. I'd expect 38.70°C but instead get 38.70000076293945℃.
If I just do
numberFormat.format(temperature.getValue().floatValue());
then it does format correctly ("38.70"). So I think the DecimalFormat is basically OK.
I considered just manually building my formatting. However that doesn't really work for what I want to do - pass in the NumberDelimiterQuantityFormat (or applicable interface).
Can anyone suggest an appropriate way to format a Quantity<> with fixed decimal precision?
First off, I'm completely unfamiliar with the Java Unit API and this implementation, but this seemed like an interesting question, so I looked into it.
I had a look at the implementation of NumberDelimiterQuantityFormat and right there in the implementation of the format method it modifies the maxiumFractionDigits of the NumberFormat depending on the fraction
if (quantity != null && quantity.getValue() != null) {
fract = getFractionDigitsCount(quantity.getValue().doubleValue());
}
if (fract > 1) {
numberFormat.setMaximumFractionDigits(fract + 1);
}
Source
This makes little sense to me for two reasons:
It negates the whole reason to have a NumberFormat in the first place especially in context with floating point numbers where it's virtually impossible to avoid superfluous fraction digits.
It modifies the internal state of the NumberDelimiterQuantityFormat in a method where it isn't expected.
I should have checked first, but there is actually an issue about this, which is "being analyzed" for several months now. Maybe it would make sense to ask in there.

DecimalFormat weird behavior with pattern #####0.00 in Java

I am using below code snap to display float price value with two decimal points.
NumberFormat FORMAT = new DecimalFormat("#####0.00");
float myFloatValue =\\I am able to fetch this value dynamically
String finalPrice = FORMAT.format(myFloatValue);
// I am using this String (finalPrice) for export xml purpose.
It seems working fine normally, but I have noticed some examples(given below) where it is not working properly and produce the price with more than two decimal points. I am not able to replicate it again, I can see it in only log files.
Some examples output of finalPrice String : 0.10999966, 0.1800003, 0.45999908.
Can anybody help me to guess original value of myFloatValue from these outputs? So that it will help me to replicate the scenario and fix it.
The sporadic occurrence makes me wonder whether the DECIMAL_FORMAT is used in several threads concurrently. That is a no-no. However one would expect
wrong values too.
Maybe for good order also specify a fixed Locale (decimal point vs. comma, thousand separators).
And finally float or even double are not suited for financial software: those numbers are approximations.
BigDecimal price = new BigDecimal("9.99");
price = price.multiply(BigDecimal.TWO); // 19.98 exact
BigDecimal is a PITA for writing calculations, but keeps its precision.

Java getBytes() method is stripping .00 from numbers in my String

I'm generating a csv file and I have a bunch of numbers without decimal points and I'm being required to put .00 for those cases, I'm using:
DecimalFormat f = new DecimalFormat("#.00");
So fa so good I can see a string looking this way:
String myStringWithDecimalPoints = "124.00, 24567868.00, 5.00"
but when I do:
out.write(myStringWithDecimalPoints.getBytes());
I get in my csv:
124, 24567868, 5
Why is this happening?
Any workarounds? (it does have to be CSV and .00 must appear)
You have to be careful with how you view your data, especially in spreadsheets like Excel where the format of the output depends on the type of the cell. It may or may not show decimal values.
A note for the future, with a call like
out.write(myStringWithDecimalPoints.getBytes());
you can safely assume that Java is writing all the bytes to the OutputStream. If you're not seeing the same thing in the receiving side, then the receiving isn't being done like you would expect.
Most likely there is some confusion between the value of your original string, and how your string appears when you output it in certain ways using your formatter. This does not necessarily mean that your "original" string has been altered.
We could say with greater certainty if you provided a more complete code example.

Parse BigDecimal from String containing a number in arbitrary format

We read data from XLS cells formatted as text.
The cell hopefully contains a number, output will be a BigDecimal (because of arbitrary precision).
Problem is, the cell format is also arbitrary, which means it may contain numbers like:
with currency symbols ($1000)
leading and trailing whitespaces, or whitespaces in between digits (eg. 1 000 )
digit grouping symbols (eg. 1,000.0)
of course, negative numbers
'o's and 'O's as zeros (eg. 1,ooo.oo)
others I can't think of
It's mostly because of this last point that I'm looking for a standard library that can do all this, and which is configurable, well tested etc.
I looked at Apache first, found nothing but I might be blind... perhaps it's a trivial answer for someone else...
UPDATE: the domain of the question is financial applications. Actually I'm expecting a library where the domain could be an input parameter - financial, scientific, etc. Maybe even more specific: financial with currency symbols? With stock symbols? With distances and other measurement units? I can't believe I'm the first person to think of something like this...
I don't know any library, but you can try that:
Put your number on a string. (ex: $1,00o,oOO.00)
Remove all occurrences of $,white-spaces or any other strang symbols you can think of...
Replace occurrences of o and O.
Try to parse the number =]
That should solve 99% of the entrys...
Buy bunch photos or even better videos with legal adult content. Create a web site with these resources but limit the access with captcha which will be displaying unsolved number formats. Create a set of number decoders out of known number formats and create an algorithm which will add new ones based on user solved captchas.
I think this is what I've been looking for:
http://site.icu-project.org/
Very powerful library, although at the moment it's not clear whether it can only format or all the formatted stuff can be parsed back as well.

Categories