将强制转换应用于整数和浮点除法的结果:这里发生了什么?

时间:2011-08-04 23:41:24

标签: java floating-point

我是一个初学者,而且对我来说没有什么意义。请你能解释一下我哪里出错了。如果以前曾被问过,我很抱歉。

这里小数点的存在意味着使用浮点除法进行评估。

System.out.println(1/3.0); // this prints: 0.3333333333333333
System.out.println(1.0/3); // this prints: 0.3333333333333333
System.out.println(1.0/3.0); // this prints: 0.3333333333333333

显然,下面是"截断整数除法的一个例子。"对我来说似乎有点奇怪但是没问题。

System.out.println(1/3); // this prints: 0

可以说:"在下面一行中,(双)演员阵容被评估为第一名。它有效地说:"将1/3视为双重 - 不要使用截断整数除法。而是使用浮点除法。""

System.out.println((double)1/3); // this prints: 0.3333333333333333

下面,我们得到0.0 - 这是怎么发生的?

System.out.println((double)(1/3)); // this prints: 0.0

好吧也许额外的括号意味着(1/3)得到第一次评估。它是使用截断整数除法得到0来评估的。然后然后应用了双倍给我们0.0好有意义

好的,我们也许可以在这里提出几条一般规则:

规则1 :(双)表达意味着首先应用(双)强制转换,然后评估表达式。

规则2 :( double)(表达式)表示计算表达式然后应用强制转换。 太好了!

所以在下面的下一行我们有:(int)表达式,所以我想我们可以应用规则1)。 (int)演员表被评估为1st。它有效地说:"将1.0 / 3视为一个内存,而不是使用双倍的内存。不要使用浮点除法,而是应用截断整数除法。""所以我们0对吗?否。

System.out.println((int)1/3.0); // this prints: 0.3333333333333333

好的,所以我们有0.33333所以(int)演员表没有被评估为1st。就好像它不在那里。让我们提出第3条规则:

规则3:(int)表达式意味着忽略(int)强制转换只是评估表达式,就像(int)isn甚至那样。

确定将规则3应用到下面的行,我们有(int)但我们只是忽略它。使用浮点除法评估1.0 / 3.0,得到0.3333333。成功了!

System.out.println((int)1.0/3.0); // this prints: 0.3333333333333333

在下面的最后一行中,我们再次(int),但我们只是忽略它。 (1.0 / 3)使用浮点除法得到0.3333333333对吧?否。

System.out.println((int)(1.0/3)); // this prints: 0

好的,现在我很困惑。请你能帮助我解决这个问题吗?

4 个答案:

答案 0 :(得分:7)

Java的语言解析规则基本上暗示了代码中的大量括号,这些括号基于操作顺序的规则。了解Java认为括号的位置将有助于您了解此行为。当你说:

(double) 1 / 3.0

......这相当于说:

((double) 1) / 3.0

这意味着1会转换为double,而3.0会自动转换为double,因此您最终会执行浮点除法而不是整数除法。 (double) 1 / 3会发生同样的情况,因为除数是double,所以即使被除数是int,系统也会意识到你想要进行浮点除法。编译器不希望你失去精度,除非你特别要求,所以除非被分红或除数是double,它将进行double除法

另一方面:

(int) 1 / 3.0

......与说法相同:

((int) 1) / 3.0

在这种情况下,你告诉编译器它已经知道的东西:除数(1)是int。然后你要求它除以double值(3.0)。由于被除数是double,它将执行double除法。

正如您所指出的,1/3将产生零,因为这是整数除法的工作原理,两个数字都是整数。 1/(int)3.0会发生同样的情况,因为您告诉编译器在分割发生之前将3.0变为int(如1/((int)3.0))。

要记住的最后一点是(int) 0.33也会转换为0,因为整数不能包含十进制值。因此,当您说(int)(1.0/3)时,您正在进行double除法,但之后您将双倍转换为int,生成0

答案 1 :(得分:3)

这在Java Language Specification - Numeric Promotions

中指定
  

如果任何操作数是引用类型,则执行拆箱转换(第5.1.8节)。

     

然后:

     

如果任一操作数的类型为double,则另一个操作数转换为double。

     

否则,如果任一操作数的类型为float,则另一个操作数转换为float。

     

否则,如果任一操作数的类型为long,则另一个操作数转换为long。

     

否则,两个操作数都将转换为int类型。

这个概念叫做加宽转换:

  

5.1.2扩大原始转换

     

以下19种关于基本类型的特定转换称为扩展基元转换:

     
      
  • byte to short,int,long,float或double
  •   
  • 简称为int,long,float或double
  •   
  • char to int,long,float或double
  •   
  • int to long,float或double
  •   
  • 长期漂浮或加倍   浮动加倍
  •   

原因

(int) (1.0/3) == 0

是因为你将1.0 / 3的结果(上述规则为0.33333 ...)显式地转换为一个整数,相当于“floor(result)”(向下舍入),因此结果为0。 / p>

Cast的优先级高于/,这就是为什么其他操作误导您的理解:

(double) 1 / 3

将首先显式地将1转换为双值1.0,因此上述规则的结果再次等于0.3333 ....

答案 2 :(得分:2)

在所有这些案件中有两个因素:

  1. Operator precedence
  2. 当除法的一个参数是浮点数时,结果是一个浮点数。
  3. 我将从你的问题中给出三个例子:

    1. (double) (1/3) - 首先评估括号中的表达式 - (1/3)是整数除法,结果是0,然后将其转换为double,得到0.0
    2. (int) (1.0/3) - 首先评估括号中的表达式 - (1.0 / 3)是浮点除法,因此结果为0.3333,然后将其转换为int,得到{{1} }
    3. (double)1/3 - 首先执行转换,使0变为1.0,然后评估除法(double)1 - 这是浮点除法,因此结果为1.0/3

答案 3 :(得分:2)

演员表仅适用于紧接其后的表达 示例:

(int)1/3  
applies the cast to the 1. equivalent to ((int)1)/3

(int)(1/3)
the cast is applied to the result of the expression.

(int)((double)1.333*(float)3.167)
getting a little more complicated. 1.333 casted to double, 
multiplied by 3.167 casted to a float, with the result casted to an int

希望有所帮助!