Java中用于十进制数字的主要类型 /对象是float
/ Float , double
/ Double和BigDecimal 。 在每种情况下,其“默认”字符串表示形式都是“计算机科学计数法”。 这篇文章演示了一些简单的方法,可以在没有科学符号的情况下提供十进制数的字符串表示形式。
本文中的示例将演示这些Java数值类型的“默认”科学表示法,其中每种类型的数字都使用一定范围的数字表示,这些数字表示了每种类型的“默认”表示法在何处变为科学表示法。 接下来的三个代码清单显示了用于构造float
, double
和BigDecimal
的常规范围的代码。 这些示例的完整源代码清单可在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
尽管float
和double
的最小和最大数字用科学计数法表示,但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
枚举的代码清单,该枚举演示了可以与float
, double
和BigDecimal
使用的方法,而无需科学的表示法。
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,以确保在不使用科学计数法的情况下呈现float
和double
。 使用BigDecimal的toPlainString()方法甚至可以轻松完成此任务。
接下来显示使用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
类用科学计数法表示一些数字,但是很容易确保在不需要时不使用这种默认的科学计数法表示。