DecimalFormat weird behavior with pattern #####0.00 in Java - 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.

Related

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.

Java: Simple format standard for various precision data

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.

Output Number, without digits after decimal place

ANDROID STUDIO HELP, THE VB.NET CODE ARE EXAMPLES - (SOLVED !!)
I'm coming from VB.NET (2+ Years).
Need help outputting Double variable, without digits after decimal place.
I understand that an integer is a number without any digits after the decimal place.
In Visual Basic or VB.NET, I can do this by doing this..
Dim Variable_Name_A as Decimal = 12.0123990110001
Variable_To_Hold_It = Decimal.Truncate(Variable_Name_A)
Outputs : 12
Val treats a String or TextBox as a Double.
So how can we do this in Java or for Android Studio?
Also, if you can answer but just one more question. How do you get rid of the negative symbol in Android Studio.. In VB.NET I can type the following code, to get rid of it.
Dim My_Variable_Name_A as Double = -12.00017
My_Variable_Name_B = Math.Abs(My_Variable_Name_A)
Outputs : 12.00017
So, I've taken a look at "Formater" for Android Studio. I've read countless posts that deals with digits after the decimal place. I don't understand any of it.
I DO NOT WANT ROUNDING.
In VB.NET, if I wanted to "Format" a number, we usually do something like this..
Dim Variable_Name_A as Double = 13.00192012334
Variable_Name_B = format(Variable_Name_A, "0.000")
Output : 13.002
I just need the whole number, before the decimal place for Android Studio, I don't want the numbers after the decimal place.
Also.. If you could.. WITHOUT ROUNDING.. Could you please tell me how to Format the number as well. Yes, with X number of digits after the decimal place.
Can you please help with my first question, and help me with the other questions if you can.
* So I figured it out.. *
EditText Millimeters_VARa = (EditText) findViewById(R.id.Millimeters_EditText_ID);
Double MM_Double = Double.parseDouble(Millimeters_VARa.getText().toString());
EditText Inches_VARa = (EditText) findViewById(R.id.Inches_EditText_ID);
DecimalFormat WholeNumber = new DecimalFormat("0");
DecimalFormat WholeAndThousandths = new DecimalFormat("0.000");
// Converts Millimeters to Inches.
Double MM_to_Inches_Convert = (MM_Double / 25.4);
Inches_VAR.setText(WholeNumber.format(MM_to_Inches_Convert));
Output Example : 2
Inches_VAR.setText(WholeAndThousandths.format(MM_to_Inches_Convert));
Output Example : 2.000
So, it seems it only works when finally outputting the value.
How would I store the formatted number or value in a Double Variable?
Ahh.. I figured it out. Like this?
* Storing a Formatted Number or Value as a Double *
Double TheWholeNumber = Double.parseDouble(WholeNumber.format(MM_to_Inches_Convert.toString()));
NOPE !! Doesn't work.. App Crashes.. Just keeping it simple, and formatting the number when finally outputting it with the setText.
But of course it rounds the last digit. So, now I'm gonna learn how to fix that.
PREVENTING FROM ROUNDING - SOLVED
public void FormatFunction(View v){
EditText EditText_VAR = (EditText) findViewById(R.id.EditText_A);
Double EditText_Double = Double.parseDouble(EditText_VAR.getText().toString());
TextView TextView_VAR = (TextView) findViewById(R.id.TextView_A);
DecimalFormat LOL = new DecimalFormat("0.0000");
LOL.setRoundingMode(RoundingMode.DOWN);
TextView_VAR.setText(LOL.format(EditText_Double));
Voilà
That's how ya do it. I also understand now what the difference between using a pound sign "#", vs. using just a zero. The pound sign prevents trailing zeros.
The Class Name, FormatFuncion is called by a button Click.
<TextView
android:textSize="22sp"
android:id="#+id/TextView_A"
android:text="#string/OUTPUT_STRING"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"/>
<EditText
android:layout_width="200dp"
android:layout_height="60dp"
android:layout_marginTop="90dp"
android:id="#+id/EditText_A"
android:inputType="numberDecimal"/>
<Button
android:layout_width="150dp"
android:layout_height="60dp"
android:layout_below="#+id/EditText_A"
android:layout_marginTop="20dp"
android:text="#string/Format_String_A"
android:onClick="FormatFunction"/>
</RelativeLayout>
As you can clearly see.
This post should help anyone looking for the Answer to formatting a number, as well as how to prevent rounding. SOLVED.
Android programming is a little difficult. It takes much longer then programming in VB.NET using Visual Studio 2010. Apps for Windows OS. I could, lol, Correction.. "I HAVE" made apps a couple times already in VB.NET, and it sure as hell beats the snot out of Programing for Android. As far as the amount of time it takes to make an App for my $700+ (Android) Samsung Galaxy Note 4. I just hate.. Sorta.. typing my layout. It's time consuming. Also, in order to get things to line up correctly, as in making a button under another button, or on the right, left, etc. If you have multiple other objects, gotta say stuff like An Example : android:layout_toRightOf="#+id/EditText_A"
Just a pain in the A**, IMHO. But I love Coding for Android. Regardless if it takes some learning, and head scratching. Just much slower then VB.NET, by far.
1)Convert Double to String.
2)perform String.Split
3)join the two split parts again to a string
4)Parse String to Long
5)Wallah double without decimal
double dbNum=11112.1111;
String []dbStore=Double.toString(dbNum).split(".");
String strDBNum="";
for(String str:dbStore)
{
strDBNum+=str;
}
Long lDbNum=Long.parseLong(strDBNum);
Try this
double number = 1205.6358;
System.out.println("number : " + number);
DecimalFormat df = new DecimalFormat("###");
System.out.println("number (DecimalFormat) : " + df.format(number));
Java has this nifty little feature called a cast. Cast the Double to an int by sticking (int) in front of it
Double Variable_Name_A = 12.0123990110001;
System.out.println((int)Variable_Name_A);
What is essentially happening is Variable_Name_A is being converted to an int, thus dropping everything after the decimal. You can also keep Variable_Name_A as a double with the following:
Double Variable_Name_A = 12.0123990110001;
Double Variable_Name_A = (int)12.0123990110001;
System.out.println(Variable_Name_A);
1) There are a few ways to do this. You can either use DecimalFormat (docs found here or you can use a Cast (docs found here).
Casting is telling your program you want it to view one data type as another. In your case, you want a double to be seen as an int, which will drop anything beyond the decimal point.
double My_Variable_Name_A = -12.9345;
int casted = (int) My_Variable_Name_A;
DecimalFormat is a tool to specify exactly what you want to see in your output, though it outputs a String. It can format a large variety of things, and it's best to check out the documentation on it. It can get pretty in depth with the characters you might want to use.
DecimalFormat dfMy_Variable_Name_A = new DecimalFormat("#");
String newVariable = dfMy_Variable_Name_A.format(My_Variable_Name_A)
DecimalFormat("#") this is the part that decides the format. If you wanted "X number of places after the decimal", you would use DecimalFormat("#.###") for 3 places. If you wanted to make sure you had a comma to separate large numbers, you could use DecimalFormat("#,###") etc.
2) As far as the second half of your question, you can import Math and use the abs() method in Java to remove negative signs. Math.abs(My_Variable_Name_A);

