为什么将两个 int 除以双精度时不会得到正确的值?

为什么会出现在下面的片段中

int a = 7;
int b = 3;
double c = 0;
c = a / b;

c最终的值是2,而不是人们所期望的2.3333。如果 ab是双精度的,那么答案就是2.333。但是可以肯定的是,因为 c已经是一个双精度的,它应该已经与整数工作?

那为什么 int/int=double不起作用呢?

188034 次浏览

c是一个 double变量,但是分配给它的值是一个 int值,因为它是由两个 int除法得到的,这样就得到了“整数除法”(去掉余数)。所以在 c=a/b行发生的是

  1. 计算 a/b,创建类型为 int的临时值
  2. 在转换为 double类型之后,临时值被分配给 c

a/b的值是在不参考其上下文(赋值给 double)的情况下确定的。

这是因为您使用的是 operator/的整数除法版本,它接受2个 int并返回一个 int。为了使用返回 doubledouble版本,必须显式地将至少一个 int强制转换为 double

c = a/(double)b;

当你划分两个整数时,结果将是一个整数,而不管你把它存储在一个双精度数中。

/运算符可用于整数除法或浮点除法。你给它两个整数操作数,所以它进行整数除法,然后结果被存储在一个 double 中。

除了极少数例外(我只能想到一个) ,C + + 确定了 表达式(或子表达式)的全部意义 你怎么处理这个表达式的结果并不重要。 在您的例子中,表达式 a / b中没有 double 所以编译器使用整数除法。 只有得到结果之后,它才会考虑如何处理它,而且 转换成 double

从技术上讲,这是一个依赖于语言的问题,但是几乎所有的语言对待这个问题都是一样的。当表达式中的两个数据类型之间存在类型不匹配时,大多数语言都会尝试根据一组预定义的规则将数据强制转换到 =的一侧,以匹配另一侧的数据。

当把两个相同类型的数除以(整数、双精度数等)时,结果总是相同的类型(所以‘ int/int’总是会得到 int)。

在这种情况下,你有 double var = integer result 它将整数结果强制转换为双 在计算之后,在这种情况下,小数数据已经丢失。(大多数语言都会进行这种强制转换,以防止类型不准确而不引发异常或错误)。

如果你想保持结果是双精度的,你就要创造一种情况 double var = double result

最简单的方法是强制方程右边的表达式翻倍:

c = a/(double)b

整数和双精度数之间的除法将导致整数转换为双精度数(请注意,在进行数学运算时,编译器通常会“转换”为最具体的数据类型,这是为了防止数据丢失)。

抛出后,a将作为一个双打结束,现在你有除法之间的两个双打。这将创建所需的划分和分配。

再次强调,请注意这是特定于语言的(甚至可以是特定于编译器的) ,然而几乎所有的语言(当然是我能想到的所有语言)对待这个例子都是一样的。

这就是:

A)除两个 int总是执行整数除法。所以在你的例子中,a/b的结果只能是 int

如果你想保持 ab作为 int,然而完全分开他们,你必须铸造他们中的至少一个翻倍: (double)a/ba/(double)b(double)a/(double)b

B) c是一个 double,所以它可以 接受一个 int值的分配: int是自动转换为 double和分配到 c

C)记住,在赋值时,=右边的表达式是计算 第一(根据上面的(a)规则,不考虑 =左边的变量)和 那么(根据上面的(b))赋值给 =左边的变量。我相信这就是全部了。

在 C + + 语言中,子表达式的结果从不受周围上下文的影响(除了一些罕见的例外情况)。这是语言谨慎遵循的原则之一。表达式 c = a / b包含一个独立的子表达式 a / b,它的解释独立于该子表达式之外的任何内容。语言并不关心您稍后将结果分配给 doublea / b是一个整数除法。其他的都不重要。您将在语言规范的许多角落看到遵循这一原则。这就是 C + + (和 C)的工作原理。

我在上面提到的一个例外是在有函数指针函数重载的情况下的赋值/初始化

void foo(int);
void foo(double);


void (*p)(double) = &foo; // automatically selects `foo(fouble)`

在这种情况下,赋值/初始化的左侧会影响右侧的行为。(另外,引用到数组的初始化可以防止数组类型衰减,这是类似行为的另一个例子。)在所有其他情况下,右边完全忽略了左边。

重要的是计算的要素之一是浮点型。然后,为了得到一个双重结果,你需要对这个元素进行强制转换,如下所示:

c = static_cast<double>(a) / b;

或者 C = a/static _ cast (b) ;

或者你可以直接创建:

c = 7.0 / 3;

注意,计算元素之一必须有“ .0”才能表示 float-double 类型除以整数。否则,尽管 c 变量是双精度的,但结果也是零(一个整数)。

出于上述同样的原因,您必须将‘ a’或‘ b’之一转换为双重类型。另一种方法是使用:

double c = (a+0.0)/b;

分子被(隐式地)转换为双精度数,因为我们给它加了一个双精度数,即 0.0