Gereksiz ondalık 0 olmadan kayan sayıları String için nasıl biçimlendiririm?


496

Bir 64-bit çift +/- 2 tamsayı temsil edebilir 53 tam

Bu gerçek göz önüne alındığında, tüm türlerim için tek bir tür olarak çift tür kullanmayı tercih ederim, çünkü en büyük tam sayım işaretsiz 32 bittir.

Ama şimdi bu sahte tamsayıları yazdırmak zorundayım, ama sorun şu ki, gerçek çiftlerle de karıştırılıyorlar.

Peki bu çiftleri Java'da nasıl güzelce yazdırabilirim?

Denedim String.format("%f", value), yakın olan, ancak küçük değerler için çok sayıda sıfır var.

İşte bir örnek çıktı %f

232.00000000
,18000000000
1237875192,0
4,5800000000
0.00000000
1.23450000

Ne istiyorum:

232
0.18
1237875192
4.58
0
1,2345

Tabii bu sıfırları kırpmak için bir işlev yazabilirim, ama bu String manipülasyonu nedeniyle çok fazla performans kaybı. Başka bir biçim koduyla daha iyisini yapabilir miyim?

DÜZENLE

Tom E. ve Jeremy S.'nin cevapları, ikisi de keyfi olarak 2 ondalık basamağa yuvarlandığından kabul edilemez. Lütfen cevaplamadan önce sorunu anlayın.

DÜZENLEME 2

Not Lütfen String.format(format, args...)olduğu yerele bağımlı (aşağıda cevapları bakınız).


Tüm istediğiniz tamsayılarsa, neden uzun kullanmıyorsunuz? 2 ^ 63-1'de daha fazla patlama, garip biçimlendirme ve daha iyi performans elde edersiniz.
basszero

14
Bazı değerler aslında iki katına çıktığı için
Pyrolistics

2
Bu sorunun oluştuğu bazı durumlar JDK 7'de düzeltilen bir
hataydı

Sadece ben mi yoksa JavaScript'ten sayıdan dizeye dönüşümde Java'dan% 100 daha mı iyi?
Andy

System.out.println("YOUR STRING" + YOUR_DOUBLE_VARIABLE);
Shayan Amani

Yanıtlar:


399

Buradaki fikir, tamsayılar gibi iki katına kaydedilmiş tamsayıları yazdırmak ve aksi halde gerekli olan en düşük hassasiyetle çiftleri yazdırmaksa:

public static String fmt(double d)
{
    if(d == (long) d)
        return String.format("%d",(long)d);
    else
        return String.format("%s",d);
}

üretir:

232
0.18
1237875192
4.58
0
1.2345

Ve dize manipülasyonuna dayanmaz.


9
Kabul ediyorum, bu kötü bir cevap, kullanmayın. doubleMaksimum intdeğerden daha büyük bir değerle çalışmaz . Bununla birlikte bile longbüyük sayılar için başarısız olur. Ayrıca büyük değerler için üstel formda, örneğin "1.0E10" şeklinde bir String döndürecektir, ki bu muhtemelen askerin istediği değildir. Bunu düzeltmek için ikinci biçim dizesi %fyerine kullanın %s.
jlh

26
OP , çıktının kullanılarak biçimlendirilmesini istemediklerini açıkça belirtti %f. Cevap açıklanan duruma ve istenen çıktıya özgüdür. OP maksimum değeri onu demek aldı 32 bit işaretsiz int oldu önerdi intkabul edilebilir (aslında Java mevcut değil imzasız ve hiçbir örnek problemli olduğunu), ancak değişen inthiç longdurum farklı ise önemsiz bir düzeltmedir.
JasonD

1
Sorunun neresinde bunu yapmaması gerektiğini söylüyor?
JasonD

6
String.format("%s",d)??? Gereksiz ek yük hakkında konuşun. Kullanın Double.toString(d). Diğeri için aynı: Long.toString((long)d).
Andreas

15
Sorun şu ki %s, Locales ile çalışmıyor. Almanca'da "yerine" yerine "" kullanıyoruz. ondalık sayılarda. İken String.format(Locale.GERMAN, "%f", 1.5)döner "1,500000", String.format(Locale.GERMAN, "%s", 1.5)döner "1.5" - Alman dilinde yanlış bir ile, "". Yerel ayarlara bağlı bir "% s" sürümü de var mı?
Felix Edelmann

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

