Why does Java BigDecimal return 1E+1? - java

Why does this code sometimes return 1E+1 whilst for other inputs (e.g. 17) the output is not printed in scientific notation?
BigDecimal bigDecimal = BigDecimal.valueOf(doubleValue).multiply(BigDecimal.valueOf(100d)).stripTrailingZeros();
System.out.println("value: " + bigDecimal);

use bigDecimal.toPlainString():
BigDecimal bigDecimal = BigDecimal.valueOf(100000.0)
.multiply(BigDecimal.valueOf(100d))
.stripTrailingZeros();
System.out.println("plain : " + bigDecimal.toPlainString());
System.out.println("scientific : " + bigDecimal.toEngineeringString());
outputs:
plain : 10000000
scientific : 10E+6

It's the implicit .toString() conversion that is happening when you pass the result into System.out.println().

The exact rationale for the behaviour of BigDecimal.toString() is explained in the API doc in great (and near incomprehensible) detail.
To get a consistent (and locale-sensitive) textual representation, you should use DecimalFormat.

It's basically because you don't have enough significant digits. If you multiply something that only has 1 significant digit with 100, then you get something with only 1 significant digit. If it shows "10" then that basically says that it has 2 significant digits. The way to show it only has 1 significant digit is to show "1 x 10^1".
The following two decimals have the same value (10), but different "scales" (where they start counting significant digits; the top has 2 sig figs, the bottom has 1):
System.out.println(new BigDecimal(BigInteger.TEN, 0)); // prints 10
System.out.println(new BigDecimal(BigInteger.ONE, -1)); // prints 1E+1

Related

Java Format string to C#

Don't understand Java's syntax. How to convert: "%6d %7.1f %5.1f" to C# equivalent ?
I keep getting this print out in C#: %6d %7.1f %5.1f
Tried:
"{0:d6} {7:1f} {5:1f}"
But, ran into an exception.
Exception:
Unhandled Exception: System.FormatException: Index (zero based) must be greater than or equal to zero and less than the size of the argument list.
at System.Text.StringBuilder.AppendFormatHelper(IFormatProvider provider, String format, ParamsArray args)
at System.String.FormatHelper(IFormatProvider provider, String format, ParamsArray args)
at System.String.Format(String format, Object arg0, Object arg1, Object arg2)
at experiment.Main(String[] args)
The Java code:
String.format("%6d %7.1f %5.1f", int, double, double/double);
It's obvious what values will be generated based on variable data types.
EDIT: I just looked at, Convert this line of Java code to C# code
C#
String.Format("{0:x2}", arrayOfByte[i]);
Java
String.format("%02x", arrayOfByte[i]);
PLEASE. PLEASE. PLEASE. DO not close this. Kindly. Please.
NOTE: Completely rewrote my original answer based on a (hopefully) better understanding of the Java format specifiers.
Based on my (Google-limited understanding), %6d, %7.1f and %5.1f correspond to the following:
An integer with up to 6 characters, padded if less than 6.
A float with up to 7 characters (including the decimal point and decimal portion) with a precision of 1.
A float with up to 5 characters (including the decimal point and decimal portion) with a precision of 1.
You can accomplish this with C#'s String.Format, like this:
var newString = String.Format("{0,6:d} {1,7:f1}, {2,5:f1}", 605, 20.5, 8.22);
This will result in the following string:
" 605 20.5 8.22"
The first digit in each placeholder group (defined by { and }) corresponds to the argument passed in after the string:
0 = 605
1 = 20.5
2 = 8.22
The second digit, after the , refers to the length of the string (including decimal points and decimal portions).
6 = 6 characters for the integer
7 = 7 characters for the float
5 = 5 characters for the float
The letters and numbers after the : are the format specifiers.
d = integer
f1 = floating with a precision of 1.
Which produces the string above, as follows:
{0,6:d} turns 605 into " 605" (3 leading spaces due to the 6 before the :)
{1,7:f1} turns 20.5 into " 20.5" (3 leading spaces due to the 7 before the :)
{2,5:f1} turns 8.22 into " 8.2" (1 leading space due to the 5 before the : and 1 decimal number due to the precision).
As I said earlier, check String.Format and Standard Numeric Format Strings for more information.
Starting from C# 6. you can use interpolation.
For your case you may wanted to try the following:
string formattedString = $"{0:d6} {7.1:f} {5.1:f}";
before C# 6 you can try the following:
string formattedString = String.Format("{0:d6} {1:f} {2:f}", 0, 7.1, 5.1);

DecimalFormat - Format decimal to preserve variable amount of trailing zeros

