Frage

Ich schreibe eine Anwendung, die zur Ausgabe von Dezimalzahlen unterschiedlicher Länge benötigt, und unterschiedliches Maß in Strings ohne Dezimalpunkt zu einem anderen System auf eine flache Datei als Eingabe zu schreiben. z.

 12345  -> Length:10, Scale:2              -> 0001234500
 123.45 -> Length:10, Scale:2              -> 0000012345
 123.45 -> Length:10, Scale:3              -> 0000123450
-123.45 -> Length:10, Scale:3, signed:true -> -000123450
 123.45 -> Length:10, Scale:3, signed:true -> +000123450

Die Funktion, die ich geschrieben habe, zu handhaben dies unten und werde mir Hunderttausende Male aufgerufen werden, so will ich sicherstellen, dass es nicht eine bessere, effizientere Art und Weise, dies zu tun. Ich habe nach Wegen gesucht, erhalten DecimalFormat für mich, mehr zu tun, aber ich kann es nicht sehen, mein Bedürfnis Umgang mit Dezimalstellen zu formatieren, aber ohne Komma.

protected String getFormattedDecimal( String value, int len, int scale, Boolean signed ) throws Exception{
    StringBuffer retVal = new StringBuffer();

    //Need a BigDecimal to facilitiate correct formatting
    BigDecimal bd = new BigDecimal( value );

    //set the scale to ensure that the correct number of zeroes 
    //at the end in case of rounding
    bd = bd.setScale( scale );

    //taking it that if its supposed to have negative it'll be part of the num
    if ( ( bd.compareTo( BigDecimal.ZERO ) >= 0 ) && signed ){
        retVal.append( "+" );
    }           

    StringBuffer sbFormat = new StringBuffer();
    for (int i = 0; i < len; i++)
    {
        sbFormat.append('0');
    }

    DecimalFormat df = new DecimalFormat( sbFormat.toString() );

    retVal.append( df.format( bd.unscaledValue() ) );

    return retVal.toString();
}
War es hilfreich?

Lösung

Meine leistungsgesteigerte Implementierung ist unten. Es ist etwa 4,5-mal so schnell wie die DecimalFormatter-basierte Lösung: auf meinem Rechner läuft, mit Eclipse mit einem anständigen hausgebrauten Testgeschirr, sind die Ergebnisse:

  • Alte Art und Weise nahm 5421 ms 600.000 Anrufe (durchschnittliche 0,009035 ms pro Anruf) zu machen
  • Neue Art und Weise nahm 1219 ms 600.000 Anrufe (durchschnittliche 0,002032 ms pro Anruf) zu machen

Hier einige Hinweise:

  • Meine Lösung nutzt einen Block fester Größe von Nullen für die Polsterung. Wenn Sie auf beiden Seiten als die dreißig mehr Polsterung benötigen antizipieren oder so habe ich, dann würden Sie die Größe erhöhen müssen ... klar könnte man es dynamisch erhöhen, falls erforderlich.
  • Ihre Kommentare oben nicht ganz den Code übereinstimmen. Insbesondere wurde, wenn ein Zeichen Zeichen zurückgegeben, die zurückgegebene Länge ist um eins größer als die angeforderte (Ihre Kommentare sagen etwas anderes). Ich habe gewählt, um den Code, anstatt die Kommentare zu glauben.
  • Ich habe meine Methode statisch, da sie keine Instanz Zustand erfordert. Das ist eine persönliche Geschmackssache - ymmv.

Sie auch: um das Verhalten des Originals (aber nicht in den Kommentaren angegeben) zu imitieren, diese:

  • Wenn mehr Nachkommastellen im eingehenden Wert als fit im Maßstab sind, wirft eine ArithmeticException Wenn es mehr ganze Zahlen in den eingehenden Wert als fit in (LEN-Skala) sind, ist die zurückgegebene Zeichenfolge länger als len. Wenn unterzeichnet wahr ist, wird der zurückgegebene String eine länger als len

    • aber : if len negativ ist, die ursprüngliche kehrt eine kommagetrennte Zeichenfolge. Dies löst eine Illegal
    package com.pragmaticsoftwaredevelopment.stackoverflow;
    ...
       final static String formatterZeroes="00000000000000000000000000000000000000000000000000000000000";
       protected static String getFormattedDecimal ( String value, int len, int scale, Boolean signed ) throws IllegalArgumentException {
           if (value.length() == 0) throw new IllegalArgumentException ("Cannot format a zero-length value");
           if (len <= 0) throw new IllegalArgumentException ("Illegal length (" + len + ")");
           StringBuffer retVal = new StringBuffer();
           String sign=null;
           int numStartIdx; 
           if ("+-".indexOf(value.charAt(0)) < 0) {
              numStartIdx=0;
           } else {
              numStartIdx=1;
              if (value.charAt(0) == '-')
                 sign = "-";
           }
           if (signed && (value.charAt(0) != '-'))
              sign = "+";
           if (sign==null)
              sign="";
           retVal.append(sign);
    
    
           int dotIdx = value.indexOf('.');
           int requestedWholePartLength = (len-scale);
    
           if (dotIdx < 0) { 
              int wholePartPadLength = (requestedWholePartLength - ((value.length()-numStartIdx)));
              if (wholePartPadLength > 0)
                 retVal.append(formatterZeroes.substring(0, wholePartPadLength));
              retVal.append (value.substring(numStartIdx));
              if (scale > 0)
                 retVal.append(formatterZeroes.substring(0, scale));
           }
           else {
              int wholePartPadLength = (requestedWholePartLength - (dotIdx - numStartIdx));
              if (wholePartPadLength > 0)
                 retVal.append(formatterZeroes.substring(0, wholePartPadLength));
              retVal.append (value.substring(numStartIdx, dotIdx));
              retVal.append (value.substring (dotIdx+1));
              int fractionalPartPadLength = (scale - (value.length() - 1 - dotIdx));
              if (fractionalPartPadLength > 0)
                 retVal.append(formatterZeroes.substring(0, fractionalPartPadLength));
    
    
           }
    
           return retVal.toString();
       }
    
        
  • Andere Tipps

    Wenn Sie Ihre Eingabe als String bekommen zu beginnen, warum müssen Sie es BigDecimal konvertieren und zurück?

    Scheint, wie es viel schneller sein würde, die Position des Dezimalpunkts zu finden, zu vergleichen, dass auf Länge / Skala und Pad die Zeichenfolge entsprechend.

    Ich stimme mit ChssPly76 WRT manuellen String-Manipulation.

    Wenn Sie jedoch die BigDecimal / DecimalFormat Weg gehen wollen, möchten Sie vielleicht Ihre DecimalFormats statt der Schaffung eines neuen mit jeder Iteration betrachten zu teilen. Beachten Sie, dass diese Klassen sind nicht Thread-sicher, so dass, wenn Sie mehrere Threads verwenden, um Ihre Verarbeitung zu tun, werden Sie wollen so etwas wie ThreadLocal Speicher verwenden, um eine Formatierer pro Thread aufrecht zu erhalten.

    btw, haben Sie diese getestet und die Leistung nicht akzeptabel oder suchen Sie nur für die effizienteste Lösung möglich? Beachten Sie, was Donald Knuth sagt über das Thema der frühen Optimierung .

    Lizenziert unter: CC-BY-SA mit Zuschreibung
    Nicht verbunden mit StackOverflow
    scroll top