Статьи

Простое строковое представление десятичных чисел Java без научной нотации

Основными типами / объектами, используемыми для десятичных чисел в Java, являются float / Float , double / Double и BigDecimal . У каждого из них есть случаи, когда его строковое представление «по умолчанию» — «компьютеризированная научная запись». Этот пост демонстрирует несколько простых подходов для обеспечения строкового представления десятичного числа в этих случаях без научной записи.

Примеры в этом посте продемонстрируют научную нотацию «по умолчанию» Строковые представления этих числовых типов Java с использованием диапазона чисел для каждого типа, которые приблизительно показывают, где представление «по умолчанию» для каждого типа становится научной нотацией. Следующие три листинга кода показывают код для построения общих диапазонов для float с float , double с и BigDecimal s. Полный список исходного кода для этих примеров доступен на GitHub .

Построение примера диапазона поплавков

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
 * Writes floats in the provided format and in the
 * provided range to standard output.
 *
 * @param start Float to start writing.
 * @param threshold Float past which to not write anymore.
 * @param delta Delta for each increment of floats to be written.
 * @param label Label for header.
 * @param format Format for print out.
 */
private static void writeFloatsToOutput(
   final float start,
   final float threshold,
   final float delta,
   final String label,
   final Format format)
{
   out.println(generateHeader(label));
   float floatValue = start;
   do
   {
      out.println("= " + format.fromFloat(floatValue));
      floatValue += delta;
   }
   while (floatValue < threshold);
}

Построение примера диапазона двойников

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
 * Writes doubles in the provided format and in the
 * provided range to standard output.
 *
 * @param start Double to start writing.
 * @param threshold Double past which to not write anymore.
 * @param delta Delta for each increment of doubles to be written.
 * @param label Label for header.
 * @param format Format for print out.
 */
private static void writeDoublesToOutput(
   final double start,
   final double threshold,
   final double delta,
   final String label,
   final Format format)
{
   out.println(generateHeader(label));
   double doubleValue = start;
   do
   {
      out.println("= " + format.fromDouble(doubleValue));
      doubleValue += delta;
   }
   while (doubleValue < threshold);
}

Построение примера диапазона больших чисел

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
 * Writes BigDecimals in the provided format and in the
 * provided range to standard output.
 *
 * @param start BigDecimal to start writing.
 * @param threshold BigDecimal past which to not write anymore.
 * @param delta Delta for each increment of BigDecimals to be written.
 * @param label Label for header.
 * @param format Format for print out.
 */
private static void writeBigDecimalsToOutput(
   final BigDecimal start,
   final BigDecimal threshold,
   final BigDecimal delta,
   final String label,
   final Format format)
{
   out.println(generateHeader(label));
   BigDecimal decimal = start;
   do
   {
      out.println("= " + format.fromBigDecimal(decimal));
      decimal = decimal.add(delta);
   }
   while (decimal.compareTo(threshold) < 0);
}

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

Представление по умолчанию очень маленьких и очень больших чисел с float действительно включает научную запись для самых маленьких показанных чисел и для самых больших показанных чисел. Эти числа демонстрируют то, что обсуждается в документации Float.toString (Float) : числа «меньше 10 -3 или больше или равно 10 7 » «представлены в так называемой« компьютеризированной научной нотации ».

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
==========================
= Small Floats (DEFAULT) =
==========================
= 8.5E-4
= 9.5E-4
= 0.00105
= 0.0011499999
= 0.0012499999
= 0.0013499998
= 0.0014499997
= 0.0015499997
= 0.0016499996
= 0.0017499996
= 0.0018499995
= 0.0019499995
==========================
= Large Floats (DEFAULT) =
==========================
= 9999995.0
= 9999996.0
= 9999997.0
= 9999998.0
= 9999999.0
= 1.0E7
= 1.0000001E7
= 1.0000002E7
= 1.0000003E7
= 1.0000004E7

