I am trying to convert an inputstream to objects and am having trouble with converting the below string to BigDecimal. I get 87.00 as the 0's are ignored. I am experimenting with DecimalFormat. Any help is appreciated. Thanks!
E.g. 0087 has to be converted to 00.87
You seem to indicate in comments that the initial string, "0087", is a fixed-point representation with two decimal places, there therefore being an implicit decimal point before the last two digits. There are several ways that you could convert that to a corresponding BigDecimal, but myself, I would go with this:
BigDecimal result = BigDecimal.valueOf(Long.parseLong("0087"), 2);
The key here is to understand that BigDecimals have two characteristic properties: an arbitrary-length sequence of decimal digits, and a scale conveying the place value of the least-significant digit, in the form of the number of digits to the right of the decimal point. The particular factory method demonstrated above accepts those as separate arguments, though it only works if the digit string is short enough to be represented as a long. The 2 corresponds directly to the number of (implicitly) fractional digits in your input.
Outputting the resulting BigDecimal as "00.87" instead of "0.87" is a separate issue, but doable, if it's really something you want.
Try this code
String str="0087";
int pos=str.lastIndexOf("0");
String resultat=str.substring(0,pos+1);
resultat+=".";
resultat+=str.substring(pos+1);
System.out.println(resultat);
new BigDecimal(resultat);
Related
I am trying to convert a float to a String and insert commas into the resulting String. I don't want to add/remove any zeroes, change the precision of the float, or do any kind of rounding. I want the String result to have the exact same digits as the original float, just with commas added. A locale agnostic solution would be preferred.
What I need:
public String convertFloat(float number) {
// return converted String with commas and no rounding or extra digits
}
Some input/output examples:
Given float: 1500
Result: "1,500"
Given float: 0.00210014
Result: "0.00210014"
Given float: 168874.00210014
Result: "168,874.00210014"
Given float: 168874.01
Result: "168,874.01"
Things I have tried:
String.valueOf(168874.00210014f) // Does not work for me because the result does not contain commas
String.format("%,f", 10.2f) // Does not work for me because it inserts a bunch of zeroes on the end
// The below does not work for me because the precision gets thrown off and the result ends up being: 14.1999998093 When it should be just: 14.2
NumberFormat f = NumberFormat.getInstance();
f.setMaximumFractionDigits(10);
System.out.println(f.format(14.2f));
// Result: 14.1999998093
// The below does not work for me because a bunch of random extra digits get thrown onto the end
DecimalFormat f = new DecimalFormat("#,###.##########");
System.out.println(f.format(100514.2f));
// Result: 100,514.203125
// The below does not work for me because it rounds to 2 decimal places
DecimalFormat f = new DecimalFormat("#,###.00");
System.out.println(f.format(100514.21351f));
// Result: 100,514.203125
// Does not work for me because it rounds to 2 decimal places.
String s = String.format("%,.2f", 10.2629f)
What I am trying to do seems so simple. How can I get the exact same digits just with commas added in the resulting string?
It's important to realize that a float has about 7 digits of decimal precision -- about, because decimal numbers can't be represented precisely.
Your example value of 100514.213512345f won't ever come back out the same way you put it in because the original value would necessarily have been truncated at a value somewhere in the neighborhood of 100514.2
I know you don't want any rounding, but it's the nature of floating point math on computers. Even if you use double precision, you just make the rounding smaller -- the issue of rounding doesn't go away.
By default its 6 digits.
There are few pointers that I found:-
Float is distorting the value after decimal while double is not. Hence, would recommend using double.
It's impossible to show as many as digits after decimal as there are in original number. Hence below is a workaround:
String string = String.format("%,.6654f", Math.abs(n)).replaceAll("0*$", "")
n is a double number not a float.
I have used 6654 as random max decimal digits that you could have in your number increase it if you need to.
This is kind of hack but you can replace preceding zeros
String.format("%,f", 10.2f).replaceAll("0*$","")
As for precision with big numbers you should use BigDecimal
Additionally you can remove last dot if its round number
String.format("%,f", new BigDecimal(100010f)).replaceAll("0*$","").replaceAll("\\.$","")
OP here,
None of these answers really worked for me. Turns out that in my case converting to double was not possible. So I decided to sacrifice the commas and just go with String.valueOf() approach
Acknowledging what others have already posted regarding the limited about of digits allowed in a float, here's a version that should work when you are within the limit and won't cut out consecutive 0s if they properly belong to the float. We're basically just splitting the input into 2 substrings and adding the comma formatting to the first half.
String input = String.valueOf(number);
int decimalIndex = input.indexOf(".");
String firstHalf = input.substring(0, decimalIndex);
String secondHalf = input.substring(decimalIndex, input.length());
String commas = String.format("%,d", Integer.parseInt(firstHalf));
return commas + secondHalf;
If you want to retain more precision then please use doubles instead of floats.
I have below logic that rounds a double value to 2 decimal places:
public double round(double value, int places) {
BigDecimal bd = new BigDecimal(value);
bd = bd.setScale(places, RoundingMode.HALF_UP);
return bd.doubleValue();
}
It is working for most of the cases but fails to round the result to 2 decimal places in some cases, below is an example for it.
If I call this method using code round(12.503, 2), I need the result as 12.50 because I need result in 2 decimal places, but I am getting output as 12.5
Please help me how to fix this case.
A double in Java represents a mathematical number where 12.50 is the same number as 12.5. How many digits of a number are shown is a concern of converting it to a string, not of the number itself.
So better do the rounding when you convert the number to a string for output, e.g.:
System.out.printf("%5.2f", value);
You are not getting the result as 12.5.
You are receiving back a double.
Then, you have chosen some arbitrary method of displaying that double, (which you have told us nothing about,) and based on the results of applying that method you think that its value is 12.5.
You see, the thing with doubles is that they cannot be thought of as having a fixed number of decimal digits. (Or, more accurately, the number of decimal digits that they have is so huge, that nobody ever wants to see them all.) So, in all likelihood the actual value of the double that you receive, without any bias introduced by various methods of displaying it, is something akin to 12.5000000... But you need to choose the right method of displaying it in order to see what it is. If the method that you chose simply strips trailing zeros, then you may be left with the impression that you are missing a trailing zero. Or 10 trailing zeros.
So, you need to convert it back to BigDecimal before you can make any assumptions as to what result you are getting.
I have A String that is formatted correctly to be cast to a double and it works fine for most decimals. The issue is that for .33, .67, and possibly others I haven't tested, the decimal becomes something like .6700000000002, or .329999999998. I understand why this happens but does any one have a suggestion to fix it.
It's a result of IEEE-754 rounding rules, some numbers cannot be represented precisely in two's complement. For example, 1/10 is not precisely representable.
You can add more precision (but not infinite) by using BigDecimal.
BigDecimal oneTenth = new BigDecimal("1").divide(new BigDecimal("10"));
System.out.println(oneTenth);
Which outputs 0.1
Some decimal numbers can not be represented accurately with the internal base 2 machine representation.
That's double precision for you. Binary numbers and decimals don't work well together. Unless you are doing something really precise it should be fine, if you are printing it you should use either decimal format or printf.
Value of floating point numbers are not stored directly but with exponential values. You may write 3.1233453456356 as number, but this is stored something like 3 and 2^6 in memory. It tries to store a value as close as your number, but those differences can happen.
It shouldn't be a problem unless you're testing for equality. With floating-point tests for equality you'll need to allow a "delta" so that:
if (a == b)
becomes
if (abs(a-b) < 0.000001)
or a similar small delta value. For printing, limit it to two decimal places and the formatter will round it for you.
How do i print this in scientific notation:
BigDecimal r= (a.subtract(exact, MathContext.DECIMAL128)).divide(exact, MathContext.DECIMAL128).stripTrailingZeros();
DecimalFormat format = new DecimalFormat("0.###E0");
System.out.println(new BigDecimal(format.format(r));
where:
a = 1.111111111111111160454356650006957352161407470703125
exact = 0.11
returns:
r = 0.900010000000000004
any ideas? I've also tried calling EngineeringString() on the BigDecimal but this also didn't seem to work for me
You overdid the thing. What you only need is:
System.out.println(format.format(r));
The DecimalFormat object does indeed create a string, creating a BigDecimal instance again would just parse the number from string again - and the toString() method is called on the BigDecimal instance, produing the output you described...
Some clarification
BigDecimal, and other numeric formats (and dates too!) are stored in binary formats in the memory, abstracted from how us, humans think of them. BigDecimal for example stores the decimal digits, and where the decimal point is. Floating point numbers are even more sophisticated. Date stores the seconds from The Epoch. You need to format them to be readable. Formatting means to create a String (or semantically similar) object, that represents the value of the given object in the desired format. This doesn't involve changing the original object in any way.
The default formatting, toString() provides one generic format. To get your output the way you'd like does not mean to change the value to be formatted right with toString(), but to transform the unchanged value into the right String. Nice example is Double.toString() (using sun.mic.FloatingDecimal): it does exponential notation when the number is large or small enough, but in between, it prints in plain decimal format...
Hey all, I am a total newbie developing an android application, I've been reading 'Sams Teach Yourself Java in 24 hours' and it's a great book. But I have been stuck on a bit where I get the value of a decimal number only editTexts and use java maths to work out my end value.
Is there a way to have an editText input straight to a float or double variable rather than to a string and then from a string to a double?
Are there any real issues with converting between a string and a double or float or will the values remain the same and not be polluted.
Differences / pros and cons of using a doble as opposed to a float.
Best way to input a fraction value from the user?
Thanks for any help. Have a good day.
No, you can't.
Yes. If your string is, say, an ID and reads like "0029482", after you turn it into an integer it will read "29482" and probably will be invalid. Strings can be longer than doubles or floats, and if you have a value like "0.12345678901234567890123456789" in a string, you will lose a lot of precision by converting that to a double.
Doubles use double the number of bits (hence the name), and can therefore hold more precision.
Accept the denominator and numerator integers, and store them in a custom class.
No. You could write your own subclass that makes it seem like that is what's happening, but at some point somewhere in the chain you have to do a conversion from character/text data to numerical data.
Yes. Primitive floating-point types use IEEE-754 to encode decimal numbers in binary. The encoding provides very good precision, but it is not exact/cannot exactly represent many possible numbers. So if you parse from a string to a primitive floating-point type, and then back to string again, you may get something that is different from your input string.
A double uses twice as many bits to encode the number as a float, and thus is able to maintain a greater degree of precision. It will not, however, remove the issues discussed in #2. If you want to remove those issues, consider using something like BigDecimal to represent your numbers instead of primitive types like float or double.
Read the whole thing as a string, split() it on the '/' character, and then store each part as an integer (or BigInteger). If you need to display it as a decimal, use BigDecimal to perform the division.
I'd just like to add that if you are looking for an alternative to double or float that doesn't entail loss of precision when converting between strings and numeric form, look at these:
The standard java.math.BigDecimal class represents an arbitrary precision scaled number; i.e. an arbitrary precision integer multiplied (scaled) by a fixed integer power of 10.
The Apache dfp package contains implementations of decimal-based floating numbers.
However, I'd steer clear of both of this topic for now, and implement using float or double. (I take it that your real aim is to learn how to write Java, not to build the world's greatest calculator app.)