Int除法:为啥1/3 == 0的结果?
Posted
技术标签:
【中文标题】Int除法:为啥1/3 == 0的结果?【英文标题】:Int division: Why is the result of 1/3 == 0?Int除法:为什么1/3 == 0的结果? 【发布时间】:2021-11-17 19:16:24 【问题描述】:我正在编写这段代码:
public static void main(String[] args)
double g = 1 / 3;
System.out.printf("%.2f", g);
结果为0。这是为什么,我该如何解决这个问题?
【问题讨论】:
【参考方案1】:两个操作数(1 和 3)是整数,因此使用整数算术(这里是除法)。将结果变量声明为 double 只会导致在除法之后发生隐式转换。
整数除法当然会返回四舍五入到零的除法结果。 0.333...
的结果因此在此处向下舍入为 0。 (请注意,处理器实际上并没有进行任何舍入,但您仍然可以这样想。)
另外,请注意,如果 两个 操作数(数字)都以浮点数形式给出; 3.0 和 1.0,或者甚至只是 first,然后使用浮点运算,给你0.333...
。
【讨论】:
+1 并且它总是向下取整。int i = .99999999
将 int 设置为 0。更具体地说,它采用整数部分并丢弃其余部分。
它“向零”舍入,对于大于零的值,“向下”。 (+0.9 舍入为 0,-0.9 也舍入为 0。)
@Byron:是的,没错。我不相信处理器实际上会进行任何舍入,因为除法的实现方式非常不同,但这样想很方便。
不,不是四舍五入:Truncation
@BasilBourque 在 Java 术语中,rounding DOWN
接近于零。舍入 FLOOR
是向负无穷大。【参考方案2】:
1/3
使用整数除法,因为两边都是整数。
您至少需要其中一个为float
或double
。
如果您像您的问题一样在源代码中输入值,您可以这样做 1.0/3
; 1.0
是双精度的。
如果您从其他地方获取值,您可以使用(double)
将int
转换为double
。
int x = ...;
int y = ...;
double value = ((double) x) / y;
【讨论】:
【参考方案3】:将其显式转换为double
double g = 1.0/3.0
这是因为 Java 对 1
和 3
使用整数除法运算,因为您将它们作为整数常量输入。
【讨论】:
【参考方案4】:你应该使用
double g=1.0/3;
或
double g=1/3.0;
整数除法返回整数。
【讨论】:
【参考方案5】:因为你在做整数除法。
正如@Noldorin 所说,如果两个运算符都是整数,则使用整数除法。
结果 0.33333333 不能表示为整数,因此仅将整数部分 (0) 分配给结果。
如果任何运算符是double
/ float
,则将进行浮点运算。但是如果你这样做,你会遇到同样的问题:
int n = 1.0 / 3.0;
【讨论】:
【参考方案6】:最简单的解决方案就是这样做
double g = (double) 1 / 3;
由于您没有输入 1.0 / 3.0,因此您可以手动将其转换为数据类型 double,因为 Java 假定它是整数除法,即使这意味着缩小转换范围,它也会这样做。这就是所谓的强制转换运算符。 这里我们只转换一个操作数,这足以避免整数除法(向零舍入)
【讨论】:
【参考方案7】:结果为0。这是为什么,我该如何解决这个问题?
TL;DR
您可以通过以下方式解决它:
double g = 1.0/3.0;
或
double g = 1.0/3;
或
double g = 1/3.0;
或
double g = (double) 1 / 3;
当您使用变量时,这些选项中的最后一个是必需的,例如int a = 1, b = 3; double g = (double) a / b;
.
更完整的答案
双倍 g = 1 / 3;
这导致0
,因为
int
类型,因此导致int
(5.6.2. JLS) 自然不能表示浮点值,例如0.333333..
。
“整数除法向 0 舍入。” 15.17.2 JLS
为什么double g = 1.0/3.0;
和double g = ((double) 1) / 3;
有效?
来自Chapter 5. Conversions and Promotions 可以阅读:
一个转换上下文是数字运算符的操作数,例如 + 要么 *。这种操作数的转换过程称为数字 晋升。促销的特殊之处在于,在二进制的情况下 运算符,为一个操作数选择的转换可能部分取决于 另一个操作数表达式的类型。
和5.6.2. Binary Numeric Promotion
当一个运算符将二进制数字提升应用于一对 操作数,每个操作数必须表示一个可转换为 数字类型,按顺序适用以下规则:
如果任何操作数是引用类型,则对其进行拆箱 转换(第 5.1.8 节)。
加宽基元转换(第 5.1.2 节)用于转换或 两个操作数均由以下规则指定:
如果任一操作数是 double 类型,则另一个将转换为 double。
否则,如果任一操作数为浮点类型,则转换另一个 浮动。
否则,如果任一操作数是 long 类型,则转换另一个 长。
否则,两个操作数都转换为 int 类型。
【讨论】:
【参考方案8】:因为它把 1 和 3 当作整数,所以将结果向下舍入到 0,所以它是一个整数。
要获得您正在寻找的结果,请明确告诉 java 数字是双精度数,如下所示:
double g = 1.0/3.0;
【讨论】:
【参考方案9】:将 1 设为浮点数,将使用浮点除法
public static void main(String d[])
double g=1f/3;
System.out.printf("%.2f",g);
【讨论】:
【参考方案10】:JAVA 中的转换很简单,但需要一些了解。正如 integer operations 的 JLS 中所述:
如果除移位运算符以外的整数运算符至少有一个 long 类型的操作数,则使用 64 位精度进行运算,数值运算符的结果为 long 类型。如果另一个操作数不长,则首先将其扩展(第 5.1.5 节)以通过数字提升(第 5.6 节)键入 long。
而示例总是翻译 JLS 的最佳方式;)
int + long -> long
int(1) + long(2) + int(3) -> long(1+2) + long(3)
否则使用32位精度进行运算,数值运算符的结果为int类型。如果任一操作数不是 int,则首先通过数字提升将其扩展为 int 类型。
short + int -> int + int -> int
一个使用 Eclipse 的小例子表明即使添加两个 short
s 也不是那么容易:
short s = 1;
s = s + s; <- Compiling error
//possible loss of precision
// required: short
// found: int
这将需要一个可能会损失精度的铸件。
floating point operators 也是如此
如果数值运算符的至少一个操作数是 double 类型,则使用 64 位浮点算术执行运算,数值运算符的结果是 double 类型的值。如果另一个操作数不是双精度,则首先将其扩展(第 5.1.5 节)以通过数字提升(第 5.6 节)键入双精度。
所以提升是在 float 到 double 上完成的。
并且整数和浮点值的混合导致浮动值,如所述
如果二元运算符的至少一个操作数是浮点类型,则该运算是浮点运算,即使另一个是整数。
这适用于二元运算符,但不适用于像 +=
这样的“赋值运算符”
一个简单的工作示例就足以证明这一点
int i = 1;
i += 1.5f;
原因是这里做了一个隐式转换,这将像执行一样
i = (int) i + 1.5f
i = (int) 2.5f
i = 2
【讨论】:
【参考方案11】:1 和 3 是整数常量,因此 Java 会进行整数除法,结果为 0。如果要编写双精度常量,则必须编写 1.0
和 3.0
。
【讨论】:
【参考方案12】:我这样做了。
double g = 1.0/3.0;
System.out.printf("%gf", g);
在进行双重计算时使用 .0,否则 Java 会假定您使用的是整数。如果计算使用任意数量的双精度值,则输出将是双精度值。如果都是整数,则输出将是整数。
【讨论】:
【参考方案13】:(1/3) 表示整数除法,这就是为什么你不能从这个除法中得到十进制值的原因。要解决此问题,请使用:
public static void main(String[] args)
double g = 1.0 / 3;
System.out.printf("%.2f", g);
【讨论】:
【参考方案14】:public static void main(String[] args)
double g = 1 / 3;
System.out.printf("%.2f", g);
由于 1 和 3 都是整数,因此结果不会四舍五入,但会被截断。所以你忽略分数而只取整数。
为避免这种情况,请至少将数字 1 或 3 之一作为十进制形式 1.0 和/或 3.0。
【讨论】:
【参考方案15】:试试这个:
public static void main(String[] args)
double a = 1.0;
double b = 3.0;
double g = a / b;
System.out.printf(""+ g);
【讨论】:
请不要发布仅代码的答案,包括说明您的代码的作用以及它如何(以及为什么)解决问题的问题。还要考虑到这是一个已有 8 年历史的问题,它有现有的赞成答案,以及您的答案是否比现有答案增加了任何价值。【参考方案16】:执行“双 g=1.0/3.0;”而是。
【讨论】:
只是好奇......这个答案有什么问题?当我第一次遇到问题时,我使用了这种方法。对此解决方案有什么问题的解释将不胜感激。提前致谢。 @Mr.PortStJoe 它没有向提出问题的人提供任何详细信息。查看评分最高的答案,我们可以看到他们也解释了为什么会发生这种情况。虽然答案在技术上可能是正确的,但它的用处可能被视为有限。【参考方案17】:许多其他人未能指出真正的问题:
仅对整数的运算将运算结果转换为整数。
这必然意味着可以显示为整数的浮点结果将被截断(去掉小数部分)。
你问什么是casting(类型转换/类型转换)?
它因语言的实现而异,但 Wikipedia 有一个相当全面的观点,它也谈到了强制,这是回答您问题的关键信息。
http://en.wikipedia.org/wiki/Type_conversion
【讨论】:
这个答案有缺陷。在像1/2
这样的全整数定义中不涉及类型转换或类型转换,而不是在目标语言 (java) 中。您只需调用一个整数除法,这将产生一个整数结果。类型转换只是因为在分配期间从int
向上转换为double
。
@YoYo 你是说 0.5 是一个整数?我不这么认为,伙计。
这个兄弟没有说任何关于0.5
的事情。简单地说,在 Java 中,1/2
是一个整数除法,它产生一个零整数。您可以将零分配给双精度,它仍然是零,尽管是 0.0
双精度。以上是关于Int除法:为啥1/3 == 0的结果?的主要内容,如果未能解决你的问题,请参考以下文章