Представление по умолчанию очень маленьких и очень больших double s включает научную запись для наименьших показанных чисел и для наибольших показанных чисел. Эти числа демонстрируют то, что обсуждается в документации Javadoc для Double.toString (double) : числа «меньше 10 -3 или больше или равно 10 7 » «представлены в так называемой« компьютеризированной научной нотации ».

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
===========================
= Small Doubles (DEFAULT) =
===========================
= 8.5E-4
= 9.5E-4
= 0.00105
= 0.00115
= 0.00125
= 0.00135
= 0.0014500000000000001
= 0.0015500000000000002
= 0.0016500000000000002
= 0.0017500000000000003
= 0.0018500000000000003
= 0.0019500000000000003
===========================
= Large Doubles (DEFAULT) =
===========================
= 9999995.0
= 9999996.0
= 9999997.0
= 9999998.0
= 9999999.0
= 1.0E7
= 1.0000001E7
= 1.0000002E7
= 1.0000003E7
= 1.0000004E7

В то время как float и double имели наименьшее и наибольшее числа, выраженные в научных обозначениях, BigDecimal делает это по умолчанию только для меньших чисел. Это описано в документации Javadoc BigDecimal.toString () : «Если масштаб больше или равен нулю, а скорректированный показатель больше или равен -6, число будет преобразовано в символьную форму без использования экспоненциальной нотации , … Если… скорректированный показатель меньше -6, число будет преобразовано в символьную форму с использованием экспоненциальной записи ».

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
===============================
= Small BigDecimals (DEFAULT) =
===============================
= 8.5E-7
= 9.5E-7
= 0.00000105
= 0.00000115
= 0.00000125
= 0.00000135
= 0.00000145
= 0.00000155
= 0.00000165
= 0.00000175
= 0.00000185
= 0.00000195
===============================
= Large BigDecimals (DEFAULT) =
===============================
= 99999950000000000000000000000000000000000000000000
= 99999960000000000000000000000000000000000000000000
= 99999970000000000000000000000000000000000000000000
= 99999980000000000000000000000000000000000000000000
= 99999990000000000000000000000000000000000000000000
= 100000000000000000000000000000000000000000000000000
= 100000010000000000000000000000000000000000000000000
= 100000020000000000000000000000000000000000000000000
= 100000030000000000000000000000000000000000000000000
= 100000040000000000000000000000000000000000000000000
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private static void writeFormattedValues(final Format format)
{
   writeFloatsToOutput(
      0.00085f, 0.002f, 0.0001f, "Small Floats (" + format + ")", format);
   writeFloatsToOutput(
      9_999_995f, 10_000_005f, 1f, "Large Floats (" + format + ")", format);
 
   writeDoublesToOutput(
      0.00085d, 0.002d, 0.0001d, "Small Doubles (" + format + ")", format);
   writeDoublesToOutput(
      9_999_995d, 10_000_005d, 1d, "Large Doubles (" + format + ")", format);
 
   writeBigDecimalsToOutput(
      new BigDecimal("0.00000085"),
      new BigDecimal("0.000002"),
      new BigDecimal("0.0000001"),
      "Small BigDecimals (" + format + ")",
      format);
   writeBigDecimalsToOutput(
      new BigDecimal("99999950000000000000000000000000000000000000000000"),
      new BigDecimal("100000050000000000000000000000000000000000000000000"),
      new BigDecimal("10000000000000000000000000000000000000000000"),
      "Large BigDecimals (" + format + ")",
      format);
}

Представление очень маленьких и очень больших чисел в приведенном выше коде может быть представлено в формате по умолчанию или в формате, исключающем использование научной нотации. Далее приведен список кода для перечисления Format и это перечисление демонстрирует подходы, которые можно использовать с float , double и BigDecimal для их рендеринга без научной нотации.

Format.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/**
 * Supports rendering of Java numeric types float, double,
 * and BigDecimal in "default" format and in format that
 * avoids use of scientific notation.
 */