Yorumlarda belirtildiği gibi, bu orijinal sorunun doğru cevabı değildir.
Bununla birlikte, gereksiz sondaki sıfırlar olmadan sayıları biçimlendirmenin çok yararlı bir yoludur.


16
Burada önemli bir not, 1.1'in herhangi bir sıfır olmadan düzgün şekilde "1.1" olarak biçimlendirilmesidir.
Steve Pomeroy

53
Ve belirli sayıda sondaki sıfırlar istiyorsanız (örneğin, para miktarlarını yazdırıyorsanız), '#' yerine '0' kullanabilirsiniz (yani yeni DecimalFormat ("0.00"). Biçim (miktar);)) OP'nin istediği şey değildir, ancak referans için yararlı olabilir.
TJ Ellis

22
Evet, sorunun asıl yazarı olarak bu YANLIŞ cevaptır. Komik kaç oy var. Bu çözümün problemi keyfi olarak 2 ondalık basamağa yuvarlanmasıdır.
Pirolistik

11
@Mazyod çünkü her zaman formattan daha fazla ondalık sayıyla kayan bir işaretle geçebilirsiniz. Bu, çoğu zaman işe yarayacak, ancak tüm kenar durumlarını kapsamaz.
Pyrolistik

15
@Pyrolistic - IMHO, birçok upvotes var, çünkü bu sizin için yanlış bir çözüm olmasına rağmen, bu soru ve cevapları bulanların% 99'u + için doğru çözümdür: genellikle, bir çiftin son birkaç basamağı "gürültü", çıktıyı karıştırarak okunabilirliğe müdahale eder. Böylece programcı, çıktıyı okuyan kişiye kaç basamak yararlı olduğunu belirler ve bu rakamın kaç tanesini belirtir. Yaygın bir durum küçük matematik hatalarının birikmesidir, bu nedenle bir değer 12.000000034 olabilir, ancak 12'ye yuvarlamayı ve kompakt olarak "12" olarak görüntülenmeyi tercih eder. Ve "12.340000056" => "12.34".
ToolmakerSteve

226
String.format("%.2f", value) ;

