我有一个类型为float
的变量x
,需要将其提高到某个幂次p
。如果x
是一个double
型变量,我可以使用Math.pow(x, p)
方法。但如果要计算x^p
并且结果仍然是float
类型,是否有可能呢?
我有一个类型为float
的变量x
,需要将其提高到某个幂次p
。如果x
是一个double
型变量,我可以使用Math.pow(x, p)
方法。但如果要计算x^p
并且结果仍然是float
类型,是否有可能呢?
pow
并转换为浮点数时,几乎总是会产生与计算单精度的 pow
相同的结果。要理解这一点,请考虑数学上准确的值 xp。如果采用四舍五入模式,将其正确地舍入为双精度数,然后再正确地舍入为浮点数,结果与直接舍入为浮点数相同,除非将值从一个舍入边界移动到另一个舍入边界。 Bit 23 24 25-52 53 54…
Original 1 0 11…11 1 anything
Rounded to double 1 1 00…00 0 0… (53 above midpoint: rounds up, carries to higher bits)
Then to float 0 0 00…00 0 0… (24 at midpoint, 23 is odd: rounds up, carries into bit 22, not shown)
Directly to float 1 0 00…00 0 0… (24 below midpoint: rounds down)
案例1:
Bit 23 24 25-52 53 54…
Original 0 1 00…00 0 anything except all zeroes
Rounded to double 0 1 00…00 0 0… (53 below midpoint: rounds down)
Then to float 0 0 00…00 0 0… (24 at midpoint, 23 is even: rounds down)
Directly to float 1 0 00…00 0 0… (24 above midpoint: rounds up)
情景2:
Bit 23 24 25-52 53 54…
Original 0 1 00…00 1 0…
Rounded to double 0 1 00…00 0 0… (53 at midpoint, 52 is even: rounds down)
Then to float 0 0 00…00 0 0… (24 at midpoint, 23 is even: rounds down)
Directly to float 1 0 00…00 0 0… (24 above midpoint: rounds up)
第0种情况需要31位具有特定值,因此在假设值有效均匀分布的情况下,它发生的概率是231中的一次。第1种情况与第0种情况相同,只是还需要在无限多个位中的任何位置出现一个一位,其概率有效为1。第2种情况要求无限多个位为零,因此其概率为零。至少在美学上,第1种和第2种情况是相互呼应的。
这些情况发生的综合概率为230中的1。
因此,将double
结果四舍五入为float
,产生与直接计算float
结果不同的情况很少见。
除此之外,大多数pow
实现都是不完美的。它们并不知道在所有情况下返回正确舍入的结果。(这很难实现。) 因此,您可能仍然会得到不完美的结果。将结果舍入为double
,然后再舍入为float
不会产生明显的差异。
public float power(final float base, final int power) {
float result = 1;
for( int i = 0; i < power; i++ ) {
result *= base;
}
return result;
}
编辑:一些额外的测试
正如评论中的人们所指出的,如果生成的浮点数太大而无法存储在浮点值中,这将返回错误。
以下是主要方法:
public static void main(final String[] args) {
System.out.println( power(Float.MAX_VALUE, 2));
}
Infinity
float ^ someX
总是会返回一个 float 吗? - Ravinder Reddydouble
参数的 pow()
的合理实现更糟糕。 - Pascal Cuoqresult*base
返回一个超过 float
可以表示的最大值的数字,那么这个方法将会导致溢出并返回虚假结果。 - BackSlash你仍然可以使用
Math.pow(x, p);
即使您没有明确地进行转换,您的浮点数x也将被转换为双精度。问题在于当您将返回值作为双精度并对其进行操作时会出现问题。
编辑: 如果需要一个返回浮点数的方法,您仍然可以使用Math.pow,然后包括从双精度转换回浮点数并包括自己的逻辑。
public float myPow(float x, float p) {
double dblResult = Math.pow(x, p);
float floatResult = (float)dblResult; // <-- Change to something safe. It may easily overflow.
return floatResult;
}
(float)dblResult
转换中溢出,它将导致 inf
,这就是如果存在 float
版本的 pow
将为相同的参数返回的东西。 - Pascal Cuoq
double
呢? - fge