542

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).

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Pyrolistical
  • 26,088
  • 21
  • 78
  • 104

27 Answers27

435
new DecimalFormat("#.##").format(1.199); //"1.2"

As pointed in the comments, this is not the right answer to the original question.
That said, it is a very useful way to format numbers without unnecessary trailing zeros.

Tom Esterez
  • 20,104
  • 8
  • 33
  • 38
  • 16
    An important note here is that 1.1 would properly be formatted as "1.1" without any trailing zeros. – Steve Pomeroy Apr 27 '11 at 07:10
  • Exactly what was asked for (and what I needed when I clicked on this question. – Zulaxia Apr 30 '11 at 09:49
  • 56
    And if you happen to want a specific number of trailing zeroes (e.g. if you are printing money amounts) then you can use '0' instead of '#' (i.e. new DecimalFormat("0.00").format(amount);) this isn't what OP wanted, but may be useful for reference. – TJ Ellis Oct 19 '11 at 19:31
  • 22
    Yes, as the original author of the question this is the WRONG answer. Funny how many up votes there are. The problem with this solution is it arbitrarily rounds to 2 decimal places. – Pyrolistical Dec 10 '12 at 18:00
  • 5
    @Pyrolistical I don't get why you can't just use: `new DecimalFormat("#.##########").format(1.199);` ??? – Mazyod Jan 26 '13 at 07:44
  • 11
    @Mazyod because you can always pass in a floating pointing with more decimals than the format. That is writing code that will work most of the time but not cover all the edge cases. – Pyrolistical Feb 15 '13 at 17:15
  • 2
    @Pyrolistical You could use so many decimal points in the format it doesn't round beyond what precision is lost due to floating point representations internally (i.e. at many many decimals places, `double` loses precision). However, this is an awkward solution; I believe JasonD's answer is the best way to go. – FThompson Feb 15 '13 at 17:21
  • @Vulcan yes, the code would not be obvious that your selected format exceeds the precision of double. if somebody were to copy such code to apply it to a 128-bit float, it wouldn't be obvious you need to add more precision to the format. – Pyrolistical Feb 20 '13 at 19:03
  • 15
    @Pyrolistical - IMHO, there are many upvotes because, although this is the wrong solution for you, it is the right solution for 99%+ of those who find this Q&A: usually, the final few digits of a double are "noise", that clutter the output, interfering with readability. Hence the programmer determines how many digits are beneficial to the person reading the output, and specifies that many. A common situation is small math errors have accumulated, so a value might be 12.000000034, but would prefer rounding to 12, and displaying compactly as "12". And "12.340000056" => "12.34". – ToolmakerSteve Sep 14 '14 at 19:17
  • 2
    Man, I owe you a beer :-) – Roman Nov 26 '14 at 12:47
  • 1
    Warning: This is *Locale dependent* – Zarathustra Nov 25 '15 at 10:32
  • well this is not working for me i had an array of 180 items i want each item upto four decimal places when i do it some of the values return zero!!! – Nowshad Aug 09 '16 at 08:32
  • This may not be the right answer to the original question, but it is the right answer for 95% of people coming here from google – Joe Maher Dec 20 '16 at 06:03
  • 1
    Formatters are expensive, do not create these in onBind and methods as such. Use one and re-use. Which leads to the other important (not mentioned) fact here: Formatters are *NOT* thread-safe. So if you're going to re-use one, make sure you use ThreadLocal<> or similar. – Martin Marconcini Mar 02 '17 at 01:56
  • @sirelon lol - the same string format works for C# too :-) didn't even realize this was a Java question until I got distracted by reading the comments – Simon_Weaver Sep 04 '17 at 02:46
  • offtopic answer, you wrong answer doesn't return `232 0.18 1237875192 4.58 0 1.2345` – user924 Dec 03 '20 at 10:14
429

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.

ToolmakerSteve
  • 5,893
  • 8
  • 67
  • 145