I have a situation where I need to preserve the number of decimal places for a number when formatting to a String using DecimalFormat, specifically for trailing zeros. I need to use DecimalFormat because I also need to avoid scientific notation for large numbers, and as seen here, this is the best way to do so. However, as you can see in that post, the code provided also removes trailing zeros, whereas I would like to preserve them.
1.00 -> "1.00"
1.000 -> "1.000"
I've seen a lot of questions that involve a fixed number of decimal places, but in my situation I need to account for a variable amount of decimal places. I looked into counting the number of decimal places, but since my input can also be a Double (in addition to BigDecimal), there appears to be no reliable way to count the digits after the decimal point for all numbers. Double.toString() does not work since Doubles break into exponential notation for very small and very big numbers. See here for more info regarding why it is difficult to count the number of decimal places in a double.
"Preserve" trailing zeros?
A double value doesn't know how many trailing zeroes you want to see. It is just a number, and 1.00 and 1.000 are the same number, i.e. the number 1. What you are asking cannot be done with a double value.
Now, BigDecimal does remember the number of trailing zeroes, so if you want to print a BigDecimal value, retaining the scale of the number, but ensuring it never prints in scientific notation, don't use a DecimalFormat, but instead use toPlainString():
Returns a string representation of this BigDecimal without an exponent field.
UPDATE
If you want to print a double value with as many decimal fraction digits as needed (i.e. no trailing zeroes), and want to make sure it never prints in scientific notation, use a DecimalFormat with very high MaximumIntegerDigits and very high setMaximumFractionDigits.
"Very high" means values exceeding the range of a double, so 999 is a good "round" number, though 330 would be high enough.
Test
DecimalFormat fmt = new DecimalFormat("0");
fmt.setMaximumIntegerDigits(330);
fmt.setMaximumFractionDigits(330);
System.out.println("0.0123400 = " + 0.0123400 + " = " + fmt.format(0.0123400));
System.out.println("123400.00 = " + 123400.00 + " = " + fmt.format(123400.00));
System.out.println("NaN = " + Double.NaN + " = " + fmt.format(Double.NaN));
System.out.println("-INFINITY = " + Double.NEGATIVE_INFINITY + " = " + fmt.format(Double.NEGATIVE_INFINITY));
System.out.println("+INFINITY = " + Double.POSITIVE_INFINITY + " = " + fmt.format(Double.POSITIVE_INFINITY));
System.out.println("MIN_NORMAL = " + Double.MIN_NORMAL + " = " + fmt.format(Double.MIN_NORMAL));
System.out.println("MIN_VALUE = " + Double.MIN_VALUE + " = " + fmt.format(Double.MIN_VALUE));
System.out.println("MAX_VALUE = " + Double.MAX_VALUE + " = " + fmt.format(Double.MAX_VALUE));
Output
0.0123400 = 0.01234 = 0.01234
123400.00 = 123400.0 = 123400
NaN = NaN = �
-INFINITY = -Infinity = -∞
+INFINITY = Infinity = ∞
MIN_NORMAL = 2.2250738585072014E-308 = 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014
MIN_VALUE = 4.9E-324 = 0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000049
MAX_VALUE = 1.7976931348623157E308 = 179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Either double (no precision, always approximating values), or BigDecimal.
Use BigDecimal as new BigDecimal("2.00") defining the correct scale (precision) of two digits. You can set the scale programmatically.
For database and calculation (like financial) BigDecimal is fine.
The scientific representation on output can be avoided in BigDecimal.toPlainString().
For double one could format with
s = String.format("%10.2f", 13.5789); // " 13.58"
All this is with a decimal point and no thousands separators.
Internationalized (localized) software will use a MessageFormat with a Locale (explicit or the default platform locale).
Locale.setDefault(new Locale("bg", "BG"));
s = MessageFormat.format("Number: {0, number, #.##}, "
+ "amount: {1, number, currency}",
42.125, 19.99);

Java Integer addition with String

With below code sample why the first addition (1/2+1/2) prints 0 but the second addition prints 00.
System.out.println(1/2+1/2+"=1/2+1/2");
System.out.println("1/2+1/2="+1/2+1/2);
Output:
0=1/2+1/2
1/2+1/2=00
Integer math (int 1 divided by int 2 is int 0, if you want a floating point result cast one, or both, of 1 and 2 to a floating point type) and order of operations, the second example is String concatenation. The compiler turns that into
System.out.println(new StringBuilder("1/2+1/2=").append(1/2).append(1/2));
and then you get
System.out.println(new StringBuilder("1/2+1/2=").append(0).append(0));
The first statement "System.out.println(1/2+1/2+"=1/2+1/2");" prints 0 because an the integer value obtained from 1/2 is zero. The remainder is dropped and since 1/2 equals 0.5 the .5 is dropped.
The second statement "System.out.println("1/2+1/2="+1/2+1/2);" prints out 00 because of the concatenation sign. In the second statement the first integer 1 is shown as +1 so the statement is actually being read as (+1/2 +1/2) which is why it returns 00.
If the second statement was set up like this:
System.out.println("1/2+1/2="+ (1/2+1/2));
The output would be the same as the first statement.
Expression is evaluated from left to right. In the first case it does int+int (which is 0), then int + "= String" which is a String tmp = "0= String". In the other case you have '"String =" + intwhich becomes"String =int"to which you append one moreint`. Thus you print String, "0" and "0".
java assumes that the result of the division is integer , since its members are integers. For the floating result ( 0.5 ) of each division , the divisor or the dividend should be of type float
System.out.println("1/2+1/2="+(1/2.0+1/2.0));

