Bigdecimal restriction whole and decimal part - java

How do you restrict the whole part to 15 and decimal part to 8 like 15.8 using BigDecimal
For Example:
String quant= "1000";
String price = "123456789012345.12345678";
final int contant = 100;
BigDecimal bd1;
BigDecimal bd2;
String value = "";
bd1 = new BigDecimal(price).multiply(new BigDecimal(quant));
bd2 = bd1.divide(new BigDecimal(contant));
value = bd2.toPlainString();
Output value coming as 1234567890123451.2345678. So can I restrict the whole part up to 15 and decimal part up to 8.

If you restrict the 'whole' part to 15, then you will lose precision, why would you do that?
You can restrict (round) the decimal part by using BigDecimal.setScale. setScale can take an integer (how many decimal parts should be used) and a rounding strategy, e.g. BigDecimal.ROUND_UP.
Check the JavaDoc from BigDecimal for further information.

You can validate as follows
String price = "123456789012345.12345678";
String[] str=price.split("\\.");
if(!((str[0].length()==15)&&(str[1].length()==8))){
System.out.println("not a valid format");
}

Not sure why you would do that, but here is a way-
int contant = 100;
String price = "123456789012345.12345678224423";
String quant = "1000";
BigDecimal bd1 = new BigDecimal(price).multiply(new BigDecimal(quant));
BigDecimal bd2 = bd1.divide(new BigDecimal(contant));
final int WHOLE_MAX = 15;
final int SCALE = 8;
String value = bd2.setScale(SCALE, RoundingMode.HALF_UP).toPlainString();
String tempWhole = value.substring(0, value.indexOf('.')); // Digits before the decimal point
String wholePart = tempWhole.substring(0, Math.min(tempWhole.length(), WHOLE_MAX)); // Gets the first 15 digits
String decimalPart = value.substring(value.indexOf('.'));
value = wholePart.concat(decimalPart);
System.out.println(value);
Output:
123456789012345.23456782

The BigDecimal is described with precision. You can set it using MathContext.
MathContext context = new MathContext(15 + 8, RoundingMode.HALF_UP);
When you apply to your need
BigDecimal value = new BigDecimal("1234567890123456789.12345678",context);
The out put will be
1234567890123456789.1235
This is the expected way that what is erased from the number is the smallest thing. If you wan to set upper limit for the number you will need to declare your own type and check that result is grater then limit, then you have an overflow error.
You can implement your type that controls it by extending BigDecimal class
private class BigNumber extends BigDecimal {
private final int exponent;
private final int mantissa;
private BigDecimal limit;
public BigNumber(String val, int exponent, int mantissa) {
super(val);
this.exponent = exponent;
this.mantissa = mantissa;
char[] limit = new char[exponent];
Arrays.fill(limit, '9');
this.limit = new BigDecimal(limit).add(BigDecimal.ONE);
}
#Override
public BigDecimal add(BigDecimal augend) {
BigDecimal result = super.add(augend);
if(result.compareTo(limit) < 0) {
return result;
}
throw new RuntimeException("Nuber to large");
}
}

Related

How to express "1.275" to "1.28" with Decimal Format in Java

DecimalFormat decimalFormat = new DecimalFormat();
decimalFormat.setRoundingMode(RoundingMode.HALF_UP);
decimalFormat.applyPattern(".00");
System.out.print(decimalFormat.format(63.275));
// output : 63.27
System.out.print(decimalFormat.format(64.275));
// output : 64.28
Why are they different?
The value of 63.275 is recorded in computer as 63.27499999999999857891452847979962825775146484375 . As per the Java API doc "https://docs.oracle.com/javase/8/docs/api/java/math/RoundingMode.html#HALF_UP " Behaves as for RoundingMode.UP if the discarded fraction is ≥ 0.5; otherwise, behaves as for RoundingMode.DOWN.
so ,
63.27499999999999857891452847979962825775146484375 ~ 63.27
64.275000000000005684341886080801486968994140625 ~ 64.28
public static double roundByPlace(double number, int scale){
BigDecimal bigDecimal = BigDecimal.valueOf(number);
String pattern = "0.";
for(int i = 0; i<scale; i++){
pattern = pattern+"0";
}
DecimalFormat decimalFormat = new DecimalFormat(pattern);
decimalFormat.setRoundingMode(RoundingMode.HALF_UP);
double result = Double.parseDouble(decimalFormat.format(bigDecimal));
return result;
}

How to get rid of .0 on end of whole float number [duplicate]