JasonD
  • 15,840
  • 2
  • 28
  • 42
  • 9
    Agreed, this is a bad answer, do not use it. It fails to work with a `double` larger than the maximum `int` value. Even with `long` it would still fail for huge numbers. Further it will return a String in exponential form, e.g. "1.0E10", for large values, which is probably not what the asker wants. Use `%f` instead of `%s` in the second format string to fix that. – jlh Feb 03 '14 at 12:48
  • 29
    The OP stated explicitly that they did not *want* the output formatted using `%f`. The answer is specific to the situation described, and the desired output. The OP suggested their maximum value was a 32-bit unsigned int, which I took to mean that `int` was acceptable (unsigned not actually existing in Java, and no exemplar was problematic), but changing `int` to `long` is a trivial fix if the situation is different. – JasonD Feb 03 '14 at 14:26
  • 1
    Where in the question does it say it shouldn't do that? – JasonD Feb 18 '14 at 17:28
  • FYI, I changed "int" to "long", to cover a larger range of values, as suggested in the comments above. – ToolmakerSteve Nov 07 '14 at 01:54
  • Depending on the current locale, you may get the number formatted with spaces and commas inside. – 18446744073709551615 Mar 13 '15 at 10:07
  • 10
    `String.format("%s",d)`??? Talk about unnecessary overhead. Use `Double.toString(d)`. Same for the other: `Long.toString((long)d)`. – Andreas Oct 14 '15 at 23:00
  • Good solution if you know that the "d" value is always in a valid range. Agree with Andreas about not using String.format() though. – northernman Dec 28 '15 at 03:27
  • 17
    The problem is that `%s` doesn't work with Locales. In German, we use a "," instead of a "." in decimal numbers. While `String.format(Locale.GERMAN, "%f", 1.5)` returns "1,500000", `String.format(Locale.GERMAN, "%s", 1.5)` returns "1.5" – with a ".", which is false in German language. Is there a locale-dependent version of "%s" as well? – Felix Edelmann Apr 19 '16 at 17:42
  • 1
    String value = (f == (long) f) ? String.valueOf((long) f) : String.valueOf(f); – Lukas Hanacek Feb 07 '18 at 09:54
  • Came across this problem as I was working on a contest problem: I came across this solution as well, but it didn't seem to solve the problem for me as for some test cases, it would format the solution into scientific notation, which is not ideal. – simonzhu Apr 15 '18 at 21:05
241
String.format("%.2f", value);
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Jeremy Slade
  • 3,808
  • 1
  • 16
  • 14
  • 15
    That's correct but always prints trailing zeros even if there is no fractional part. String.format("%.2f, 1.0005) prints 1.00 and not 1. Is there any format specifier for not to print fractional part if it does not exist? – Emre Yazici Feb 05 '10 at 20:45
  • 103
    Down voted since the question is asking to strip all trailing zeros and this answer will always leave two floating points regardless of being zero. – Zulaxia Apr 30 '11 at 09:48
  • The DecimalFormat was a nice trick -- although I ended up using this one for my situation (game level timer) as the trailing zeros looked better. – Timothy Lee Russell Oct 08 '11 at 03:59
  • 2
    I think you can handle the trailing zeroes correctly by using g instead of f. – Peter Ajtai Jan 04 '12 at 00:36
  • 4
    I used this solution in a production system with "%.5f", and it is really really bad, do not use it... because it printed this: 5.12E-4 instead of 0.000512 – hamish Jul 08 '14 at 11:21
  • Although this is exactly opposite to what the OP is tryna ask but I'm grateful this existed here, I was looking for just this! – Yash Joshi May 28 '21 at 19:34
