Related
I have a business case where I need to get the decimal values as a new integer and
then traverse it from left to right to evaluate.
Eg: I have a integer value int val=1345679;
square root of val is double sqrt_val=1160.03405122; //sqrt(1345679), decimal values are limit to 8 digits
Now I need decimal value(03405122) to store it into integer variable
int decimalValue=03405122;
With this decimal value I want to verify with some number which is given by business.
Let's take some number as 45.
now I have to verify decimalValue until it meets the below condition
03405122<=45 if yes just take the decimal value
if no then remove the 1st digit from left side until condition satisfiet
3405122<=45
405122<=45
05122<=45
5122<=45
122<=45
22<=45.
So, 22 is the number I have to take for further implementation.
This is the code which I have written, and give me some suggestions that If I can write in a better way.
// Extracting Decimal value
public int extractDecimal(int computeRandomNumber)
{
int _computeRandom = computeRandomNumber;
double sqrt = Math.sqrt(_computeRandom);
BigDecimal df;
df = round(sqrt, 8);
// System.out.println(df);
String sqrt_round = String.valueOf(df);
// System.out.println(sqrt_round);
int index = sqrt_round.lastIndexOf('.') + 1;
String sqrt_round_deci = sqrt_round.substring(index);
// System.out.println(sqrt_round_deci);
return Integer.parseInt(sqrt_round_deci);
}
//Comparing with the some number to find the random number
public int findRandomNumber(int value, int totalRange) {
int _val;
System.out.println("calling rec::: val:" + value);
if (value <= totalRange) {
System.out.println("Success... returing on final value:" + value);
return value;
}
String new_str = String.valueOf(value);
String final_str = new_str.substring(1);
// System.out.println("str:"+final_str);
int val = Integer.parseInt(final_str);
// System.out.println("val:"+val);
_val = findRandomNumber(val, totalRange);
return _val;
// System.out.println("Returning flag:"+flag);
}
Thanks in Advance!
As you provided a pseudo-code only question, I will be generous and provide a pseudo-code only answer:
1) Get the String value of sqrt_val
2) Use the substring() method to get only the places1 after the .
3) Loop through the length2 of said substring
4) Check on each iteration if the valueOf your String is less than your target
5a) If so, there's your result
5b) If not, get the substring starting from position 1
1 If this begins with a 0, your results may vary so I'll leave this for you to work out
2 If you use this way, be careful if your loop goes via String.length as you use a substring in the else
I am in no way convinced that this is the best solution but here's an alternative solution which doesn't use Strings.
import java.math.BigDecimal;
public class Test {
public static void main(String[] args) {
// Value to be less than
BigDecimal lessThan = new BigDecimal(80);
int test = 333444;
BigDecimal bd = new BigDecimal( Math.sqrt(test) );
System.out.println(bd);
while( bd.scale() > 0 ) {
// get the fractional value and make it a whole number
BigDecimal fractionOnly = bd.divideAndRemainder(BigDecimal.ONE)[1];
fractionOnly = fractionOnly.movePointRight(fractionOnly.scale());
// do the check
System.out.println( fractionOnly + " < " + lessThan );
if ( fractionOnly.compareTo( lessThan ) < 0 ) {
System.out.println( "Yes" );
break;
}
// method kinda says it
bd = bd.movePointRight(1);
}
}
}
I'm using the documentation's stock factorial operator which looks like this:
factorial = new Operator("!", 1, true, Operator.PRECEDENCE_POWER + 1) {
#Override public double apply(double... args) {
final long arg = (long) args[0];
if ((double) arg != args[0]) {
throw new IllegalArgumentException("Operand for factorial has to be an " + "integer");
}
if (arg < 0) {
throw new IllegalArgumentException("The operand of the factorial can not " +
"be " +
"less than zero");
}
double result = 1;
for (int i = 1; i <= arg; i++) {
result *= i;
}
return result;
}
};
It works as intended for regular expressions, but when I have an expression like
5^(2)! it returns 25 when the expected answer would be1.55e25. It takes the 2 as its argument instead of the final answer of the power.
I tried messing around with the precedence but nothing seems to be making a difference.
Any ideas?
Seems correct to me. 5^2! should be 25 as should 5^(2)!
Google confirmed both of those.
Perhaps you meant (5^2)! instead? That should fix it.
I don't know any case where putting parens around a single number changes the order of operation.
I wrote Java code to convert String to long. However, when dealing with overflow problem, I don't have clues how to solve it. If a number is overflowed, computer believe every number is legal in storage. How to let program, with 64bit jdk ,detect the real number is overflowed is the key problem. And I'm not allowed to use any built-in library such as parseLong or others.
public static long strTolong(String s){
//error checking
if(s == null) return 0;
s = s.trim();//remove all space character
boolean neg = false;//judge the number is negative or positive
int pos = 0 ; //index of string
long result = 0;
//check positive or negative
if(s.charAt(pos) == '-'){
neg = true;
pos++;
}else if(s.charAt(pos) == '+') pos++;
//calculate result
while(pos<s.length()){
if(s.charAt(pos) >='0' && s.charAt(pos) <='9'){
result = result*10+(s.charAt(pos) - '0');
}else
break;
pos++;
}
if(neg) result =-result;
//check overflow
if(result >Long.MAX_VALUE) {
return Long.MAX_VALUE;
}
if(result<Long.MIN_VALUE){
return Long.MIN_VALUE;
}
return result;
}
If data is larger than long.maxvalue, the result can't be stored in computer correctly.
How to solve this problem?
Your best option is probably to do a lexicographical comparison between the input and the minimum/maximum numbers before you start.
static int compare(String v1, String v2) {
boolean neg1 = v1.startsWith("-");
boolean neg2 = v2.startsWith("-");
return neg1 ? (neg2 ? -comparePositives(v1.substring(1),v2.substring(1)):-1)
: (neg2 ? 1 : comparePositives(v1, v2));
}
static int comparePositives(String v1, String v2) {
// Is one longer?
if (v1.length() != v2.length())
return v1.length() < v2.length() ? -1 : 1;
// Both empty?
if (v1.isEmpty())
return 0;
// First digit differs?
if (v1.charAt(0) != v2.charAt(0))
return v1.charAt(0) < v2.charAt(0) ? -1 : 1;
// Recurse on rest of number
return comparePositives(v1.substring(1), v2.substring(1));
}
Use it for instance as follows:
if (compare(s, ""+Long.MIN_VALUE) == -1)
throw new NumberFormatException("Input too small");
if (compare(s, ""+Long.MAX_VALUE) == 1)
throw new NumberFormatException("Input too large");
Tested here: http://ideone.com/HmMkJ3
Note that the code does not check that the input is well formed. I suggest you do such check first. (Be aware of cases like 0 and -0 etc.)
You could do the same thing that Long#parseLong would do:
throw new NumberFormatException("too long (pun intended): "+s);
I am not sure what you trying to achieve here. If String is greater than Long.MAX_VALUE means that is no more a Long value.
If your String value is withing the range of Long, you can use Long.parseLong() with out this kind of hard ways.
If you want to have huge number you can use BigDecimal easily
String max = Long.MAX_VALUE+"";
System.out.println(max);
long maxL=Long.parseLong(max)+1;
System.out.println(maxL);
BigDecimal bigDecimal=new BigDecimal(max).add(new BigDecimal("1"));
System.out.println(bigDecimal);
Out put:
9223372036854775807 // long max value
-9223372036854775808 // incorrect result in long
9223372036854775808 // BigDecimal gives you correct one
For your case you can throws an Exception if value is greater than Long.MAX_VALUE or lower than Long.MIN_VALUE
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.
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.