在乘法中使用 Math.pow 时,是否需要将每个操作数转换为 long?

Do I need to cast each operand to long when using Math.pow in a multiplication?

提问人:Renaud Marmion 提问时间:10/13/2023 最后编辑:Mark RotteveelRenaud Marmion 更新时间:10/14/2023 访问量:84

问:

我在 Java 中有许多操作需要大量执行:

int b = [big number];
int c = [big number];
int d = [big number];
long a = (long) (Math.pow(b, 4) * Math.pow(c, 2) * d);

我敢肯定,这不会超过一个长。但是,可能会或可能超过 int 的大小。 我应该强制转换 的每个结果,还是 JVM 会自行处理整个操作的强制转换?aMath.pow(b, 4)Math.pow(c, 2)Math.pow

Java 强制转换 扩展

评论

1赞 Federico klez Culloca 10/13/2023
Math.pow(b, 4) * Math.pow(c, 2) * d将在上下文中执行这些乘法,因为第一个乘法在 S 之间,并将在第二个乘法中转换为 A。这里不涉及。doubledoubleddoubleint
0赞 M.P. Korstanje 10/13/2023
请注意,乘以大会产生近似值。如果您需要准确的结果,您应该将 和 to 分别偏移 2 和 1。在这种情况下,您将不得不在移位之前投射到很长时间。或者更好的是,使用 .doublebclongBigInteger
0赞 Arun Sudhakaran 10/13/2023
扩展(基元数据类型)和上转换(派生数据类型)会自动发生,因此,当您将层次结构中较低的类型分配给层次结构中较高的类型时,您不必手动指定该类型。
0赞 user207421 10/13/2023
您的标题与您的问题不一致。你不必在这里投射任何操作数,我实际上看不出投射结果的意义。
0赞 Renaud Marmion 10/14/2023
@user207421我需要将结果转换为 long,因为它是 Map 的键

答:

4赞 rzwitserloot 10/13/2023 #1

我敢肯定,“a”不会超过长头的大小。

这不是正确的边框值。

double是 64 位值。基础信息学理论证明,因此,一个双精度值最多可以表示 264 个唯一值。这很奇怪,因为 double 名义上说它可以代表“任何数字”,并且存在超过 264 个数字。

因此,在实践中,有一些(略小于 264)数字可以代表 double,任何其他值都会默默地四舍五入到最接近的这种“祝福”值。

举个简单的例子,0.1 不是这些值之一。因此,为什么会这样:

double v = 0.0;
for (int i = 0; i < 10; i++) v += 0.1;
System.out.println(1.0 == v);

实际上打印 false。建议双数学说 10 * 0.1 在某种程度上不是 1.0。这就是它的真正工作原理。

考虑到这一点,doubles 可以准确地表示每个整数值,最多 2^53。不是 2^64,这是多头可以代表的。因此,有些数字是多头可以表示的(例如 2^62-13),但双倍不能:

long x = (1L << 62) - 13;
System.out.println(x);
double v = x;
long y = (long) v;
System.out.println(y);

它们不会打印相同的数字。

我必须投射到多头吗?

是的。每次。

原因是一个相当不令人满意的“因为规范是这么说的”。上面的解释在某种程度上解释了为什么规范是这样说的:作为程序员,你需要表明你承认这里的准确性是有限的;如果这些数字超过 2^52,它就不太准确了。您可以通过转换为 long 来表示这一点。

评论

0赞 user207421 10/13/2023
'you indicate this by casting to 是什么意思?long
0赞 Renaud Marmion 10/14/2023
我不明白你为什么提到.我只使用 和 .doubleintlong
1赞 WJS 10/14/2023
@RenaudMarmion您隐式使用 since 将其参数转换为 double 并返回 double。在转换过程中,您可能会失去精度。doubleMath.pow()
0赞 rzwitserloot 10/14/2023
Math.pow仅存在 。通过使用,一切都变成了数学。您可以来回转换,但是,如果数字超过此值,则会导致舍入错误。doubleMath.powdouble2^52
0赞 Reilas 10/14/2023 #2

"...我应该强制转换 Math.pow 的每个结果,还是 JVM 会自行处理整个操作的强制转换?..."

只需使用 pow 方法返回的 double 值即可。
它将保存一个 int 值。

double a = Math.pow(b, 4) * (Math.pow(c, 2) * d);

实际上,如果值预计会超过 64 位容器,则应使用 BigDecimalBigInteger 类。

我推荐 String 构造函数方法。

BigInteger b = new BigInteger(""),
           c = new BigInteger(""),
           d = new BigInteger("");
BigInteger a = b.pow(4).multiply(c.pow(2).multiply(d));