A 64-bit double can represent integer +/- 253 exactly.
Given this fact, I choose to use a double type as a single type for all my types, since my largest integer is an unsigned 32-bit number.
But now I have to print these pseudo integers, but the problem is they are also mixed in with actual doubles.
So how do I print these doubles nicely in Java?
I have tried String.format("%f", value), which is close, except I get a lot of trailing zeros for small values.
Here's an example output of of %f
232.00000000
0.18000000000
1237875192.0
4.5800000000
0.00000000
1.23450000
What I want is:
232
0.18
1237875192
4.58
0
1.2345
Sure I can write a function to trim those zeros, but that's lot of performance loss due to string manipulation. Can I do better with other format code?
The answers by Tom E. and Jeremy S. are unacceptable as they both arbitrarily rounds to two decimal places. Please understand the problem before answering.
Please note that String.format(format, args...) is locale-dependent (see answers below).
If the idea is to print integers stored as doubles as if they are integers, and otherwise print the doubles with the minimum necessary precision:
public static String fmt(double d)
{
if(d == (long) d)
return String.format("%d",(long)d);
else
return String.format("%s",d);
}
Produces:
232
0.18
1237875192
4.58
0
1.2345
And does not rely on string manipulation.
String.format("%.2f", value);
In short:
If you want to get rid of trailing zeros and locale problems, then you should use:
double myValue = 0.00000021d;
DecimalFormat df = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
df.setMaximumFractionDigits(340); //340 = DecimalFormat.DOUBLE_FRACTION_DIGITS
System.out.println(df.format(myValue)); //output: 0.00000021
Explanation:
Why other answers did not suit me:
Double.toString() or System.out.println or FloatingDecimal.toJavaFormatString uses scientific notations if double is less than 10^-3 or greater than or equal to 10^7
double myValue = 0.00000021d;
String.format("%s", myvalue); //output: 2.1E-7
by using %f, the default decimal precision is 6, otherwise you can hardcode it, but it results in extra zeros added if you have fewer decimals. Example:
double myValue = 0.00000021d;
String.format("%.12f", myvalue); // Output: 0.000000210000
by using setMaximumFractionDigits(0); or %.0f you remove any decimal precision, which is fine for integers/longs but not for double
double myValue = 0.00000021d;
System.out.println(String.format("%.0f", myvalue)); // Output: 0
DecimalFormat df = new DecimalFormat("0");
System.out.println(df.format(myValue)); // Output: 0
by using DecimalFormat, you are local dependent. In the French locale, the decimal separator is a comma, not a point:
double myValue = 0.00000021d;
DecimalFormat df = new DecimalFormat("0");
df.setMaximumFractionDigits(340);
System.out.println(df.format(myvalue)); // Output: 0,00000021
Using the ENGLISH locale makes sure you get a point for decimal separator, wherever your program will run.
Why using 340 then for setMaximumFractionDigits?
Two reasons:
setMaximumFractionDigits accepts an integer, but its implementation has a maximum digits allowed of DecimalFormat.DOUBLE_FRACTION_DIGITS which equals 340
Double.MIN_VALUE = 4.9E-324 so with 340 digits you are sure not to round your double and lose precision
Use:
if (d % 1.0 != 0)
return String.format("%s", d);
else
return String.format("%.0f", d);
This should work with the extreme values supported by Double. It yields:
0.12
12
12.144252
0
On my machine, the following function is roughly 7 times faster than the function provided by JasonD's answer, since it avoids String.format:
public static String prettyPrint(double d) {
int i = (int) d;
return d == i ? String.valueOf(i) : String.valueOf(d);
}
My two cents:
if(n % 1 == 0) {
return String.format(Locale.US, "%.0f", n));
} else {
return String.format(Locale.US, "%.1f", n));
}
if (d == Math.floor(d)) {
return String.format("%.0f", d); //Format is: 0 places after decimal point
} else {
return Double.toString(d);
}
More info: https://docs.oracle.com/javase/tutorial/java/data/numberformat.html
float price = 4.30;
DecimalFormat format = new DecimalFormat("0.##"); // Choose the number of decimal places to work with in case they are different than zero and zero value will be removed
format.setRoundingMode(RoundingMode.DOWN); // Choose your Rounding Mode
System.out.println(format.format(price));
This is the result of some tests:
4.30 => 4.3
4.39 => 4.39 // Choose format.setRoundingMode(RoundingMode.UP) to get 4.4
4.000000 => 4
4 => 4
Naw, never mind. The performance loss due to string manipulation is zero.
And here's the code to trim the end after %f:
private static String trimTrailingZeros(String number) {
if(!number.contains(".")) {
return number;
}
return number.replaceAll("\\.?0*$", "");
}
Use a DecimalFormat and setMinimumFractionDigits(0).
This one will gets the job done nicely:
public static String removeZero(double number) {
DecimalFormat format = new DecimalFormat("#.###########");
return format.format(number);
}
new DecimalFormat("00.#").format(20.236)
//out =20.2
new DecimalFormat("00.#").format(2.236)
//out =02.2
0 for minimum number of digits
Renders # digits
Please note that String.format(format, args...) is locale-dependent because it formats using the user's default locale, that is, probably with commas and even spaces inside like 123 456,789 or 123,456.789, which may be not exactly what you expect.
You may prefer to use String.format((Locale)null, format, args...).
For example,
double f = 123456.789d;
System.out.println(String.format(Locale.FRANCE,"%f",f));
System.out.println(String.format(Locale.GERMANY,"%f",f));
System.out.println(String.format(Locale.US,"%f",f));
prints
123456,789000
123456,789000
123456.789000
and this is what will String.format(format, args...) do in different countries.
EDIT Ok, since there has been a discussion about formalities:
res += stripFpZeroes(String.format((Locale) null, (nDigits!=0 ? "%."+nDigits+"f" : "%f"), value));
...
protected static String stripFpZeroes(String fpnumber) {
int n = fpnumber.indexOf('.');
if (n == -1) {
return fpnumber;
}
if (n < 2) {
n = 2;
}
String s = fpnumber;
while (s.length() > n && s.endsWith("0")) {
s = s.substring(0, s.length()-1);
}
return s;
}
I made a DoubleFormatter to efficiently convert a great numbers of double values to a nice/presentable string:
double horribleNumber = 3598945.141658554548844;
DoubleFormatter df = new DoubleFormatter(4, 6); // 4 = MaxInteger, 6 = MaxDecimal
String beautyDisplay = df.format(horribleNumber);
If the integer part of V has more than MaxInteger => display V in scientific format (1.2345E+30). Otherwise, display in normal format (124.45678).
the MaxDecimal decide numbers of decimal digits (trim with bankers' rounding)
Here the code:
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Locale;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
/**
* Convert a double to a beautiful String (US-local):
*
* double horribleNumber = 3598945.141658554548844;
* DoubleFormatter df = new DoubleFormatter(4,6);
* String beautyDisplay = df.format(horribleNumber);
* String beautyLabel = df.formatHtml(horribleNumber);
*
* Manipulate 3 instances of NumberFormat to efficiently format a great number of double values.
* (avoid to create an object NumberFormat each call of format()).
*
* 3 instances of NumberFormat will be reused to format a value v:
*
* if v < EXP_DOWN, uses nfBelow
* if EXP_DOWN <= v <= EXP_UP, uses nfNormal
* if EXP_UP < v, uses nfAbove
*
* nfBelow, nfNormal and nfAbove will be generated base on the precision_ parameter.
*
* #author: DUONG Phu-Hiep
*/
public class DoubleFormatter
{
private static final double EXP_DOWN = 1.e-3;
private double EXP_UP; // always = 10^maxInteger
private int maxInteger_;
private int maxFraction_;
private NumberFormat nfBelow_;
private NumberFormat nfNormal_;
private NumberFormat nfAbove_;
private enum NumberFormatKind {Below, Normal, Above}
public DoubleFormatter(int maxInteger, int maxFraction){
setPrecision(maxInteger, maxFraction);
}
public void setPrecision(int maxInteger, int maxFraction){
Preconditions.checkArgument(maxFraction>=0);
Preconditions.checkArgument(maxInteger>0 && maxInteger<17);
if (maxFraction == maxFraction_ && maxInteger_ == maxInteger) {
return;
}
maxFraction_ = maxFraction;
maxInteger_ = maxInteger;
EXP_UP = Math.pow(10, maxInteger);
nfBelow_ = createNumberFormat(NumberFormatKind.Below);
nfNormal_ = createNumberFormat(NumberFormatKind.Normal);
nfAbove_ = createNumberFormat(NumberFormatKind.Above);
}
private NumberFormat createNumberFormat(NumberFormatKind kind) {
// If you do not use the Guava library, replace it with createSharp(precision);
final String sharpByPrecision = Strings.repeat("#", maxFraction_);
NumberFormat f = NumberFormat.getInstance(Locale.US);
// Apply bankers' rounding: this is the rounding mode that
// statistically minimizes cumulative error when applied
// repeatedly over a sequence of calculations
f.setRoundingMode(RoundingMode.HALF_EVEN);
if (f instanceof DecimalFormat) {
DecimalFormat df = (DecimalFormat) f;
DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();
// Set group separator to space instead of comma
//dfs.setGroupingSeparator(' ');
// Set Exponent symbol to minus 'e' instead of 'E'
if (kind == NumberFormatKind.Above) {
dfs.setExponentSeparator("e+"); //force to display the positive sign in the exponent part
} else {
dfs.setExponentSeparator("e");
}
df.setDecimalFormatSymbols(dfs);
// Use exponent format if v is outside of [EXP_DOWN,EXP_UP]
if (kind == NumberFormatKind.Normal) {
if (maxFraction_ == 0) {
df.applyPattern("#,##0");
} else {
df.applyPattern("#,##0."+sharpByPrecision);
}
} else {
if (maxFraction_ == 0) {
df.applyPattern("0E0");
} else {
df.applyPattern("0."+sharpByPrecision+"E0");
}
}
}
return f;
}
public String format(double v) {
if (Double.isNaN(v)) {
return "-";
}
if (v==0) {
return "0";
}
final double absv = Math.abs(v);
if (absv<EXP_DOWN) {
return nfBelow_.format(v);
}
if (absv>EXP_UP) {
return nfAbove_.format(v);
}
return nfNormal_.format(v);
}
/**
* Format and higlight the important part (integer part & exponent part)
*/
public String formatHtml(double v) {
if (Double.isNaN(v)) {
return "-";
}
return htmlize(format(v));
}
/**
* This is the base alogrithm: create a instance of NumberFormat for the value, then format it. It should
* not be used to format a great numbers of value
*
* We will never use this methode, it is here only to understanding the Algo principal:
*
* format v to string. precision_ is numbers of digits after decimal.
* if EXP_DOWN <= abs(v) <= EXP_UP, display the normal format: 124.45678
* otherwise display scientist format with: 1.2345e+30
*
* pre-condition: precision >= 1
*/
#Deprecated
public String formatInefficient(double v) {
// If you do not use Guava library, replace with createSharp(precision);
final String sharpByPrecision = Strings.repeat("#", maxFraction_);
final double absv = Math.abs(v);
NumberFormat f = NumberFormat.getInstance(Locale.US);
// Apply bankers' rounding: this is the rounding mode that
// statistically minimizes cumulative error when applied
// repeatedly over a sequence of calculations
f.setRoundingMode(RoundingMode.HALF_EVEN);
if (f instanceof DecimalFormat) {
DecimalFormat df = (DecimalFormat) f;
DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();
// Set group separator to space instead of comma
dfs.setGroupingSeparator(' ');
// Set Exponent symbol to minus 'e' instead of 'E'
if (absv>EXP_UP) {
dfs.setExponentSeparator("e+"); //force to display the positive sign in the exponent part
} else {
dfs.setExponentSeparator("e");
}
df.setDecimalFormatSymbols(dfs);
//use exponent format if v is out side of [EXP_DOWN,EXP_UP]
if (absv<EXP_DOWN || absv>EXP_UP) {
df.applyPattern("0."+sharpByPrecision+"E0");
} else {
df.applyPattern("#,##0."+sharpByPrecision);
}
}
return f.format(v);
}
/**
* Convert "3.1416e+12" to "<b>3</b>.1416e<b>+12</b>"
* It is a html format of a number which highlight the integer and exponent part
*/
private static String htmlize(String s) {
StringBuilder resu = new StringBuilder("<b>");
int p1 = s.indexOf('.');
if (p1>0) {
resu.append(s.substring(0, p1));
resu.append("</b>");
} else {
p1 = 0;
}
int p2 = s.lastIndexOf('e');
if (p2>0) {
resu.append(s.substring(p1, p2));
resu.append("<b>");
resu.append(s.substring(p2, s.length()));
resu.append("</b>");
} else {
resu.append(s.substring(p1, s.length()));
if (p1==0){
resu.append("</b>");
}
}
return resu.toString();
}
}
Note: I used two functions from the Guava library. If you don't use Guava, code it yourself:
/**
* Equivalent to Strings.repeat("#", n) of the Guava library:
*/
private static String createSharp(int n) {
StringBuilder sb = new StringBuilder();
for (int i=0; i<n; i++) {
sb.append('#');
}
return sb.toString();
}
String s = String.valueof("your int variable");
while (g.endsWith("0") && g.contains(".")) {
g = g.substring(0, g.length() - 1);
if (g.endsWith("."))
{
g = g.substring(0, g.length() - 1);
}
}
You said you choose to store your numbers with the double type. I think this could be the root of the problem, because it forces you to store integers into doubles (and therefore losing the initial information about the value's nature). What about storing your numbers in instances of the Number class (superclass of both Double and Integer) and rely on polymorphism to determine the correct format of each number?
I know it may not be acceptable to refactor a whole part of your code due to that, but it could produce the desired output without extra code/casting/parsing.
Example:
import java.util.ArrayList;
import java.util.List;
public class UseMixedNumbers {
public static void main(String[] args) {
List<Number> listNumbers = new ArrayList<Number>();
listNumbers.add(232);
listNumbers.add(0.18);
listNumbers.add(1237875192);
listNumbers.add(4.58);
listNumbers.add(0);
listNumbers.add(1.2345);
for (Number number : listNumbers) {
System.out.println(number);
}
}
}
Will produce the following output:
232
0.18
1237875192
4.58
0
1.2345
For Kotlin you can use an extension like:
fun Double.toPrettyString() =
if(this - this.toLong() == 0.0)
String.format("%d", this.toLong())
else
String.format("%s", this)
This is what I came up with:
private static String format(final double dbl) {
return dbl % 1 != 0 ? String.valueOf(dbl) : String.valueOf((int) dbl);
}
It is a simple one-liner and only casts to int if it really needs to.
Format price with grouping, rounding, and no unnecessary zeroes (in double).
Rules:
No zeroes at the end (2.0000 = 2; 1.0100000 = 1.01)
Two digits maximum after a point (2.010 = 2.01; 0.20 = 0.2)
Rounding after the 2nd digit after a point (1.994 = 1.99; 1.995 = 2; 1.006 = 1.01; 0.0006 -> 0)
Returns 0 (null/-0 = 0)
Adds $ (= $56/-$56)
Grouping (101101.02 = $101,101.02)
More examples:
-99.985 = -$99.99
10 = $10
10.00 = $10
20.01000089 = $20.01
It is written in Kotlin as a fun extension of Double (because it is used in Android), but it can be converted to Java easily, because Java classes were used.
/**
* 23.0 -> $23
*
* 23.1 -> $23.1
*
* 23.01 -> $23.01
*
* 23.99 -> $23.99
*
* 23.999 -> $24
*
* -0.0 -> $0
*
* -5.00 -> -$5
*
* -5.019 -> -$5.02
*/
fun Double?.formatUserAsSum(): String {
return when {
this == null || this == 0.0 -> "$0"
this % 1 == 0.0 -> DecimalFormat("$#,##0;-$#,##0").format(this)
else -> DecimalFormat("$#,##0.##;-$#,##0.##").format(this)
}
}
How to use:
var yourDouble: Double? = -20.00
println(yourDouble.formatUserAsSum()) // will print -$20
yourDouble = null
println(yourDouble.formatUserAsSum()) // will print $0
About DecimalFormat: https://docs.oracle.com/javase/6/docs/api/java/text/DecimalFormat.html
A simple solution with locale in mind:
double d = 123.45;
NumberFormat numberFormat = NumberFormat.getInstance(Locale.GERMANY);
System.out.println(numberFormat.format(d));
Since comma is used as decimal separator in Germany, the above will print:
123,45
Here's another answer that has an option to append decimal ONLY IF decimal was not zero.
/**
* Example: (isDecimalRequired = true)
* d = 12345
* returns 12,345.00
*
* d = 12345.12345
* returns 12,345.12
*
* ==================================================
* Example: (isDecimalRequired = false)
* d = 12345
* returns 12,345 (notice that there's no decimal since it's zero)
*
* d = 12345.12345
* returns 12,345.12
*
* #param d float to format
* #param zeroCount number decimal places
* #param isDecimalRequired true if it will put decimal even zero,
* false will remove the last decimal(s) if zero.
*/
fun formatDecimal(d: Float? = 0f, zeroCount: Int, isDecimalRequired: Boolean = true): String {
val zeros = StringBuilder()
for (i in 0 until zeroCount) {
zeros.append("0")
}
var pattern = "#,##0"
if (zeros.isNotEmpty()) {
pattern += ".$zeros"
}
val numberFormat = DecimalFormat(pattern)
var formattedNumber = if (d != null) numberFormat.format(d) else "0"
if (!isDecimalRequired) {
for (i in formattedNumber.length downTo formattedNumber.length - zeroCount) {
val number = formattedNumber[i - 1]
if (number == '0' || number == '.') {
formattedNumber = formattedNumber.substring(0, formattedNumber.length - 1)
} else {
break
}
}
}
return formattedNumber
}
Here are two ways to achieve it. First, the shorter (and probably better) way:
public static String formatFloatToString(final float f)
{
final int i = (int)f;
if(f == i)
return Integer.toString(i);
return Float.toString(f);
}
And here's the longer and probably worse way:
public static String formatFloatToString(final float f)
{
final String s = Float.toString(f);
int dotPos = -1;
for(int i=0; i<s.length(); ++i)
if(s.charAt(i) == '.')
{
dotPos = i;
break;
}
if(dotPos == -1)
return s;
int end = dotPos;
for(int i = dotPos + 1; i<s.length(); ++i)
{
final char c = s.charAt(i);
if(c != '0')
end = i + 1;
}
final String result = s.substring(0, end);
return result;
}
public static String fmt(double d) {
String val = Double.toString(d);
String[] valArray = val.split("\\.");
long valLong = 0;
if(valArray.length == 2) {
valLong = Long.parseLong(valArray[1]);
}
if (valLong == 0)
return String.format("%d", (long) d);
else
return String.format("%s", d);
}
I had to use this because d == (long)d was giving me violation in a SonarQube report.
I am using this for formatting numbers without trailing zeroes in our JSF application. The original built-in formatters required you to specify max numbers of fractional digits which could be useful here also in case you have too many fractional digits.
/**
* Formats the given Number as with as many fractional digits as precision
* available.<br>
* This is a convenient method in case all fractional digits shall be
* rendered and no custom format / pattern needs to be provided.<br>
* <br>
* This serves as a workaround for {#link NumberFormat#getNumberInstance()}
* which by default only renders up to three fractional digits.
*
* #param number
* #param locale
* #param groupingUsed <code>true</code> if grouping shall be used
*
* #return
*/
public static String formatNumberFraction(final Number number, final Locale locale, final boolean groupingUsed)
{
if (number == null)
return null;
final BigDecimal bDNumber = MathUtils.getBigDecimal(number);
final NumberFormat numberFormat = NumberFormat.getNumberInstance(locale);
numberFormat.setMaximumFractionDigits(Math.max(0, bDNumber.scale()));
numberFormat.setGroupingUsed(groupingUsed);
// Convert back for locale percent formatter
return numberFormat.format(bDNumber);
}
/**
* Formats the given Number as percent with as many fractional digits as
* precision available.<br>
* This is a convenient method in case all fractional digits shall be
* rendered and no custom format / pattern needs to be provided.<br>
* <br>
* This serves as a workaround for {#link NumberFormat#getPercentInstance()}
* which does not renders fractional digits.
*
* #param number Number in range of [0-1]
* #param locale
*
* #return
*/
public static String formatPercentFraction(final Number number, final Locale locale)
{
if (number == null)
return null;
final BigDecimal bDNumber = MathUtils.getBigDecimal(number).multiply(new BigDecimal(100));
final NumberFormat percentScaleFormat = NumberFormat.getPercentInstance(locale);
percentScaleFormat.setMaximumFractionDigits(Math.max(0, bDNumber.scale() - 2));
final BigDecimal bDNumberPercent = bDNumber.multiply(new BigDecimal(0.01));
// Convert back for locale percent formatter
final String strPercent = percentScaleFormat.format(bDNumberPercent);
return strPercent;
}
work with given decimal length...
public static String getLocaleFloatValueDecimalWithLength(Locale loc, float value, int length) {
//make string from float value
return String.format(loc, (value % 1 == 0 ? "%.0f" : "%."+length+"f"), value);
}
0.0 -> 0%
1.0 -> 100%
0.1 -> 10%
0.11 -> 11%
0.01 -> 1%
0.111 -> 11.1%
0.001 -> 0.1%
0.1111 -> 11.11%
0.0001 -> 0.01%
".replace()" is added because I was always getting wrong separator
import java.text.NumberFormat
fun Double.formating(): String {
val defaultFormat: NumberFormat = NumberFormat.getPercentInstance()
defaultFormat.minimumFractionDigits = 0
defaultFormat.maximumFractionDigits = 2
return defaultFormat.format(this).replace(",", ".")
}
Here is an answer that actually works (combination of different answers here)
public static String removeTrailingZeros(double f)
{
if(f == (int)f) {
return String.format("%d", (int)f);
}
return String.format("%f", f).replaceAll("0*$", "");
}
The best way to do this is as below:
public class Test {
public static void main(String args[]){
System.out.println(String.format("%s something", new Double(3.456)));
System.out.println(String.format("%s something", new Double(3.456234523452)));
System.out.println(String.format("%s something", new Double(3.45)));
System.out.println(String.format("%s something", new Double(3)));
}
}
Output:
3.456 something
3.456234523452 something
3.45 something
3.0 something
The only issue is the last one where .0 doesn't get removed. But if you are able to live with that then this works best. %.2f will round it to the last two decimal digits. So will DecimalFormat. If you need all the decimal places, but not the trailing zeros then this works best.
String s = "1.210000";
while (s.endsWith("0")){
s = (s.substring(0, s.length() - 1));
}
This will make the string to drop the tailing 0-s.

Rounding to one decimal place

I im currently working on a temprature converter app. Everything works but I can get over 5 decimals and I have tried to look it up and search on Google but can't find out how do it. Here is where I display the text in the main.java:
text = (EditText) findViewById(R.id.editText1);
result = (TextView) findViewById(R.id.tvResult);
float inputValue = Float.parseFloat(text.getText().toString());
DecimalFormat df = new DecimalFormat("#.00");
String s = (String.valueOf(ConvertFahrCels.convertCelsiusToFahrenheit(inputValue)));
String d = (String.valueOf(ConvertFahrCels.convertFahrenheitToCelsius(inputValue)));
if (celsiusButton.isChecked()) {
result.setText(d);
celsiusButton.setChecked(false);
fahrenheitButton.setChecked(true);
} else {
result.setText(s);
fahrenheitButton.setChecked(false);
celsiusButton.setChecked(true);
}
And here is where I calculate it:
// converts to celsius
public static float convertFahrenheitToCelsius(float fahrenheit) {
return ((fahrenheit - 32) * 5 / 9);
}
// converts to fahrenheit
public static float convertCelsiusToFahrenheit(float celsius) {
return ((celsius * 9) / 5) + 32;
}
Your code here implies it is creating a decimal format to do the work, but, you don't actually use it!
DecimalFormat df = new DecimalFormat("#.00");
String s = (String.valueOf(ConvertFahrCels.convertCelsiusToFahrenheit(inputValue)));
String d = (String.valueOf(ConvertFahrCels.convertFahrenheitToCelsius(inputValue)));
The code should be:
DecimalFormat df = new DecimalFormat("#.00");
String s = df.format(ConvertFahrCels.convertCelsiusToFahrenheit(inputValue));
String d = df.format(ConvertFahrCels.convertFahrenheitToCelsius(inputValue));
It is more common in Java now to use String formatting instead of decimal format. Consider:
String s = String.format("%.1f", ConvertFahrCels.convertCelsiusToFahrenheit(inputValue));
Finally, your question indicates you want 1 decimal place, but, the Decimal format you use adds two.

Convert float to String and String to float in Java

How could I convert from float to string or string to float?
In my case I need to make the assertion between 2 values string (value that I have got from table) and float value that I have calculated.
String valueFromTable = "25";
Float valueCalculated =25.0;
I tried from float to string:
String sSelectivityRate = String.valueOf(valueCalculated);
but the assertion fails
Using Java’s Float class.
float f = Float.parseFloat("25");
String s = Float.toString(25.0f);
To compare it's always better to convert the string to float and compare as two floats. This is because for one float number there are multiple string representations, which are different when compared as strings (e.g. "25" != "25.0" != "25.00" etc.)
Float to string - String.valueOf()
float amount=100.00f;
String strAmount=String.valueOf(amount);
// or Float.toString(float)
String to Float - Float.parseFloat()
String strAmount="100.20";
float amount=Float.parseFloat(strAmount)
// or Float.valueOf(string)
You can try this sample of code:
public class StringToFloat
{
public static void main (String[] args)
{
// String s = "fred"; // do this if you want an exception
String s = "100.00";
try
{
float f = Float.valueOf(s.trim()).floatValue();
System.out.println("float f = " + f);
}
catch (NumberFormatException nfe)
{
System.out.println("NumberFormatException: " + nfe.getMessage());
}
}
}
found here
I believe the following code will help:
float f1 = 1.23f;
String f1Str = Float.toString(f1);
float f2 = Float.parseFloat(f1Str);
This is a possible answer, this will also give the precise data, just need to change the decimal point in the required form.
public class TestStandAlone {
/**
* This method is to main
* #param args void
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
Float f1=152.32f;
BigDecimal roundfinalPrice = new BigDecimal(f1.floatValue()).setScale(2,BigDecimal.ROUND_HALF_UP);
System.out.println("f1 --> "+f1);
String s1=roundfinalPrice.toPlainString();
System.out.println("s1 "+s1);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Output will be
f1 --> 152.32
s1 152.32
If you're looking for, say two decimal places..
Float f = (float)12.34;
String s = new DecimalFormat ("#.00").format (f);
well this method is not a good one, but easy and not suggested. Maybe i should say this is the least effective method and the worse coding practice but, fun to use,
float val=10.0;
String str=val+"";
the empty quotes, add a null string to the variable str, upcasting 'val' to the string type.
There are three ways to convert float to String.
"" + f
Float.toString(f)
String.valueOf(f)
There are two ways Convert String to float
Float.valueOf(str)
Float.parseFloat(str);
Example:-
public class Test {
public static void main(String[] args) {
System.out.println("convert FloatToString " + convertFloatToString(34.0f));
System.out.println("convert FloatToStr Using Float Method " + convertFloatToStrUsingFloatMethod(23.0f));
System.out.println("convert FloatToStr Using String Method " + convertFloatToStrUsingFloatMethod(233.0f));
float f = Float.valueOf("23.00");
}
public static String convertFloatToString(float f) {
return "" + f;
}
public static String convertFloatToStrUsingFloatMethod(float f) {
return Float.toString(f);
}
public static String convertFloatToStrUsingStringMethod(float f) {
return String.valueOf(f);
}
}
String str = "1234.56";
float num = 0.0f;
int digits = str.length()- str.indexOf('.') - 1;
float factor = 1f;
for(int i=0;i<digits;i++) factor /= 10;
for(int i=str.length()-1;i>=0;i--){
if(str.charAt(i) == '.'){
factor = 1;
System.out.println("Reset, value="+num);
continue;
}
num += (str.charAt(i) - '0') * factor;
factor *= 10;
}
System.out.println(num);
To go the full manual route: This method converts doubles to strings by shifting the number's decimal point around and using floor (to long) and modulus to extract the digits. Also, it uses counting by base division to figure out the place where the decimal point belongs. It can also "delete" higher parts of the number once it reaches the places after the decimal point, to avoid losing precision with ultra-large doubles. See commented code at the end. In my testing, it is never less precise than the Java float representations themselves, when they actually show these imprecise lower decimal places.
/**
* Convert the given double to a full string representation, i.e. no scientific notation
* and always twelve digits after the decimal point.
* #param d The double to be converted
* #return A full string representation
*/
public static String fullDoubleToString(final double d) {
// treat 0 separately, it will cause problems on the below algorithm
if (d == 0) {
return "0.000000000000";
}
// find the number of digits above the decimal point
double testD = Math.abs(d);
int digitsBeforePoint = 0;
while (testD >= 1) {
// doesn't matter that this loses precision on the lower end
testD /= 10d;
++digitsBeforePoint;
}
// create the decimal digits
StringBuilder repr = new StringBuilder();
// 10^ exponent to determine divisor and current decimal place
int digitIndex = digitsBeforePoint;
double dabs = Math.abs(d);
while (digitIndex > 0) {
// Recieves digit at current power of ten (= place in decimal number)
long digit = (long)Math.floor(dabs / Math.pow(10, digitIndex-1)) % 10;
repr.append(digit);
--digitIndex;
}
// insert decimal point
if (digitIndex == 0) {
repr.append(".");
}
// remove any parts above the decimal point, they create accuracy problems
long digit = 0;
dabs -= (long)Math.floor(dabs);
// Because of inaccuracy, move to entirely new system of computing digits after decimal place.
while (digitIndex > -12) {
// Shift decimal point one step to the right
dabs *= 10d;
final var oldDigit = digit;
digit = (long)Math.floor(dabs) % 10;
repr.append(digit);
// This may avoid float inaccuracy at the very last decimal places.
// However, in practice, inaccuracy is still as high as even Java itself reports.
// dabs -= oldDigit * 10l;
--digitIndex;
}
return repr.insert(0, d < 0 ? "-" : "").toString();
}
Note that while StringBuilder is used for speed, this method can easily be rewritten to use arrays and therefore also work in other languages.

Format double to at least one significant digit in Java/Android

I have a DecimalFormat object which I'm using to format all of my double values to a set number of digits (let's say 2) when I'm displaying them. I would like it to normally format to 2 decimal places, but I always want at least one significant digit. For example, if my value is 0.2 then my formatter spits out 0.20 and that's great. However, if my value is 0.000034 my formatter will spit out 0.00 and I would prefer my formatter spit out 0.00003.
The number formatters in Objective-C do this very simply, I can just set a max number of digits I want to show at 2 and the minimum number of significant digits at 1 and it produces my desired output, but how can I do it in Java?
I appreciate any help anyone can offer me.
Kyle
Edit: I'm interested in rounding the values so 0.000037 displays as 0.00004.
It's not efficient, so if you perform this operation often I'd try another solution, but if you only call it occasionally this method will work.
import java.text.DecimalFormat;
public class Rounder {
public static void main(String[] args) {
double value = 0.0000037d;
// size to the maximum number of digits you'd like to show
// used to avoid representing the number using scientific notation
// when converting to string
DecimalFormat maxDigitsFormatter = new DecimalFormat("#.###################");
StringBuilder pattern = new StringBuilder().append("0.00");
if(value < 0.01d){
String s = maxDigitsFormatter.format(value);
int i = s.indexOf(".") + 3;
while(i < s.length()-1){
pattern.append("0");
i++;
}
}
DecimalFormat df = new DecimalFormat(pattern.toString());
System.out.println("value = " + value);
System.out.println("formatted value = " + maxDigitsFormatter.format(value));
System.out.println("pattern = " + pattern);
System.out.println("rounded = " + df.format(value));
}
}
import java.math.BigDecimal;
import java.math.MathContext;
public class Test {
public static void main(String[] args) {
String input = 0.000034+"";
//String input = 0.20+"";
int max = 2;
int min =1;
System.out.println(getRes(input,max,min));
}
private static String getRes(String input,int max,int min) {
double x = Double.parseDouble(((new BigDecimal(input)).unscaledValue().intValue()+"").substring(0,min));
int n = (new BigDecimal(input)).scale();
String res = new BigDecimal(x/Math.pow(10,n)).round(MathContext.DECIMAL64).setScale(n).toString();
if(n<max){
for(int i=0;i<max;i++){
res+="0";
}
}
return res;
}
}

Categories

Resources