102

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
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
JBE
  • 9,856
  • 6
  • 45
  • 44
  • This does not work for integers, e.g. "2" becomes "2." – kap Feb 03 '15 at 16:45
  • Thanks, I've fixed the answer by using the pattern `0` instead of `#.` – JBE Feb 09 '15 at 22:49
  • You are not using the constant `DecimalFormat.DOUBLE_FRACTION_DIGITS` but you are using the value 340, which you then provide a comment for to show that it equals `DecimalFormat.DOUBLE_FRACTION_DIGITS`. Why not just use the constant??? – Maarten Bodewes Oct 23 '15 at 14:47
  • 3
    Because this attribute is not public ... it is "package friendly" – JBE Oct 23 '15 at 17:27
  • 5
    Thanks! In fact, this answer is the only one that really matches all requirements mentioned in the question – it doesn't show unnecessary zeros, doesn't round the numbers and is locale-dependant. Great! – Felix Edelmann Apr 20 '16 at 15:57
  • Thanks! My requirement was to remove the trailing zeroes without loosing precision. This is so far the best answer I've found online. Initializing `df` just once in the class did the trick for all `double` number prints. – NurShomik Jan 23 '17 at 20:31
  • what would be a solution if you require minimal 2 fractional digits (even if zero) and all the rest as per above (remove all the non-needed 0's in the precision). – jcuypers Sep 26 '17 at 12:02
  • Using this with 0.001f results in 0.0010000000474974513 Any idea why? – Robert Stoll Jan 07 '18 at 22:29
  • @RobertStoll because floating point numbers are intrinsically imprecise. Try doing `assert(0.001f == 0.001f)` and it will fail. See this question for (very) thorough explanation: https://stackoverflow.com/questions/21895756/why-are-floating-point-numbers-inaccurate – drake Jan 10 '19 at 12:25
  • Thanks, worked for me. This answer would have been accepted if it was me who posted the question. Great explaination – Demon App Programmer Jul 29 '19 at 18:46
32

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
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Valeriu Paloş
  • 2,792
  • 1
  • 15
  • 11
29

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);
}
Community
  • 1
  • 1
Rok Strniša
  • 6,085
  • 6
  • 37
  • 48
24

My two cents:

if(n % 1 == 0) {
    return String.format(Locale.US, "%.0f", n));
} else {
    return String.format(Locale.US, "%.1f", n));
}
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Fernando Gallego
  • 3,974
  • 27
  • 50
14

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*$", "");
}
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Pyrolistical
  • 26,088
  • 21
  • 78
  • 104
  • If you are going to down vote, you need to at least leave a comment – Pyrolistical Apr 01 '09 at 00:24
  • 7
    I downvoted because your solution is not the best way to go. Have a look at String.format. You need to use the correct format type, float in this instance. Look at my above answer. – jjnguy Apr 01 '09 at 02:28
  • 8
    I voted up because I am having the same problem, and nobody here seems to understand the problem. – Obay Jan 19 '11 at 10:38
  • 1
    Downvoted as the DecimalFormat mentioned in Tom's post is exactly what you were looking for. It strips zeros quite effectively. – Steve Pomeroy Apr 27 '11 at 07:15
  • Down voted for the same reason as Steve Pomeroy. The DecimalFormat answer is the best way to do this and should really be the accepted answer here. – Zulaxia Apr 30 '11 at 09:51
  • 5
    To the above, maybe he wants to trim the zeros WITHOUT rounding? P.S. @Pyrolistical, surely you can just use number.replaceAll(".?0*$", ""); (after contains(".") of course) – Rehno Lindeque Oct 06 '11 at 10:49
  • Thanks, my regex was rather pathetic when I first posted that. And Rehno nailed it on the head Tom's code rounds to 2 decimals places. – Pyrolistical Oct 22 '11 at 05:49
  • This solution is not localisable, which is one example why it is the wrong way to do it. If one day your application runs under a European locale, which uses commas as the decimal separator, it won't work. Whereas DecimalFormat automatically works under any locale. You might not plan to ever run in Europe but there may be other gotchas you haven't considered - using the inbuilt methods gives you the best chance to avoid them. – Fletch Jan 17 '12 at 11:12
  • 1
    Ok, then how would you be able to achieve my objective with the DecimalFormat? – Pyrolistical Jan 18 '12 at 06:59
  • 1
    By the way if I had localisation concerns I can add more logic. The most voted answer by @Tom does not fill the requirements. Tom's code is arbitrarily round to 2 decimal places. – Pyrolistical May 07 '12 at 18:20
  • 1
    Upvoted for understanding the problem well. But the regex should be "\\.?0*$". Otherwise, for 34.23298424000 it will give back 34.2329842 and not 34.23298424. – autra Feb 15 '13 at 14:31
