简体   繁体   English

相同的计算,不同的结果?

[英]Same Calculation, different result?

My goal is to calculate how many percent counter out of cap is. 我的目标是计算有多少百分比counter出的cap是。 Now I ran over a problem, I can't find the difference between the two formulas below, as far as my mathematical understanding tells me, it's exactly the same calculation. 现在我遇到了一个问题,据我的数学理解告诉我,下面的两个公式之间的区别找不到,这是完全相同的计算。 But only the first one works, brackets make no difference. 但是只有第一个有效,括号没有区别。

int i = counter * 100 / cap; //works
int i = counter / cap * 100; //doesn't work

Has this got something to do with java or is it just me who's made a horrible thinking mistake? 这与java有关吗,或者只是我犯了一个可怕的思维错误?

It is not the same calculation, since you are handling integer arithmetics , which does not have Multiplicative inverse number for all numbers (only 1 has it). 这是不相同的计算,因为您正在处理整数算术 ,该算术不对所有数字都具有乘法逆数 (只有1具有)。

In integer arithmetics, for example, 1/2 == 0 , and not 0.5 - as it is in real numbers arithmetics. 例如,在整数算术中, 1/2 == 0 ,而不是在实数算术中的0.5 This will of course cause later on inconsistency when multiplying. 当然,这将在以后导致乘法时出现不一致。

As already mentioned - the root of this is the fact that integer arithmetics does not behave like real numbers arithmetics, and in particular, the divide operator is not defined as a/b == a*b^-1 , since b^-1 is not even defined in integer arithmetics to all numbers but 1. 如前所述-根本原因是整数算术的行为不像实数算术,尤其是除法运算符未定义为a/b == a*b^-1 ,因为b^-1甚至没有在整数算术中定义为所有数字,而是1。

Your mistake is assuming that these are just pure, abstract numbers. 您的错误是假设这些只是纯抽象数字。 I assume that counter is an int ... so the second version is evaluated as: 我认为counter是一个int ...,因此第二个版本的评估结果是:

int tmp = counter / cap;
int i = tmp * 100;

Now we're dealing with integer arithmetic here - so if counter is in the range [-99, 99] for example, tmp will be 0. 现在我们在这里处理整数算术 -例如,如果counter处于[-99,99]范围内,则tmp将为0。

Note that even your first version may not work, either - if counter is very large, multiplying it by 100 may overflow the bounds of int , leading to a negative result. 请注意,即使您的第一个版本也可能不起作用-如果counter很大,将其乘以100可能会溢出int的边界,从而导致结果为负。 Still, that's probably your best approach if counter is expected to be in a more reasonable range. 但是,如果预计counter在一个更合理的范围内,那可能是您最好的方法。

Even with floating point arithmetic, you still don't get the behaviour of "pure" numbers, of course - there are still limits both in terms of range and precision. 当然,即使使用浮点算术,您仍然不会获得“纯”数字的行为-在范围和精度方面仍然存在限制。

First case 第一种情况

int i = counter * 100 / cap;

is evaluated like 被评估为

(counter * 100) / cap;

The second case 第二种情况

int i = counter / cap * 100; 

is evluated like this 像这样

(counter / cap) * 100

Hence different results 因此结果不同

In Java, operators * and / have the same precedence, so the expressions are evaluated sequentially. 在Java中,运算符*和/具有相同的优先级,因此表达式是按顺序求值的。 Ie

  1. counter * 100 / cap --> (counter * 100) / cap 计数器* 100 /上限->(计数器* 100)/上限
  2. counter / cap * 100 --> (counter / cap) * 100 计数器/上限* 100->(计数器/上限)* 100

So for values eg counter = 5, cap = 25 (expecting count and cap to be both int variables), the evaluation is in the first case: 5 * 100 = 500, then 500 / 25 = 20 因此,对于例如counter = 5,cap = 25(期望count和cap均为int变量)的值,在第一种情况下计算为:5 * 100 = 500,则500/25 = 20

In the second case, the evaluation is: 5 / 25 = 0 (integer math!), then 0 * 100 = 0. 在第二种情况下,计算结果为:5/25 = 0(整数运算!),则0 * 100 = 0。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM