Java中用于十进制数字的主要类型 /对象是float / Floatdouble / DoubleBigDecimal 。 在每种情况下,其“默认”字符串表示形式都是“计算机科学计数法”。 这篇文章演示了一些简单的方法,可以在没有科学符号的情况下提供十进制数的字符串表示形式。

本文中的示例将演示这些Java数值类型的“默认”科学表示法,其中每种类型的数字都使用一定范围的数字表示,这些数字表示了每种类型的“默认”表示法在何处变为科学表示法。 接下来的三个代码清单显示了用于构造floatdoubleBigDecimal的常规范围的代码。 这些示例的完整源代码清单可在GitHub上找到

构造浮点示例范围

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

构造双打的示例范围

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

构造BigDecimals的示例范围

/**
 * 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十进制类型的String表示形式。 接下来的三个输出列表中显示了每种数值类型以“默认”格式运行上述命令的输出。

非常小的和非常大的float的默认表示形式确实包括科学符号,用于显示最小的数字和显示最大的数字。 这些数字说明了Float.toString(Float)文档中讨论的内容:数字“小于10 -3或大于或等于10 7 ”以“所谓的“计算机科学表示法”表示。

==========================
= 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和非常大的double的默认表示形式确实包括对显示的最小数字和显示的最大数字的科学计数法。 这些数字说明了Javadoc文档中Double.toString(double)所讨论的内容 :数字“小于10 -3或大于或等于10 7 ”以“所谓的“计算机科学计数法”表示。

===========================
= 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

尽管floatdouble的最小和最大数字用科学计数法表示,但BigDecimal仅默认情况下对较小的数字执行此操作。 BigDecimal.toString()Javadoc文档中对此进行了描述:“如果小数位数大于或等于零,并且调整后的指数大于或等于-6,则数字将转换为字符形式而无需使用指数表示法。 …如果…调整后的指数小于-6,则数字将使用指数表示法转换为字符形式。”

===============================
= 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
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枚举的代码清单,该枚举演示了可以与floatdoubleBigDecimal使用的方法,而无需科学的表示法。

Format.java

/**
 * 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,以确保在不使用科学计数法的情况下呈现floatdouble 。 使用BigDecimaltoPlainString()方法甚至可以轻松完成此任务。

接下来显示使用Format.NO_EXPONENT运行代码的输出(并且看不到指数或科学符号)。

==============================
= 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类用科学计数法表示一些数字,但是很容易确保在不需要时不使用这种默认的科学计数法表示。

翻译自: https://www.javacodegeeks.com/2017/11/simple-string-representation-java-decimal-numbers-without-scientific-notation.html