public enum Format
{
   DEFAULT
   {
      @Override
      public String fromFloat(final float floatValue)
      {
         return String.valueOf(floatValue);
      }
      @Override
      public String fromDouble(final double doubleValue)
      {
         return String.valueOf(doubleValue);
      }
      @Override
      public String fromBigDecimal(final BigDecimal bigDecimalValue)
      {
         return bigDecimalValue.toString();
      }
   },
   NO_EXPONENT
   {
      @Override
      public String fromFloat(final float floatValue)
      {
         return numberFormat.format(floatValue);
      }
      @Override
      public String fromDouble(final double doubleValue)
      {
         return numberFormat.format(doubleValue);
      }
      @Override
      public String fromBigDecimal(final BigDecimal bigDecimalValue)
      {
         return bigDecimalValue.toPlainString();
      }
   };
 
   private static final NumberFormat numberFormat = NumberFormat.getInstance();
 
   static
   {
      numberFormat.setMaximumFractionDigits(Integer.MAX_VALUE);
      numberFormat.setGroupingUsed(false);
   }
 
   public abstract String fromFloat(final float floatValue);
   public abstract String fromDouble(final double doubleValue);
   public abstract String fromBigDecimal(final BigDecimal bigDecimalValue);
}

Перечисление Format использует экземпляр NumberFormat с отключенной группировкой и с максимальными цифрами дроби, установленными в Integer.MAX_VALUE, чтобы гарантировать, что числа с float и double отображаются без научной записи. Это даже проще сделать с помощью BigDecimal, используя метод toPlainString () .

Результат выполнения кода с Format.NO_EXPONENT показан далее (и в нем нет показателей или научных обозначений).

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
==============================
= Small Floats (NO_EXPONENT) =
==============================
= 0.0008500000112690032
= 0.0009500000160187483
= 0.0010499999625608325
= 0.0011499999091029167
= 0.001249999855645001
= 0.0013499998021870852
= 0.0014499997487291694
= 0.0015499996952712536
= 0.0016499996418133378
= 0.001749999588355422
= 0.0018499995348975062
= 0.0019499994814395905
==============================
= Large Floats (NO_EXPONENT) =
==============================
= 9999995
= 9999996
= 9999997
= 9999998
= 9999999
= 10000000
= 10000001
= 10000002
= 10000003
= 10000004
===============================
= Small Doubles (NO_EXPONENT) =
===============================
= 0.00085
= 0.00095
= 0.00105
= 0.00115
= 0.00125
= 0.00135
= 0.0014500000000000001
= 0.0015500000000000002
= 0.0016500000000000002
= 0.0017500000000000003
= 0.0018500000000000003
= 0.0019500000000000003
===============================
= Large Doubles (NO_EXPONENT) =
===============================
= 9999995
= 9999996
= 9999997
= 9999998
= 9999999
= 10000000
= 10000001
= 10000002
= 10000003
= 10000004
===================================
= Small BigDecimals (NO_EXPONENT) =
===================================
= 0.00000085
= 0.00000095
= 0.00000105
= 0.00000115
= 0.00000125
= 0.00000135
= 0.00000145
= 0.00000155
= 0.00000165
= 0.00000175
= 0.00000185
= 0.00000195
===================================
= Large BigDecimals (NO_EXPONENT) =
===================================
= 99999950000000000000000000000000000000000000000000
= 99999960000000000000000000000000000000000000000000
= 99999970000000000000000000000000000000000000000000
= 99999980000000000000000000000000000000000000000000
= 99999990000000000000000000000000000000000000000000
= 100000000000000000000000000000000000000000000000000
= 100000010000000000000000000000000000000000000000000
= 100000020000000000000000000000000000000000000000000
= 100000030000000000000000000000000000000000000000000
= 100000040000000000000000000000000000000000000000000

Стандартные плавающие типы Java и класс BigDecimal отображают некоторые числа в научной нотации, но легко гарантировать, что эта презентация научной нотации по умолчанию не используется, когда она нежелательна.

Опубликовано на Java Code Geeks с разрешения Дастина Маркса, партнера нашей программы JCG . См. Оригинальную статью здесь: Простое строковое представление десятичных чисел Java без научной нотации

Мнения, высказанные участниками Java Code Geeks, являются их собственными.