如何计算溢出值的输出

时间:2019-05-09 18:47:04

标签: java integer-overflow

在采访中有人问我一个与整数溢出有关的问题。这个问题很简单,但是我找不到一个简单的方法来计算溢出值的结果。

例如,以下程序应将1000打印为输出,但由于Integer溢出其将打印5。

public class IntegerOvewflow {

    /**
     * Java does not have target typing, a language feature wherein the type of the
     * variable in which a result is to be stored influences the type of the
     * computation.
     * 
     * @param args
     */
    public static void main(String[] args) {
        final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000;
        final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;
        System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);

    }
}

但是,我们可以在这里使用任何特定的公式或方程式来计算溢出值的输出。这里的数字确实很大,用人的思维来快速判断输出结果并不容易。

3 个答案:

答案 0 :(得分:1)

指定它们与long一起L,因为如果不这样做,您将进行int乘法,这将导致int接触溢出,然后存储到long

public static void main(String[] args) {
    final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000L;
    final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000L;
    System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);   // 1000
}

签出:https://ideone.com/5vHjnH

答案 1 :(得分:1)

这是一本非常好的书《 Java Puzzlers Link to Book

中的经典问题。

谜题3:长除法 这个难题被称为“长除法”,因为它涉及到一个划分程序 两个long值。红利表示一天中的微秒数; 除数,一天中的毫秒数。该程序打印什么?

public class LongDivision {
public static void main(String[] args) {
final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000;
final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;
System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);
}

}

解决方案3:长期合作 这个难题似乎很简单。每毫秒的毫秒数 天和每天的微秒数是常数。 为了清楚起见,它们表示为产品。 每天的微秒数是(24小时/天·60 分钟/小时·60秒/分钟·1,000毫秒/秒·1,000微秒/毫秒。

每天的毫秒数的区别仅在于 缺少最终因子1,000。当您划分微秒数时 每天(以每天的毫秒数为单位),除数中的所有因子都将抵消 ,剩下的就是1,000,即每毫秒的微秒数。除数和除数都是长类型,这很容易大 足以容纳两种产品而不会溢出。

那么,该程序似乎 必须打印1000。不幸的是,它打印5。这到底是怎么回事? 问题是常量MICROS_PER_DAY的计算确实 溢出。尽管计算结果很长,但仍有余地, 它不适合int。计算完全以int算术执行, 并且只有在计算完成之后,结果才会提升到很长的时间。通过 然后,为时已晚:计算已经溢出,返回的值 太低了200倍。从int到long的提升是扩大的原始转换[JLS 5.1.2],该转换保留了(错误的)数值。这个 然后将值除以MILLIS_PER_DAY,该值已正确计算,因为 它确实适合int。该除法的结果是5。 那么为什么要用int算术执行计算呢?因为所有相乘的因子都是int值。当您将两个int值相乘时,您将获得另一个int值。 Java没有目标类型,一种语言 特征,其中要存储结果的变量的类型会影响 计算类型。 通过使用长文字代替int来修复程序很容易。 每个产品的首要因素。这迫使表达式中的所有后续计算都需要使用长算法。尽管仅在以下情况才需要这样做 MICROS_PER_DAY的表达式,这是在两种产品中都可以使用的好形式。同样,在产品中不一定总是使用long作为第一个值,但这是一个很好的形式。两种计算均以长值开头,这很清楚它们不会溢出。

该程序按预期打印1000:

public class LongDivision {
public static void main(String[] args) {
final long MICROS_PER_DAY = 24L * 60 * 60 * 1000 * 1000;
final long MILLIS_PER_DAY = 24L * 60 * 60 * 1000;
System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);
}
}

课程很简单:处理大量数字时,请注意 溢出-它是一个沉默的杀手。只是因为变量足够大,可以容纳 结果并不意味着得出结果的计算是正确的 类型。如有疑问,请使用长算法执行整个计算。 对于语言设计人员来说,应该减少静默溢出的可能性。这可以通过提供对算术的支持来完成 不会无声地溢出。程序可能引发异常,而不是 像Ada一样溢出,否则它们可能会切换到更大的内部表示形式 Lisp会自动按要求自动避免溢出。这两个 方法可能会与性能相关联。另一种方式 减少静默溢出的可能性是为了支持目标键入,但这增加了 类型系统的复杂性[Modula-3 1.4.8]。

答案 2 :(得分:0)

您可以将BigInteger类用于这些目的。

Oracle文档:here

link

中有一篇很好的快速文章