Самый быстрый способ подать число на Java до определенного количества цифр

StackOverflow https://stackoverflow.com/questions/2989663

Вопрос

Я пытаюсь создать хорошо оптимизированный код для создания количества x-цифр длиной (где x считывается из файла свойств времени выполнения), на основе номера последовательности, сгенерированного DB (Y), который затем используется папкой -Поллект при сохранении файла.

Я придумал три идеи до сих пор, самая быстрая из которых является последней, но я бы признателен за любые советы, которые люди могут иметь по этому поводу ...

1) создайте экземпляр StringBuilder с начальной емкостью X. Приложение Y. В то время как длина <x, вставьте ноль при POS Zero.

2) создайте создание строк -повестка с начальной емкостью X. В то время как длина <x, добавьте ноль. Создайте DecimalFormat на основе значения StringBuilder, а затем отформатируйте число, когда оно необходимо.

3) Создайте новый int of Math.pow (10, x) и добавьте Y. Используйте string.valueof () на новом номере, а затем подстрою (1) IT.

Второй, очевидно, может быть разделен на участки внешней петли и внутренней петли.

Итак, какие -нибудь советы? Используя петлю из 10000 итераций, я получаю аналогичные времена от первых двух, а третий метод примерно в десять раз быстрее. Это кажется правильным?

Полный код тестирования-метода ниже ...

    // Setup test variables
    int numDigits = 9;
    int testNumber = 724;
    int numIterations = 10000;
    String folderHolder = null;
    DecimalFormat outputFormat = new DecimalFormat( "#,##0" );

    // StringBuilder test
    long before = System.nanoTime();
    for ( int i = 0; i < numIterations; i++ )
    {
        StringBuilder sb = new StringBuilder( numDigits );
        sb.append( testNumber );
        while ( sb.length() < numDigits )
        {
            sb.insert( 0, 0 );
        }

        folderHolder = sb.toString();
    }
    long after = System.nanoTime();
    System.out.println( "01: " + outputFormat.format( after - before ) + " nanoseconds" );
    System.out.println( "Sanity check: Folder = \"" + folderHolder + "\"" );

    // DecimalFormat test
    before = System.nanoTime();
    StringBuilder sb = new StringBuilder( numDigits );
    while ( sb.length() < numDigits )
    {
        sb.append( 0 );
    }
    DecimalFormat formatter = new DecimalFormat( sb.toString() );
    for ( int i = 0; i < numIterations; i++ )
    {
        folderHolder = formatter.format( testNumber );
    }
    after = System.nanoTime();
    System.out.println( "02: " + outputFormat.format( after - before ) + " nanoseconds" );
    System.out.println( "Sanity check: Folder = \"" + folderHolder + "\"" );

    // Substring test
    before = System.nanoTime();
    int baseNum = (int)Math.pow( 10, numDigits );
    for ( int i = 0; i < numIterations; i++ )
    {
        int newNum = baseNum + testNumber;
        folderHolder = String.valueOf( newNum ).substring( 1 );
    }
    after = System.nanoTime();
    System.out.println( "03: " + outputFormat.format( after - before ) + " nanoseconds" );
    System.out.println( "Sanity check: Folder = \"" + folderHolder + "\"" );
Это было полезно?

Решение

Я бы перестал делать оптимизацию на основе микро-распаковки и пойти на что-то, что выглядит элегантно, например, как String.format("%0"+numDigits+"d", testNumber)

Другие советы

Используйте string.format ("%0 [длина] D", i)

Для длины 8 это было бы

String out = String.format("%08d", i);

Это медленнее, но время, потраченное на набор и отладку, более сложный код, вероятно, превысит общее дополнительное время, когда -либо используемое во время выполнения.

На самом деле, если вы добавляете все часы, которые уже потратили на обсуждение этого, это, скорее всего, превышает экономию времени исполнения по большим фактором.

Вставка символов на прокладки один за другим, очевидно, медленно. Если производительность действительно очень большая, вы можете использовать предопределенные строковые константы Ленгтов 1..N-1 (где не является самой большой ожидаемой длиной), хранится в массиве в соответствующих индексах.

Если не очень большой, по крайней мере, вы все еще можете вставить в большие куски вместо одиночных карт.

Но в целом, как отмечали другие, оптимизация возможна только в том случае, если вы профилировали свое приложение при реальных обстоятельствах и обнаружили, какой конкретный кусок кода является узким местом. Затем вы можете сосредоточиться на этом (и, конечно, снова профиль, чтобы убедиться, что ваши изменения на самом деле улучшают производительность).

Вот решение, которое в основном то же самое, что и ваш StringBuilder с двумя оптимизациями:

  1. Он прямо пишет на массив, обходящего накладные расходы StringBuilder
  2. Он выполняет операции в обратном направлении вместо вставки (0), которая каждый раз переворачивает арамеркопию

Это также делает предположения, что Numdigits будет> = для фактических символов, необходимых, но правильно обрабатывает отрицательные числа:

before = System.nanoTime();
String arrString=null;
for ( int j = 0; j < numIterations; j++ ){
  char[] arrNum = new char[numDigits];
  int i = numDigits-1;
  boolean neg = testNumber<0;
  for(int tmp = neg?-testNumber:testNumber;tmp>0;tmp/=10){
    arrNum[i--] = (char)((tmp%10)+48);
  }
  while(i>=0){
    arrNum[i--]='0';
  }
  if(neg)arrNum[0]='-';
  arrString = new String(arrNum);
}
after = System.nanoTime();
System.out.println( "04: " + outputFormat.format( after - before ) + " nanoseconds" );
System.out.println( "Sanity check: Folder = \"" + arrString + "\"" );

Этот метод хорошо превзошел ваши образцы на моей машине для негативов и был сопоставим для положительных результатов:

01: 18,090,933 nanoseconds
Sanity check: Folder = "000000742"
02: 22,659,205 nanoseconds
Sanity check: Folder = "000000742"
03: 2,309,949 nanoseconds
Sanity check: Folder = "000000742"
04: 6,380,892 nanoseconds
Sanity check: Folder = "000000742"

01: 14,933,369 nanoseconds
Sanity check: Folder = "0000-2745"
02: 21,685,158 nanoseconds
Sanity check: Folder = "-000002745"
03: 3,213,270 nanoseconds
Sanity check: Folder = "99997255"
04: 1,255,660 nanoseconds
Sanity check: Folder = "-00002745"

Редактировать: Я заметил, что ваши тесты вызвали некоторые из объектов в цикле итерации, которые я не делал в моем (например, не пересчитывая базон в подстроении). Когда я изменил тесты, чтобы быть последовательными (не разрешая никаких объектов / расчетов, моя версия выполнялась лучше, чем ваша:

01: 18,377,935 nanoseconds
Sanity check: Folder = "000000742"
02: 69,443,911 nanoseconds
Sanity check: Folder = "000000742"
03: 6,410,263 nanoseconds
Sanity check: Folder = "000000742"
04: 996,622 nanoseconds
Sanity check: Folder = "000000742"

Конечно, поскольку другие упоминали, что микро -бензин невероятно сложный / «пугающий» со всей оптимизацией, выполненной виртуальной машиной и неспособностью контролировать их.

Это, вероятно, связано Link обсуждает многие из способов сделать это. Я бы порекомендовал опцию Apache, StringUtils, он может быть или не быть самым быстрым, но обычно это один из самых простых, чтобы понять, и из него избил) & ##@, так что он, вероятно, не сломается в каком -то непредвиденном крае. ;)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top