将小数格式化为字符串以提高性能

Mad*_*urf 5 java formatting performance decimal

我正在编写一个应用程序,需要输出不同长度的十进制数,并将不同的比例缩放到没有小数点的字符串,以便将平面文件写入另一个系统的输入.例如

 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
Run Code Online (Sandbox Code Playgroud)

我编写的用于处理此功能的功能在下面,并且将被称为数十万次,因此我想确保没有更好,更有效的方法来执行此操作.我已经看过让DecimalFormat为我做更多事情的方法,但我看不到它处理我需要用小数位格式化但没有小数点.

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();
}
Run Code Online (Sandbox Code Playgroud)

CPe*_*ins 8

我的性能增强实现如下.它的速度是基于DecimalFormatter的解决方案的4.5倍:在我的机器上运行,使用带有体面的自制测试工具的Eclipse,结果如下:

  • 旧方式需要5421毫秒才能拨打600,000个电话(平均每次通话0.009035毫秒)
  • 新方式需要1219毫秒才能拨打600,000个电话(平均每次通话0.002032毫秒)

一些说明:

  • 我的解决方案使用固定大小的零块进行填充.如果你预计任何一侧都需要更多填充,那么你必须增加尺寸......显然你可以根据需要动态增加它.
  • 您上面的评论与代码不太匹配.具体来说,如果返回了一个符号字符,则返回的长度比请求的长一个(您的注释另有说明).我选择相信代码而不是评论.
  • 我使我的方法静态,因为它不需要实例状态.这是个人品味的东西 - ymmv.

另外:为了模仿原文的行为(但在评论中没有给出),这个:

  • 如果输入值中的小数位数多于比例中的小数位数,则抛出ArithmeticException如果输入值中的整数位数多于(len-scale),则返回的字符串长于len.如果signed为true,则返回的字符串将比len长

    • 但是:如果len为负数,则原始返回逗号分隔的字符串.这会抛出IllegalARgumentException
    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();
       }
    
    Run Code Online (Sandbox Code Playgroud)