13
Bu doğru ama kesirli bir parça olmasa bile daima sıfırlar yazdırıyor. String.format ("%. 2f, 1.0005) 1 değil 1,00 yazdırır. Kesirli kısmı yoksa yazdırmamak için herhangi bir biçim belirteci var mı?
Emre Yazici

87
Down, soru tüm takip eden sıfırları ayırmak istediğinden ve bu cevap sıfırdan bağımsız olarak her zaman iki kayan nokta bırakacağından dolayı oy kullandı.
Zulaxia

DecimalFormat güzel bir numaraydı - her ne kadar benim durumum için (oyun seviyesi zamanlayıcısı) bunu takip eden sıfırlar daha iyi görünüyordu olarak kullandım.
Timothy Lee Russell

2
Bence f yerine g kullanarak sıfırları doğru şekilde işleyebilirsiniz.
Peter Ajtai

3
Bu çözümü "% .5f" ile bir üretim sisteminde kullandım ve gerçekten çok kötü, kullanmayın ... çünkü bunu yazdırdı: 0.000512 yerine 5.12E-4
hamish

87

Kısacası:

Sondaki sıfırlardan ve Yerel ayar sorunlarından kurtulmak istiyorsanız, şunları kullanmalısınız:

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

Açıklama:

Diğer cevaplar neden bana uymadı:

  • Double.toString()ya da System.out.printlnya da FloatingDecimal.toJavaFormatStringçift az 10 ^ -3 ise bilimsel semboller kullanan veya daha büyük ya da 10 ^ 7 eşit

    double myValue = 0.00000021d;
    String.format("%s", myvalue); //output: 2.1E-7
  • kullanarak %f, varsayılan ondalık duyarlık 6'dır, aksi takdirde sabit kodlayabilirsiniz, ancak daha az ondalık sayınız varsa ekstra sıfır eklenir. Misal :

    double myValue = 0.00000021d;
    String.format("%.12f", myvalue); //output: 0.000000210000
  • kullanarak setMaximumFractionDigits(0);veya %.0ftamsayılar / uzunlar için iyi olan ancak iki katına çıkmayan ondalık duyarlığı kaldırarak

    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 kullanarak yerel bağımlısınız. Fransızca yerel ayarında, ondalık ayırıcı virgüldür, nokta değildir:

    double myValue = 0.00000021d;
    DecimalFormat df = new DecimalFormat("0");
    df.setMaximumFractionDigits(340);
    System.out.println(df.format(myvalue));//output: 0,00000021

    İNGİLİZCE yerel ayarını kullanmak, programınızın çalışacağı her yerde ondalık ayırıcı için bir nokta elde etmenizi sağlar

Neden 340 için kullanıyorsunuz setMaximumFractionDigits?

İki sebep :

  • setMaximumFractionDigitsbir tamsayı kabul eder ancak uygulanması izin maksimum basamak DecimalFormat.DOUBLE_FRACTION_DIGITSolan 340 eşittir
  • Double.MIN_VALUE = 4.9E-324 340 basamakla, çift ve gevşek hassasiyetinizi yuvarlamayacağınızdan emin olabilirsiniz

Bu tamsayılar için çalışmaz, örneğin "2" "2" olur.
kap

Teşekkürler, 0bunun yerine deseni kullanarak cevabı çözdüm#.
JBE

Sabiti kullanmıyorsunuz, DecimalFormat.DOUBLE_FRACTION_DIGITSancak 340 değerini kullanıyorsunuz, daha sonra buna eşit olduğunu göstermek için bir yorum yapıyorsunuz DecimalFormat.DOUBLE_FRACTION_DIGITS. Neden sadece sabiti kullanmıyorsunuz ???
Maarten Bodewes

1
Bu özellik herkese açık olmadığı için ... "paket dostu"
JBE

4
Teşekkürler! Aslında, bu cevap soruda belirtilen tüm gereksinimlere gerçekten uyan tek cevaptır - gereksiz sıfırlar göstermez, sayıları yuvarlamaz ve yerel ayara bağlıdır. Harika!
Felix Edelmann

26

Neden olmasın:

if (d % 1.0 != 0)
    return String.format("%s", d);
else
    return String.format("%.0f",d);

Bu, Double tarafından desteklenen aşırı değerlerle çalışmalıdır. Verim:

0.12
12
12.144252
0

2
Tür dönüşümü yapmak zorunda olmadığımız bu cevabı tercih ederim.
Jeff T.

Kısa açıklama: "%s"temelde arar d.toString()ama ile intya da çalışmıyor d==null!
Nefret

24

Makinemde , aşağıdaki işlev, JasonD'nin cevabının sağladığı işlevden kabaca 7 kat daha hızlıdır , çünkü kaçınır String.format:

public static String prettyPrint(double d) {
  int i = (int) d;
  return d == i ? String.valueOf(i) : String.valueOf(d);
}

1
Hmm, bu yerel ayarları hesaba katmıyor, ama JasonD'ler de dikkate almıyor.
TWiStErRob

22

2 sentim:

if(n % 1 == 0) {
    return String.format(Locale.US, "%.0f", n));
} else {
    return String.format(Locale.US, "%.1f", n));
}

2
Veya sadece return String.format(Locale.US, (n % 1 == 0 ? "%.0f" : "%.1f"), n);.
MC İmparatoru

23.00123 ==> 23.00
aswzen

11

Hayır, boş ver.

Dize manipülasyonu nedeniyle performans kaybı sıfırdır.

Ve işte sonu kesen kod %f

private static String trimTrailingZeros(String number) {
    if(!number.contains(".")) {
        return number;
    }

    return number.replaceAll("\\.?0*$", "");
}

7
İndirdim çünkü çözümünüz en iyi yol değil. String.format'a bir göz atın. Doğru format türünü kullanmanız, bu örnekte yüzmeniz gerekir. Yukarıdaki cevabıma bak.
jjnguy

6
Oy verdim çünkü aynı sorunu yaşıyorum ve buradaki kimse sorunu anlamıyor gibi görünüyor.
Program Müdürlüğü'nden