Double number formatting in java

I am working on a calculator program in Java and I need to display a number with no more than 15 digits in length (decimal point included).
I've tried to format this number using String.format("%g", myDouble), also with %f, but can't get the result I'm looking for.
The thing is that I need the number:
to be displayed as scientific notation if it has more than 15 digits,
or display it without rounding it if it has less than 15 digits.
Also, I do not want any fixed number of digits before or after the decimal point.
Any suggestions?
This is the code snipet where my number gets displayed:
if (("" + myDouble).length() > 15) {
screen.setText(String.format("%g", myDouble));
} else {
screen.setText("" + myDouble);
}
One problem is that when the else clause is executed, sometimes the numbers get displayed as 9.0000E7, which is not favorable and is different from the String.format("%g", myDouble) scientific notation which looks more like 9.000e+7.
This seems to be close to what you're asking for:
static String format(double n) {
if(Double.isInfinite(n) || Double.isNaN(n))
return Double.toString(n);
String result = BigDecimal.valueOf(n).toPlainString();
if(result.length() > 15)
result = String.format("%.15e", n);
return result;
}
Since your requirement is that the decimal places aren't fixed, I don't really see a way to do it with a formatter exclusively.
If you want a particular number of digits for the scientific notation, then you can use a format like "%.15e" where 15 is the number of decimal digits you want.
Or possibly you want something like:
if(result.length() > 15)
result = new DecimalFormat("0.###############E0").format(n);
But if you're trying to "block align" to some maximum, then things get complicated because the number of fractional digits depends on the number of digits in the exponent.
Just use the NumberFormat object. See the javadoc for details.
NumberFormat formatter = new DecimalFormat();
if (("" + myDouble).length() > 15) {
formatter = new DecimalFormat("0.######E0");
screen.setText(formatter.format(myDouble));
} else {
formatter = new DecimalFormat("#");
screen.setText(formatter.format(myDouble));
}

Int String format problem

I'm returning this, it is similar to how you percieve dollars, $"32.95" etc. I calculate it in cents which is an int, but the problem is the second half cuts off the 10s of cents part if the number is less than that. For example if I have "32.08" it returns as "32.8". Any ideas ? i know i need an if but i cant think how to write it.
public String toString()
{
return (cents / 100)+ "." + (cents % 100);
}
You can use http://java.sun.com/j2se/1.5.0/docs/api/java/text/DecimalFormat.html
DecimalFormat is a concrete subclass of NumberFormat that formats decimal numbers. It has a variety of features designed to make it possible to parse and format numbers in any locale, including support for Western, Arabic, and Indic digits. It also supports different kinds of numbers, including integers (123), fixed-point numbers (123.4), scientific notation (1.23E4), percentages (12%), and currency amounts ($123). All of these can be localized.
String pattern = "$###,###.###";
double value = 12345.67;
DecimalFormat myFormatter = new DecimalFormat(pattern);
String output = myFormatter.format(value);
System.out.println(value + " " + pattern + " " + output);
// => 12345.67 $###,###.### $12,345.67
The quick hack:
return String.format("%d.%02d", cents/100, cents%100);
Use the BigDecimal class, that's what it's for.
You could always check if cents % 100 is less than 10, and if it is, add another 0. There's probably a more elegant solution though.
So, 32.08 % 100 is 8 not 08. You could of course add in a "0" for values less than 10.
However, you might want to think about using java.text, in particular NumberFormat, DecimalFormat and MessageFormat. java.util.Formatter and "printf" might be more appropriate if you are attempting to write machine readable text.
NumberFormat nf=NumberFormat.getInstance(); // Get Instance of NumberFormat
nf.setMinimumIntegerDigits(5); // The minimum Digits required is 5
return (cents / 100)+ "." + nf.format(cents % 100);
That should do it, been a while since I did java.
(""+(100+cents%100)).substring(1) // LOL
(cents / 100)+ "." + (cents /10 %10) + (cents % 10); // <<== OK
Where's the abstraction? Java's an object oriented language. Wouldn't it be a better idea to encapsulate all that implementation detail in a Money class and hide it from clients?

Categories