BigDecimal precision above 1E22

for some reason I found myself coding some piece of software, that should be able to perfom some astronomic calculations.
While most of it will be about transfering the correct formula into Java, I found an annoying Problem right at the verry beginning of my "test how to calculate big numbers".
Well... Imagine the Sun (our Sun), which has a mass of (about and rounded, for more easy explaining) 10E30 kg. Ten with 30 following Zeros. All native datatypes are just unusuable for this. To mention: I KNOW that I could use 3000 to calculate things and just add trailing zeros in the output-view, but I hoped to keep it as precise as possible. So using short numbers will be my last resort only.
Comming to the Problem. Please have a look at the code:
BigDecimal combinedMass = new BigDecimal(1E22);
int massDistribution = 10;
Integer mD1 = massDistribution;
Integer mD2 = 100 - massDistribution;
BigDecimal starMass;
BigDecimal systemMass;
systemMass = combinedMass.divide(new BigDecimal("100")).multiply(new BigDecimal(mD1.toString()));
starMass = combinedMass.divide(new BigDecimal("100")).multiply(new BigDecimal(mD2.toString()));
System.out.println((systemMass).toEngineeringString());
System.out.println((starMass));
It will output 1000000000000000000000 and 9000000000000000000000, whats exactly what I did expect. But look at the combineMass Field. If I raise it to 1E23, the Output will change
I get 9999999999999999161139.20 and 89999999999999992450252.80...
So I know I could use jut BigInteger, because its more reliable in this case, but for the sake of precicion, sometimes the BigWhatEver may drop to something like 50.1258
Plus, I hope to get the 10.xE30 as output, whats only possible using bigDecimals.
I want to know: Is there no way avoidng this (that error appers above 1E23 for every value I tried), while keeping the ability to calculate Floating-Points? Should I cut the After-Decimal-Separator-Values for this Field to two digets?
And for something more to wonder about:
System.out.println(combinedMass.precision());
in relation with the code above will provide 23 for that case, but En+1 for most other values (Thats was when I grow really confused)
Thanks for advise.
You're using basic types without realizing it:
new BigDecimal(1E22);
Here, 1E22 is a primitive double, and you already lost precision by using it.
What you want is
new BigDecimal("10000000000000000000000");
or
new BigDecimal(10).pow(22);

Converting from String to BigDecimal to do math on currency

I am working on a project that requires some simple math to be performed on currency, however it arrives in the form of a String. I am new to Java/Android so I am looking for help in converting from a String to a data type appropriate to this operation. At first I thought Float was right but after reading elsewhere and introducing myself to the numbers class, it appears BigDecimal is correct. Am I on the right track? At this point I simply want to subtract the sum of payments from an initial invoice amount. I get the feeling this code is simple but clumsy and I suspect I am missing a great deal about the nuances of working with currency. How would you do it? All advice warmly appreciated!
// capture variables from sending activity
String invoiceAmt = getIntent().getStringExtra("invoiceAmt");
String paymentsSum = getIntent().getStringExtra("paymentsSum");
// convert strings to BigD's
BigDecimal amt = new BigDecimal(invoiceAmt);
BigDecimal sum = new BigDecimal(paymentsSum);
// Do the math
BigDecimal invDue = amt.subtract(sum);
// insert the value (back to string) into textView
TextView tvInvoiceDue = (TextView)findViewById(R.id.InvoiceDue);
tvInvoiceDue.setText(invDue.toString());
BigDecimal is a fine approach. So is using an int or a long to store cents. I've heard some people like Joda-Money but I've never used it myself.
See this question.
In the code you posted, make sure the Strings you are receiving don't have currency symbols in them.

Categories