1
Tom'un gönderisinde belirtilen DecimalFormat olarak aradığınız şey tam olarak aradığınız şeydir. Sıfırları oldukça etkili bir şekilde çıkarır.
Steve Pomeroy

4
Yukarıdakilere, belki yuvarlama olmadan sıfırları düzeltmek istiyor? PS @Pyrolistics, kesinlikle number.replaceAll (".? 0 * $", ""); (tabii sonra içerir ("."))
Rehno Lindeque

1
Tamam, o zaman DecimalFormat ile hedefime nasıl ulaşabilirdiniz?
Ocak'ta Pyrolistik

8

A DecimalFormatve kullanınsetMinimumFractionDigits(0)


Ben eklemek setMaximumFractionDigits(2)ve setGroupingUsed(false)(OP's bahsetmiyorum ama örnek olarak gerekli görünüyor). Ayrıca, bu durumda önemsiz olduğundan küçük bir test vakası zarar görmez. Yine de, bunun en basit çözüm olduğunu düşündüğüm için, bir upvote bir upvote :)
19:13

6
if (d == Math.floor(d)) {
    return String.format("%.0f", d);
} else {
    return Double.toString(d);
}

1
Sanırım seni takip edeceğim: D
aeracode

5

Lütfen not String.format(format, args...)olan yerele bağımlı o biçimlendirir, çünkü kullanıcının varsayılan yerel ayarını kullanarak muhtemelen gibi içeri virgül ve hatta alanlar ile, 123 456789 veya 123,456.789 tam olarak beklediğiniz olabilir.

Kullanmayı tercih edebilirsiniz String.format((Locale)null, format, args...).

Örneğin,

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

baskılar

123456,789000
123456,789000
123456.789000

ve String.format(format, args...)farklı ülkelerde yapacaklar.

EDIT Tamam, formaliteler hakkında bir tartışma olduğu için:

    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;
}

1
bunu kabul edilen cevaba bir yorum olarak eklemelisiniz
Pyrolistics

Yorumlar bu ekin uzunluğuna veya biçimine izin vermez. Muhtemelen faydalı bilgiler eklediğinden, silinmek yerine izin verilmesi gerektiğini düşünüyorum.
Terry Jan Reedy

5

Ben DoubleFormatterverimli bir şekilde güzel / prezentabl bir dize çift sayı çok sayıda dönüştürmek için yapılmış :

double horribleNumber = 3598945.141658554548844; 
DoubleFormatter df = new DoubleFormatter(4,6); //4 = MaxInteger, 6 = MaxDecimal
String beautyDisplay = df.format(horribleNumber);
  • V tamsayı kısmı MaxInteger => 'den fazla ise bilim adamı formatında (1.2345e + 30) V gösterirse, aksi takdirde normal format 124.45678'de görüntülenir.
  • Ondalık basamakların MaxDecimal karar sayısı (bankanın yuvarlamasıyla kırpma)

İşte kod:

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 (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) {

        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_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();
    }
}

Not: GUAVA kütüphanesinden 2 fonksiyon kullandım. GUAVA kullanmıyorsanız, kendiniz kodlayın:

