【问题标题】:Finding average of two numbers using only ints仅使用整数求两个数字的平均值
【发布时间】:2016-08-25 18:10:36
【问题描述】:

我需要仅使用 int 作为数据类型来查找两个数字的平均值。我不能使用公式 (x1+x2)/2 = mean,因为如果数字足够大,这会导致溢出。

我找到了这个公式

int mid = low + ((high - low) / 2);

来自这个帖子Explanation of the safe average of two numbers

但是,当涉及负数时,此公式不起作用。有没有人对如何解决这个问题有任何想法?谢谢

编辑 - Java

【问题讨论】:

  • 这是什么语言?
  • Java,并不认为它太重要,但我想我可以看到它会如何改变事情。更新帖子
  • 为什么不能用long?
  • @edtheprogrammerguy 这是一个朋友提出的我解决不了的游戏,他特别说只允许整数

标签: java int overflow


【解决方案1】:

你说你不能使用μ=(x+y)/2 的形式,但这基本上是唯一有意义的计算方法。你确实提出了一个关于溢出的好观点,但只需要一些非常基本的代数就可以解决这个问题。还记得分配属性吗?

μ = (x + y) / 2 = x/2 + y/2

在相加之前将两个整数除以 2,可以降低溢出的风险。尝试将两个值都设置为Integer.MAX_VALUE(尽管先阅读整篇文章)。所以……

int avg(int x, int y) {
    return x/2 + y/2;
}

...应该为你做。请记住,您只使用ints?当涉及到奇数时,你会担心一些精度问题......例如,如果你这样做 avg(1, 1),你会得到 0 的结果。我会留下来解决这个小问题你,但这应该会让你走上正确的道路。

【讨论】:

  • 我认为解决舍入问题的解决方案类似于if (temp1 % 2 != 0 && temp2 % 2 != 0) { avg += 1; }
  • @frillybob 这当然是一种方法,至少对于两个数字。
  • @nusukkin 这种方式实际上并不总是有效。这两个数字产生一个数字与我上面的逻辑-1073741823, 1073741824预期为0,实际上是1
  • @frillybob 你怎么能接受这么多用例结果完全错误的答案?像 avg(1,1) =0 你怎么能相信这种随机方法的结果?
  • @nasukkin 隐藏它“似乎是一个家庭作业问题”对我来说听起来太容易了,提出一个功能齐全的解决方案,然后你会发现在这种方法背后你有很多极端案例封面,这使得它太容易出错了。
【解决方案2】:

这应该适用于负值和正值,因为在这种情况下符号位不会移动:

// Convert the add operation as long to prevent overflow in case you use big
// integers
long total = (long) low + (long) high;
// Convert the mid value back to an int
int mid = (int) (total >> 1);

注意:当且仅当 lowhigh 都是 int 时才有效,根据您的问题,这里似乎就是这种情况。

【讨论】:

  • 由于溢出导致非常大和非常小的整数失败。 >> 1 等价于/2,所以提出的问题仍然有效。尝试使用等于 Integer.MAX_VALUEInteger.MIN_VALUE 的两个值。
  • @nasukkin 好的,我明白了,请再检查一次
  • 这可能是最好的答案... 如果原始问题中“仅使用 int 作为数据类型”的规定允许使用 long在中间。但是,如果使用 long 是可以接受的,则位移是不必要的,并且可能应该用 / 2 替换以提高代码可读性。实际上,如果允许在中间计算中使用 int 以外的数据类型,那么使用浮点数据类型(例如 BigDecimal)可能会更好。这将解决小数精度的一些问题。
  • @nasukkin 在问题中明确提到预期类型是 int
  • @nasukkin 答案现在有效,因此请删除您的反对票,因为您的原始评论不再有效
【解决方案3】:

这样的东西应该可以工作

private int findAverage(int lower, int higher) {
    int lowerCopy = lower;
    int higherCopy = higher;
    boolean averageFound = false;
    while (!averageFound) {
        lowerCopy++;
        higherCopy--;
        averageFound = isAverageFound(lowerCopy, higherCopy);
    }
    return getAverage(lowerCopy, higherCopy);
}

isAverageFound 将通过检查值是否彼此相等或彼此远离来实现。

这应该适用于所有数字范围,无论是正数还是负数

【讨论】:

  • 考虑对于非常大的负数和非常大的正数,while 循环需要的迭代次数。
  • 例如,对于 -100100,while 循环将迭代 100 次。现在想象一下Integer.MINInteger.MAX 的迭代次数。
【解决方案4】:
private void findAverage(int lower, int higher) {
    int lowerCopy = lower;
    int higherCopy = higher;
    int cnt = 1;
    boolean averageFound = false;
    while (!averageFound) {
        lowerCopy++;
        higherCopy--;
        ++cnt;
        averageFound = isAverageFound(lowerCopy, higherCopy);
    }
}


private boolean isAverageFound(int l, int h){
  if(l < h)
     return false;
   else if(l == h){
     System.out.print("average:" + l);
     return true;
   }else{
     System.out.print("average:" + (h/2));  
     return true;       
   }
}

是的。它被留下来改变。对于大的负数和大的正数范围,它会起作用。但是,我同意这需要 O(high + low) 时间。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-21
    • 2017-03-03
    • 1970-01-01
    • 2012-10-01
    • 2014-07-19
    • 2022-11-19
    • 2013-10-07
    相关资源
    最近更新 更多