64位双精度可以精确地表示整数+/- 2 53
鉴于这一事实,我选择将double类型用作所有类型的单一类型,因为我的最大整数是无符号32位.
但现在我必须打印这些伪整数,但问题是它们也与实际双打混合在一起.
那么如何在Java中很好地打印这些双打?
我试过了String.format("%f", value)
,这很接近,除了我得到很多小值的尾随零.
这是一个示例输出 %f
232.00000000 0.18000000000 1237875192.0 4.5800000000 0.00000000 1.23450000
我想要的是:
232 0.18 1237875192 4.58 0 1.2345
当然,我可以编写一个函数来修剪这些零,但由于字符串操作,这会导致很多性能损失.我可以用其他格式代码做得更好吗?
编辑
Tom E.和Jeremy S.的答案是不可接受的,因为它们都可以任意舍入到小数点后两位.请在回答之前先了解问题.
编辑2
请注意,String.format(format, args...)
是区域设置相关的(见下面的答案).
new DecimalFormat("#.##").format(1.199); //"1.2"
正如评论中所指出的,这不是原始问题的正确答案.
也就是说,这是一种非常有用的格式化数字的方法,没有不必要的尾随零.
如果想要打印存储为双精度的整数,就好像它们是整数一样,否则以最低必要精度打印双精度:
public static String fmt(double d) { if(d == (long) d) return String.format("%d",(long)d); else return String.format("%s",d); }
生产:
232 0.18 1237875192 4.58 0 1.2345
而且不依赖于字符串操作.
String.format("%.2f", value) ;
简而言之:
如果你想摆脱尾随零和Locale问题,那么你应该使用:
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
说明:
为什么其他答案不适合我:
Double.toString()
或者System.out.println
或FloatingDecimal.toJavaFormatString
使用科学记数法如果双小于10 ^ -3,或者大于或等于10 ^ 7
double myValue = 0.00000021d; String.format("%s", myvalue); //output: 2.1E-7
通过使用%f
,默认的小数精度是6,否则你可以对它进行硬编码,但如果你的小数点少,它会导致额外的零.示例:
double myValue = 0.00000021d; String.format("%.12f", myvalue); //output: 0.000000210000
通过使用setMaximumFractionDigits(0);
或%.0f
删除任何小数精度,这对于整数/长整数而不是双精度
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
通过使用DecimalFormat,您是本地依赖的.在法语区域设置中,小数点分隔符是逗号,而不是点:
double myValue = 0.00000021d; DecimalFormat df = new DecimalFormat("0"); df.setMaximumFractionDigits(340); System.out.println(df.format(myvalue));//output: 0,00000021
使用ENGLISH语言环境可确保在程序运行的任何位置获得小数点分隔符
为什么使用340 setMaximumFractionDigits
呢?
两个原因:
setMaximumFractionDigits
接受一个整数,但其实现的最大允许位数DecimalFormat.DOUBLE_FRACTION_DIGITS
等于340
Double.MIN_VALUE = 4.9E-324
因此,使用340位数字,您肯定不会绕过双倍和松散的精度
为什么不:
if (d % 1.0 != 0) return String.format("%s", d); else return String.format("%.0f",d);
这应该与Double支持的极值一起使用.产量:
0.12 12 12.144252 0
我的2美分:
if(n % 1 == 0) { return String.format(Locale.US, "%.0f", n)); } else { return String.format(Locale.US, "%.1f", n)); }
在我的机器上,以下功能大约比JasonD的答案提供的功能快7倍,因为它避免了String.format
:
public static String prettyPrint(double d) { int i = (int) d; return d == i ? String.valueOf(i) : String.valueOf(d); }
NOW,没关系.
字符串操作导致的性能损失为零.
以下是修改结束的代码 %f
private static String trimTrailingZeros(String number) { if(!number.contains(".")) { return number; } return number.replaceAll("\\.?0*$", ""); }
使用DecimalFormat
和setMinimumFractionDigits(0)
if (d == Math.floor(d)) { return String.format("%.0f", d); } else { return Double.toString(d); }
我做了一个DoubleFormatter
有效地将大量的double值转换为一个漂亮/可呈现的String:
double horribleNumber = 3598945.141658554548844; DoubleFormatter df = new DoubleFormatter(4,6); //4 = MaxInteger, 6 = MaxDecimal String beautyDisplay = df.format(horribleNumber);
如果V的整数部分具有科学家格式(1.2345e + 30)以上的MaxInteger => display V,则以正常格式124.45678显示.
MaxDecimal决定十进制数字的数字(与银行家的四舍五入修剪)
这里的代码:
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) { final String sharpByPrecision = Strings.repeat("#", maxFraction_); //if you do not use Guava library, replace with createSharp(precision); NumberFormat f = NumberFormat.getInstance(Locale.US); //Apply banker's 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 out side 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 (absvEXP_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) { final String sharpByPrecision = Strings.repeat("#", maxFraction_); //if you do not use Guava library, replace with createSharp(precision); final double absv = Math.abs(v); NumberFormat f = NumberFormat.getInstance(Locale.US); //Apply banker's 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_UP) { df.applyPattern("0."+sharpByPrecision+"E0"); } else { df.applyPattern("#,##0."+sharpByPrecision); } } return f.format(v); } /** * Convert "3.1416e+12" to "3.1416e+12" * 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(""); int p1 = s.indexOf('.'); if (p1>0) { resu.append(s.substring(0, p1)); resu.append(""); } else { p1 = 0; } int p2 = s.lastIndexOf('e'); if (p2>0) { resu.append(s.substring(p1, p2)); resu.append(""); resu.append(s.substring(p2, s.length())); resu.append(""); } else { resu.append(s.substring(p1, s.length())); if (p1==0){ resu.append(""); } } return resu.toString(); } }
注意:我使用了GUAVA库中的2个函数.如果您不使用GUAVA,请自行编码:
/** * Equivalent to Strings.repeat("#", n) of the Guava library: */ private static String createSharp(int n) { StringBuilder sb = new StringBuilder(); for (int i=0;i
12> 184467440737..:请注意,它
String.format(format, args...)
是依赖于语言环境的,因为它使用用户的默认语言环境进行格式化,也就是说,可能使用逗号甚至内部空格,如123 456,789或123,456.789,这可能与您的预期完全不同.您可能更喜欢使用
String.format((Locale)null, format, args...)
.例如,
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));版画
123456,789000 123456,789000 123456.789000这就是
String.format(format, args...)
不同国家的做法.编辑好了,因为有关于手续的讨论:
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; }
13> Bialy..:这个我可以很好地完成工作,我知道这个话题很老,但是直到遇到这个问题我一直在努力解决同样的问题。我希望有人觉得它有用。
public static String removeZero(double number) { DecimalFormat format = new DecimalFormat("#.###########"); return format.format(number); }