/**
 * 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();
}

1
Hassasiyeti biliyorsanız, bir BigDecimal kullanın. Bkz. Docs.oracle.com/javase/1.5.0/docs/api/java/math/…
Pyrolistics

5

Bu işi güzelce halledecek, konunun eski olduğunu biliyorum, ama ben gelene kadar aynı sorunla mücadele ediyordum. Umarım birisi faydalı bulur.

    public static String removeZero(double number) {
        DecimalFormat format = new DecimalFormat("#.###########");
        return format.format(number);
    }

5
new DecimalFormat("00.#").format(20.236)
//out =20.2

new DecimalFormat("00.#").format(2.236)
//out =02.2
  1. Minimum basamak sayısı için 0
  2. # Basamak oluşturur

Bu soruya bir çözüm sağlayabilir, ancak topluluğun
yanıttan

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);
    }
}

bunun yerine sadece sağdan ilk sıfır olmayan rakamı aramalı ve sonra subString'i kullanmalısınız (ve ayrıca dizenin "." içerdiğini doğrulamalısınız). bu şekilde, yolda çok fazla geçici dizge oluşturmayacaksınız.
android geliştirici

3

Geç cevap ama ...

Numaralarınızı çift ​​tip ile kaydetmeyi seçtiğinizi söylediniz . Sanırım bu sorunun kökü olabilir, çünkü tamsayıları iki katına (ve değerin doğası hakkındaki ilk bilgileri kaybetmeye) depolamaya zorlar . Sayılarınızı Number sınıfı (Double ve Integer'ın üst sınıfı ) örneklerinde depolamaya ve her sayının doğru biçimini belirlemek için polimorfizme güvenmeye ne dersiniz ?

Bu nedenle kodunuzun bir kısmını yeniden düzenlemenin kabul edilemeyeceğini biliyorum, ancak ekstra kod / döküm / ayrıştırma olmadan istenen çıktıyı üretebilir.

Misal:

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);
        }
    }

}

Aşağıdaki çıktıyı üretecektir:

232
0.18
1237875192
4.58
0
1.2345

javascript bu arada aynı seçimi yaptı :)
Pyrolistics

@Pyrolistik İfadenizi biraz daha açıklayabilir misiniz? Oldukça :) ... benim için açık değil
Benekli

2

Ben geldi budur:

  private static String format(final double dbl) {
    return dbl % 1 != 0 ? String.valueOf(dbl) : String.valueOf((int) dbl);
  }

Basit bir astar, sadece gerçekten gerekiyorsa int'e çevirir


1
Felix Edelmann'ın başka yerlerde söylediklerini tekrarlamak: bu, her zaman kullanıcı için uygun olmayabilecek bir Yerel Ayardan bağımsız dize oluşturur.
JJ Brown

adil nokta, benim kullanım durumum için bu bir sorun değildi, şu anda tam olarak emin değilim ama bence biri valueOf
keisar

2

Fiyat gruplama, yuvarlama, gereksiz sıfır yok (çift olarak).

Kurallar:

  1. Sonunda sıfır yok ( 2.0000 = 2; 1.0100000 = 1.01)
  2. Bir noktadan sonra maksimum iki basamak ( 2.010 = 2.01; 0.20 = 0.2)
  3. Bir noktadan sonraki 2. basamaktan sonra yuvarlama ( 1.994 = 1.99; 1.995 = 2; 1.006 = 1.01; 0.0006 -> 0)
  4. İade 0( null/-0 = 0)
  5. Ekler $( = $56/-$56)
  6. Gruplama ( 101101.02 = $101,101.02)

Daha fazla örnek:

-99.985 = -$99.99

10 = $10

10.00 = $10

20.01000089 = $20.01

Kotlin'de eğlenceli bir uzantısı olarak yazılan Double (neden Android'de kullanılır), ancak Java'ya kolayca dönüştürülebilir, neden java sınıfları kullanılmıştır.

/**
 * 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)
    }
}

Nasıl kullanılır:

var yourDouble: Double? = -20.00
println(yourDouble.formatUserAsSum()) // will print -$20

yourDouble = null
println(yourDouble.formatUserAsSum()) // will print $0

DecimalFormat Hakkında : https://docs.oracle.com/javase/6/docs/api/java/text/DecimalFormat.html


1
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);
}

d == (long)dSonar raporunda bu ihlali bana ihlal etmek için kullanmak zorunda kaldım


1
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));

bu bazı testlerin sonucudur:

4.30     => 4.3
4.39     => 4.39  // Choose format.setRoundingMode(RoundingMode.UP) to get 4.4
4.000000 => 4
4        => 4

1.23450000 hakkında ne?
Alex78191

1.23450000 => 1.23
Ahmed Mihoub

0

İşte bunu başarmanın iki yolu. İlk olarak, daha kısa (ve muhtemelen daha iyi) yol:

public static String formatFloatToString(final float f)
  {
  final int i=(int)f;
  if(f==i)
    return Integer.toString(i);
  return Float.toString(f);
  }

Ve işte daha uzun ve muhtemelen daha kötü yol:

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;
  }

1
Bazen, işleri daha basit hale getirdiğinizde, arkasındaki kod daha karmaşık ve daha az optimize edilir ... ancak evet, yerleşik API işlevlerinin bol miktarda kullanabilirsiniz ...
android geliştirici

1
Basit ile başlamalısınız ve bir kez bir performans sorununuz olduğunu belirledikten sonra, ancak o zaman optimizasyon yapmanız gerekir. Kod, insanın tekrar tekrar okuması içindir. Hızlı çalışmasını sağlamak ikincildir. Mümkün olduğunca standart API'yi kullanmamanız durumunda, hataları getirme olasılığınız daha yüksektir ve yalnızca gelecekte değiştirilmesini zorlaştırır.
Pirolistik

3
Ben daha hızlı olmayacak gibi yazmak kodu iddia ediyorum. JVM çok akıllıdır ve bir şeyi profilinize kadar ne kadar hızlı veya yavaş olduğunu bilmezsiniz. Performans sorunları, sorun haline geldiğinde algılanabilir ve düzeltilebilir. Bunun için erken optimizasyon yapmamalısınız. Makinenin nasıl çalışacağını düşündüğünüz için değil, insanların okuması için kod yazın. Bir performans sorunu haline geldiğinde, bir profil oluşturucu ile kodu yeniden yazın.
Pirolistik

2
Başka biri kod biçimlendirmesini geliştirmek için cevabı düzenledi. Onay için birkaç düzine düzenlemeyi inceliyordum ve burada düzenlemelerini onaylayacaktım, ancak düzenlemeler tutarsızdı, bu yüzden onları düzelttim. Metin parçacıklarının dilbilgisini de geliştirdim.
Steve Vinoski

1
Anlamıyorum. Biçimlendirmenin önemli olmadığını söylediyseniz, neden yeniden değiştirmek için zaman harcadınız?
OrhanC1

0

Kotlin için aşağıdaki gibi uzantıları kullanabilirsiniz:

fun Double.toPrettyString() =
    if(this - this.toLong() == 0.0)
        String.format("%d", this.toLong())
    else
        String.format("%s",this)

0

İşte SADECE ondalık sıfır değilse, ondalık ekleme seçeneği olan başka bir yanıt .

   /**
     * 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
    }

-1

İşte gerçekten çalışan bir cevap (burada farklı cevapların kombinasyonu)

public static String removeTrailingZeros(double f)
{
    if(f == (int)f) {
        return String.format("%d", (int)f);
    }
    return String.format("%f", f).replaceAll("0*$", "");
}

1
POINT'in yerini değiştirmediniz, örneğin "100.0", "100" e dönüştürülecek.
VinceStyling

eğer (f == (int) f) bununla ilgilenir.
Martin Klosi

2
Başarısız oluyor f = 9999999999.00
Dawood ibn Kareem

-4

Bu gerçekten eski bir konu olduğunu biliyorum .. Ama bence bunu yapmanın en iyi yolu aşağıdaki gibidir:

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)));
    }
}

Çıktı:

3.456 something
3.456234523452 something
3.45 something
3.0 something

Tek sorun, .0'ın kaldırılmadığı son sorudur. Ancak bununla yaşayabiliyorsanız, bu en iyi sonucu verir. % .2f bunu son 2 ondalık basamağa yuvarlar. DecimalFormat da öyle. Tüm ondalık basamaklara ihtiyacınız varsa ancak sondaki sıfırlara ihtiyacınız yoksa, bu en iyi şekilde çalışır.


2
"#. ##" biçimine sahip DecimalFormat, gerekmediklerinde fazladan 0 System.out.println(new java.text.DecimalFormat("#.##").format(1.0005));1
tutmaz

benim açımdan bu. Varsa 0.0005'in görüntülenmesini isterseniz ne olur? 2 ondalık basamak yuvarlayacaksınız.
sethu

OP iki katına kaydedilen tam sayı değerlerinin nasıl yazdırılacağını soruyor :)
Aleks G

-8
String s = "1.210000";
while (s.endsWith("0")){
    s = (s.substring(0, s.length() - 1));
}

Bu, dizgiyi kuyruk 0-s'ını düşürecektir.


1
Bu, soruya iyi bir çözümdür, eğer sadece sıfırların düşmesi ile ilgileniyorlarsa, kodunuzu sondaki bir ondalık noktasını kesmek için nasıl değiştirirdiniz? yani "1."
bakoyaro

29
Dikkatli olun, çözümünüz 1000'i 1'e dönüştürür, bu da yanlıştır.
Aleks G
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.