Java中计算两个long的百分比的溢出安全方法
我有两个非负长。它们可能很大,接近Long.MAX_值。我想从这两个数字中计算一个百分比 通常我会这样做:Java中计算两个long的百分比的溢出安全方法,java,Java,我有两个非负长。它们可能很大,接近Long.MAX_值。我想从这两个数字中计算一个百分比 通常我会这样做: long numerator = Long.MAX_VALUE / 3 * 2; long denominator = Long.MAX_VALUE; int percentage = (int) (numerator * 100 / denominator); System.out.println("percentage = " + percentage
long numerator = Long.MAX_VALUE / 3 * 2;
long denominator = Long.MAX_VALUE;
int percentage = (int) (numerator * 100 / denominator);
System.out.println("percentage = " + percentage);
如果分子在Long.MAX_值的两个数量级范围内,则这是不正确的
正确、简单、快速的方法是什么
int percentage = (int) (0.5d + ((double)numerator/(double)denominator) * 100);
如果将
long
与long
相除,将得到long
,这对百分比不好。简单的方法是在进行计算之前将两者都转换为float
或double
,但会略微降低精度。与其他选择相比,它也很慢
一种方法是将每个值分成两个32位的分量,然后进行长乘法和长除法。我会使用:
int percentage = (int)(numerator * 100.0 / denominator + 0.5);
100.0
强制浮点数学从该点开始,并且+0.5
舍入到最接近的整数,而不是截断。除非我遗漏了一些明显的东西,否则你就不能写:
public class round {
public static void main(String[] argv) {
long numerator = Long.MAX_VALUE / 3 * 2;
long denominator = Long.MAX_VALUE;
int percentage = (int) (numerator / (denominator / 100));
System.out.println("percentage = " + percentage);
}
}
相反?也就是说,在除法之前,不要使分子变大,而要使分母变小。因为你知道分母是大的,所以除法不会给出0,这就是你不使用浮点数时通常写
(n*100)/d
的原因。大家按照下面的方式实现,因为建议用BigDecimal和biginger进行计算。以下是实施:
BigDecimal n = new BigDecimal(Long.MAX_VALUE);
BigDecimal d = new BigDecimal(Long.MAX_VALUE);
BigDecimal i = new BigDecimal(100);
int percentage = n.multiply(i).divide(d).intValue();
System.out.println(percentage);
为什么结尾的“+0.5”?我想这是为了更好的四舍五入…但是99.6将会是100,也许不是这样good@SteveMcLeod:是的,这与舍入有关(参见更新的答案)。我认为舍入到最接近的值是一个合理的默认值。@SteveMcLeod:当然,如果用例要求截断而不是舍入到最接近的值,那么可以安全地删除
+0.5
@SteveMcLeod-我认为这对于有整数并且知道它们很大的情况是正确的。通常的写作方式是为了应付小的情况而设计的。