【问题标题】:Why does dividing two int not yield the right value when assigned to double?为什么将两个 int 分配给 double 时不会产生正确的值?
【发布时间】:2011-11-26 03:29:30
【问题描述】:

怎么会出现在下面的sn-p中

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

c 最终的值为 2,而不是预期的 2.3333。如果 ab 是双精度数,那么答案确实会变成 2.333。但肯定是因为c 已经是一个双精度数,所以它应该适用于整数?

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

【问题讨论】:

标签: c++ variables double integer-division


【解决方案1】:

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

c = a/(double)b;

【讨论】:

  • 为了清楚起见,我更愿意将ab 显式转换为double,但这并不重要。
  • 由于问题被标记为 C++,我更愿意看到 static_cast 而不是 C 转换。
  • 个人感觉C风格的转换更加清晰(其他大部分常用语言的转换都是C风格的)。 static_cast<> 对我来说总是很啰嗦。在原语的情况下,将static_cast<>reinterpret_cast<> 混淆并没有任何危险。
  • @Tux-D:算术转换?在这种情况下,我宁愿避免使用static_cast,而是使用 C 风格的强制转换。在这里使用 C++ 风格的强制转换没有任何好处,而且它们比 C 风格的强制转换更混乱代码。算术强制转换正是 C 风格强制转换非常合适并且实际上比其他强制转换更合适的上下文。
  • 有时你可以通过写double(b) 来智取那些“没有 C 风格的演员”的人。他们并不总是意识到这是一种转换,因为它看起来与显式构造函数调用相同。
【解决方案2】:

这里是:

a) 除以两个ints 总是执行整数除法。所以a/b的结果在你的情况下只能是int

如果您想将ab 保留为ints,但仍将它们完全分开,则必须将其中至少一个转换为两倍:(double)a/ba/(double)b(double)a/(double)b

b) c 是一个double,所以它可以接受一个int 赋值:int 自动转换为double 并赋值给c .

c) 请记住,在赋值时,= 右侧的表达式被计算首先(根据上面的规则 (a),并且不考虑 @987654337 左侧的变量@) 和 then 分配给= 左侧的变量(根据上面的(b))。我相信这完成了画面。

【讨论】:

    【解决方案3】:

    除了极少数例外(我只能想到一个),C++ 决定了 表达式(或子表达式)的全部含义 本身。你对表达式的结果做什么并不重要。 在您的情况下,在表达式a / b 中,没有double 视线;一切都是int。所以编译器使用整数除法。 只有得到结果后,它才会考虑如何处理它,并且 将其转换为double

    【讨论】:

    • 我能想到的一个例外是在获取指针时选择函数重载 - &funcname 的值取决于您将其转换为什么类型。
    • @Steve Jessop 这也是我能想到的唯一例外。 (但考虑到标准的规模和复杂性,我不想发誓我没有错过任何一个。)
    【解决方案4】:

    当您将两个整数相除时,结果将是一个整数,而不管您将它存储在一个双精度数中。

    【讨论】:

      【解决方案5】:

      c 是一个double 变量,但分配给它的值是一个int 值,因为它是两个ints 相除的结果,这给了你“整数除法”(删除余数)。那么c=a/b 行中发生的事情是

      1. a/b 被评估,创建一个临时的int 类型
      2. 临时值在转换为double类型后赋值给c

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

      【讨论】:

        【解决方案6】:

        在 C++ 语言中,子表达式的结果永远不会受到周围上下文的影响(有一些罕见的例外)。这是该语言仔细遵循的原则之一。表达式c = a / b 包含一个独立的子表达式a / b,它独立于该子表达式之外的任何内容进行解释。该语言并不关心您稍后会将结果分配给doublea / b 是整数除法。别的什么都无所谓。您将在语言规范的许多方面看到这一原则。这就是 C++(和 C)的工作原理。

        我上面提到的一个异常示例是函数重载情况下的函数指针分配/初始化

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

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

        【讨论】:

          【解决方案7】:

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

          【讨论】:

            【解决方案8】:

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

            当两个相同类型的数字(整数、双精度等)相除时,结果将始终是相同类型(因此 'int/int' 将始终导致 int)。

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

            如果您想将结果保持为双精度,您将需要创建一个您拥有的情况 double var = double result

            最简单的方法是强制等式右边的表达式转换为双精度:

            c = a/(double)b

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

            在向上转换之后,a 最终会成为一个双精度数,现在您可以在两个双精度数之间进行划分。这将创建所需的划分和分配。

            再次,请注意,这是特定于语言的(甚至可以是特定于编译器的),但是几乎所有语言(当然是我能想到的所有语言)都会处理这个示例相同。

            【讨论】:

            • 这个问题被标记为 [C++],C++ 标准明确规定了它是如何工作的。不确定您所说的“特定于语言”是什么意思,它肯定不是特定于编译器的,假设没有使用编译器扩展。
            • 另外说“double var = integer result which cast the double var down to int”也不正确。 double 不会转换为 int。 int 结果被转换为双精度值。
            • 我允许编译器扩展的可能性(实际上我曾经遇到过这个问题,我的环境“错误转换”了结果,但我不知道为什么)。结果是特定于语言的,因为在某些语言中不遵循相同的转换规则。我不认为它是 C++ 特定的标签。您对“double var = integer result”的评论是正确的。编辑以反映这一点。谢谢!
            【解决方案9】:

            出于与上述相同的原因,您必须将 'a' 或 'b' 之一转换为双精度类型。另一种方法是使用:

            double c = (a+0.0)/b;
            

            分子被(隐式)转换为双精度数,因为我们向其添加了双精度数,即 0.0

            【讨论】:

              【解决方案10】:

              重要的是计算元素之一是float-double类型。然后要获得双重结果,您需要转换此元素,如下所示:

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

              或 c = a / static_cast(b);

              也可以直接创建::

              c = 7.0 / 3;
              

              请注意,计算元素之一必须具有“.0”以指示浮点双精度类型除以整数。否则,尽管 c 变量是双精度的,但结果也将为零(整数)。

              【讨论】:

              • 你的答案带来了什么,其他 9 个答案都没有出现?
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2019-10-04
              • 2022-01-26
              • 1970-01-01
              • 1970-01-01
              • 2013-10-15
              • 2020-03-16
              相关资源
              最近更新 更多