确定可以保存字符串值的最小浮点类型

时间:2014-09-14 09:19:52

标签: java floating-point type-conversion

我正在研究一种将字符串转换为适当的Number类型的方法,具体取决于数字的格式。如果数字看起来是一个浮点值,那么我需要返回我可以使用的最小类型而不牺牲精度(FloatDoubleBigDecimal)。

基于How many significant digits have floats and doubles in java?(和其他资源),我已经学会了比Float值有23位的尾数。基于此,我使用以下方法返回给定值的位长度:

private static int getBitLengthOfSignificand(String integerPart,
    String fractionalPart) {
  return new BigInteger(integerPart + fractionalPart).bitLength();
}

如果此测试的结果低于24,我将返回Float。如果低于53,我会返回Double,否则返回BigDecimal

但是,当我考虑Float.MAX_VALUE 3.4028235E38时,我对结果感到困惑。根据我的方法(有integerPart = 3fractionalPart = 4028235,有效数字的位长是26。这会触发我的方法返回Double,当Float显然就足够了。< / p>

有人可以突出我的思考或实施中的缺陷吗?我的另一个想法是将字符串转换为BigDecimal并使用floatValue()doubleValue()缩小,测试溢出(由无限值表示)。但这会失去精确度,因此对我来说并不合适。

2 个答案:

答案 0 :(得分:1)

有效数据以二进制形式存储,只有当你不让它混淆时,你才可以把它想象成十进制表示中的数字。

指数是二进制指数,它不代表乘以10的幂乘以2的幂。因此,您使用的数字中的E38只是一个便利:真正的有效数字是二进制的,应该乘以2的幂来获得实际数字。两个权力和十个权力并不相同,因此“3.4028235”不是真正的意义。 Float.MAX_VALUE的实际有效位数为十六进制表示法,0x1.fffffe,其关联指数为127,表示Float.MAX_VALUE实际为0x1.fffffe * 2 127

查看十进制表示以选择二进制浮点类型来放置值,正如您尝试的那样,并不起作用。首先,一个肯定从float恢复的十进制数字的数量不同于为了区分float与其邻居(6和9)而需要写入的十进制数字的数量。分别)。您选择编写“3.4028235E38”但您可以编写3.40282E38,对于您的算法,它看起来更容易表示,当它不是真的时候。当人们写道“3.4028235E38”是float类型的最大有限值时,它们意味着如果你将这个十进制数舍入到float,你将到达最大的浮点数。如果您将“3.4028235E38”解析为双精度数字,它甚至不会等于Float.MAX_VALUE

换句话说:另一种写Float.MAX_VALUE的方式是3.4028234663852885981170418348451692544E38。它仍然可以表示为float(它表示与3.4028235E38完全相同的值)。看起来它有很多位数,因为它们是小数出现的十进制数字,实际上这个数字在内部用二进制指数表示。

(顺便说一下,你的方法不会检查指数是否在范围内来表示所选类型中的数字,这是一种类型能够表示字符串中数字的另一个条件。)

答案 1 :(得分:0)

我会根据实际值与最近的float之间的差异来工作。 BigDecimal可以精确地存储任何有限长度的小数部分并对其进行算术运算:

String转换为最近的float x。如果x是无限的,但该值具有有限double表示,请使用该表达式。

String完全转换为BigDecimal y

如果y为零,请使用float,它可以完全代表零。

如果没有,请将float x转换为BigDecimalz

BigDecimal中计算合理的小数位数,(y-z)/z的绝对值。这是由于使用float导致的相对舍入误差。如果它足够小,您选择的值少于某个值,请使用float。如果没有,请使用double

如果你真的不想牺牲精确度,那就简单多了。转换为floatdouble。比较他们的平等。比较将在double中完成。如果他们比较相等,请使用float。如果没有,请使用double