9

Use a DecimalFormat and setMinimumFractionDigits(0).

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
vlazzle
  • 721
  • 8
  • 13
  • I would add `setMaximumFractionDigits(2)` and `setGroupingUsed(false)` (OP's doesn't mention it but from example it seems that its required). Also, a small test case doesn't hurt since its trivial in this case. Still, since I think it its the simplest solution, an upvote is an upvote :) – acrespo Jul 02 '19 at 13:57
8

This one will gets the job done nicely:

    public static String removeZero(double number) {
        DecimalFormat format = new DecimalFormat("#.###########");
        return format.format(number);
    }
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Bialy
  • 779
  • 1
  • 11
  • 20
7
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
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Ahmed Mihoub
  • 349
  • 3
  • 5
6
if (d == Math.floor(d)) {
    return String.format("%.0f", d);
} else {
    return Double.toString(d);
}
fop6316
  • 173
  • 2
  • 10
6
new DecimalFormat("00.#").format(20.236)
//out =20.2

new DecimalFormat("00.#").format(2.236)
//out =02.2
  1. 0 for minimum number of digits
  2. Renders # digits
Hossein Hajizadeh
  • 1,029
  • 15
  • 9
  • while this may provide a solution to the question, it is good practice to add a brief explanation for the community to benefit (and learn) from the answer – blurfus Jul 14 '17 at 17:14
  • this is not answer to that question. it always rounds to one number after a dot. Such a bad answer and offtopic – user924 Dec 03 '20 at 10:01
  • you wrong answer doesn't return `232 0.18 1237875192 4.58 0 1.2345` – user924 Dec 03 '20 at 10:13
5

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();
}
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Hiep
  • 2,191
  • 1
  • 22
  • 29
  • 1
    If you know the precision, then use a BigDecimal. See http://docs.oracle.com/javase/1.5.0/docs/api/java/math/BigDecimal.html#setScale%28int,%20java.math.RoundingMode%29 – Pyrolistical Dec 10 '12 at 19:28
5

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;
}
18446744073709551615
  • 14,600
  • 3
  • 82
  • 116
4
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);
    }
}
Pyrolistical
  • 26,088
  • 21
  • 78
  • 104
kamal
  • 290
  • 3
  • 18
  • you should instead just search for the first non-zero-digit from the right and then use the subString ( and also verify that the string contains "." of course). this way, you won't come into creating so many temporary strings on the way. – android developer May 18 '13 at 22:25
4

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
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Spotted
  • 3,635
  • 14
  • 33
3

Format price with grouping, rounding, and no unnecessary zeroes (in double).

Rules:

  1. No zeroes at the end (2.0000 = 2; 1.0100000 = 1.01)
  2. Two digits maximum after a point (2.010 = 2.01; 0.20 = 0.2)
  3. Rounding after the 2nd digit after a point (1.994 = 1.99; 1.995 = 2; 1.006 = 1.01; 0.0006 -> 0)
  4. Returns 0 (null/-0 = 0)
  5. Adds $ (= $56/-$56)
  6. 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

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
oxied
  • 1,488
  • 16
  • 14
2

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.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
keisar
  • 5,026
  • 5
  • 24
  • 26
  • 1
    Repeating what Felix Edelmann said elsewhere: this will create a Locale-independent string, which may not always be appropriate for the user. – JJ Brown Mar 08 '19 at 18:11
  • fair point, for my use case this was not an issue, I'm not entirely sure right now but I think one could use String.format (with the wanted Locale) instead of valueOf – keisar May 09 '19 at 22:06
2

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)
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Levor
  • 660
  • 7
  • 12
1

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
    }
Tenten Ponce
  • 2,256
  • 1
  • 9
  • 27
0

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;
}
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
android developer
  • 106,412
  • 122
  • 641
  • 1,128
  • formatFloatToString can be vastly simplified with http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#indexOf(java.lang.String) and http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#indexOf(java.lang.String, int) – Pyrolistical May 21 '13 at 18:51
  • 1
    sometimes, when you make things more simple, the code behind is more complex and less optimized... but yes, you can use plenty of built in API functions... – android developer May 21 '13 at 22:16
  • 1
    You should start with simple and once you have determined you have a performance problem, then and only then should you optimize. Code is for the human to read again and again. Making it run fast is secondary. By not using the standard API whenever possible you are more likely to introduce bugs and only makes it more difficult to change in the future. – Pyrolistical May 21 '13 at 23:02
  • I disagree. Base code should run as fast as possible, as many others might use it. Performance is a huge concern and this is something people are taught about a lot at the university. You can't predict how much you function will be used. Only the most higher functions can be exactly as you say. As an example, think what would a delay of 1 second be for each time you use internet connection. would you agree to those who made the class if they told you that their code is slow because it's a simple code? – android developer May 22 '13 at 05:18
  • 3
    I would argue code you write like that is NOT going to be any faster. The JVM is very smart and you don't actually know how fast or slow something is until you profile it. Performance problems can be detected and fixed when it becomes a problem. You should not prematurely optimize for it. Write code for people to read, not for how you imagine the machine is going to run it. Once it becomes a performance problem, rewrite code with a profiler. – Pyrolistical May 22 '13 at 17:41
  • just tried to make a point. if you wish using a short code, you can look at the first example, which works fine, and might even work better. – android developer May 22 '13 at 19:55
  • 2
    Somebody else edited the answer to improve the code formatting. I was reviewing several dozen edits for approval and was going to approve their edit here, but the edits were inconsistent so I fixed them. I also improved the grammar of the text snippets. – Steve Vinoski Aug 21 '15 at 15:24
  • @SteveVinoski Grammar of English - ok (English isn't my main langauge, and when I don't have enough time, I can't review what I write), but the code formatting doesn't need to get improved. It's a matter of taste, and what I use is always one of the standard code formatting. When the "{" align with the rest of the code block, it's called "Whitesmiths " : https://en.wikipedia.org/wiki/Indent_style#Whitesmiths_style . Any developer should be able to read this code formatting, just like any other code formatting. Besides, you can always copy and format via the IDE. – android developer Aug 21 '15 at 16:04
  • 1
    I don't understand. If you said the formatting didn't matter, why did you spend the time to change it back? – OrhanC1 Jun 27 '16 at 16:54
  • @OrhanC1 If it's not wrong in any way, it can stay with what I wrote. – android developer Jun 28 '16 at 15:19
  • 1
    I agree. But because you changed it back, it sounds like it matters. You actively put the effort in. That's all. – OrhanC1 Jun 28 '16 at 15:39
0
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.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
ShAkKiR
  • 765
  • 6
  • 18
0

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;
}
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
djmj
  • 5,266
  • 4
  • 47
  • 89
-1

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*$", "");
}
Martin Klosi
  • 2,589
  • 4
  • 26
  • 35
-4

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.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
sethu
  • 7,407
  • 5
  • 35
  • 61
  • 2
    DecimalFormat with format of "#.##" will not keep extra 0 if they are not needed: `System.out.println(new java.text.DecimalFormat("#.##").format(1.0005));` will print `1` – Aleks G May 09 '12 at 09:19
  • thats my point. What if you want the 0.0005 displayed if there is any. You will be rounding it 2 decimal digits. – sethu May 09 '12 at 11:33
  • The OP is asking how to print integer values stored in doubles :) – Aleks G May 09 '12 at 11:35
-10
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.

Kadi
  • 1
  • 1
  • 1
    This is a good solution to the question, if they were only interested in trailing zeroes being dropped, how would you change your code to also trim a trailing decimal point? i.e. "1." – bakoyaro Oct 26 '11 at 16:32
  • 33
    Be careful, your solution will convert 1000 into 1, which is wrong. – Aleks G May 09 '12 at 09:16