【问题标题】:Why a double multiplies a float returns a double in C++ (VS) [closed]为什么双倍乘以浮点数在 C++(VS)中返回双精度 [关闭]
【发布时间】:2016-07-02 06:55:28
【问题描述】:

编辑(第三次): 回应到目前为止的答案,让我澄清一点:

  • @Lưu Vĩnh Phúc 正如他敏锐地指出的那样,在我原来的表达中,

算术运算的精度由精度决定 不太精确的操作数。

我应该使用准确度而不是精确度。即

算术运算的准确性由准确性决定 不太准确的操作数。

是的,我不小心使用了精确度而不是准确度,并在我的许多论点中继续使用它。我为我的愚蠢错误和相应的困惑道歉。

所以问题被重述:

例如:

auto test=100. *3.f;

那么,变量test是double类型的。

我对这个选择感到困惑。因为从数学上讲,算术运算的准确性是由不太准确的操作数的准确性决定的。在我们的例子中,3.f 在最多 8 位之后已经无法保证其准确性,将 test 存储为具有 15 位精度的可能误导印象的双精度有什么意义?

我的猜测是它可能与指数有关,但在这种情况下,结果是 300,它不会超出浮点数的范围。还是有什么历史原因?

非常感谢,


我再次为我的愚蠢道歉。


总结到目前为止的答案: 1,是的,它是关于范围的; 2、当double*float->double时,有很多截断。

【问题讨论】:

  • 那不是VS的东西,甚至不是C++的东西,每种编程语言都是这样的。
  • 三、二、一……的标准引述
  • ...zero: "...否则,如果任一操作数为双精度,则另一个应转换为双精度..."
  • 您的编辑没有比您原来的问题更有意义。 1.1 * 1.5 的结果是 1.65,原因在我的回答中给出。 1.5 * 1.2 = 1.80,出于同样的原因。
  • 在任何基数中,n 位和 m 位数字的乘积是 (n+m) 位数字,因此即使 int*int -> int 产生的位数是它可以拥有的位数的两倍。将结果存储在比原始类型更窄的类型中更糟糕。 double*float->double 需要大量截断,将结果存储在 float 中没有意义

标签: floating-point precision


【解决方案1】:

在两种类型之间执行操作时,C++ 将返回精度最高的值。这可以防止在缩小转换时发生溢出和其他奇怪的事情。

例如,float 最多可容纳 ~3.4×1038,而 double 最多可容纳 ~1.8×10308。如果你将3.0f 的浮点数乘以1e100 的双倍,你会想要得到大约3e100 的结果,不是吗?另一方面,如果您将其转换为 float,您将得到 inf

您可能会争辩说它应该能够分辨,但是编译器如何在编译时知道结果是否适合 float 或者是否需要 double

还值得记住的是,所有float 值都可以转换为double 而不会损失精度,但相反的情况(显然)不正确。

总结:这是计算机科学,而不是数学。

【讨论】:

  • 是的,这就是我的猜测。我认为这与指数有关。但我只是想仔细检查一下我错过的计算机科学方面是否有什么特别之处。感谢您的帮助。
  • 关于独角兽系统的常见免责声明适用,但 +1。
【解决方案2】:

从数学上讲,算术运算的精度是由不太精确的操作数的精度决定的。

不,不是。从数学上讲,乘法的精度定义为操作数精度的乘积。例如考虑1 * 1.5。结果是 1.5,而不是 1。

【讨论】:

  • 我认为这是您的误解。当您说结果是 1.5 时,您隐含地假设您的 1 比 1 位具有更高的精度。想想看,如果你的 1 有 1 的精度,它可能是 1.1、1.2 等等。你的答案是什么?因此,您隐含地假设精度比您想象的要高。
  • @FlowingCloud 别傻了。如果我错了,答案是一个,而不是。误会是你的。除法还有另一条规则,加法和减法也有。如果您想反事实地保持正确答案是 1,而不是 1.5,则需要说明原因。这是四年级的算术。当我写 1 时,我的意思是 1,而不是 1.1、1.2、...
  • 再次,这是您的误解。当你使用这个 1*1.5 时,你是在使用它的数学含义:即 1 正好是 1,它具有无限精度。
  • @FlowingCloud 文字 1 正好是 1
  • @Flowing Cloud 你的论点自相矛盾。 1 是 1。它不需要任何目的的无限精度。如果我将它用作具有无限精度,按照我自己的逻辑,我将不得不断言正确的答案是 1.5000000000000000000000000000000... 到无限个小数位。我已经实现了 COBOL 编译器算法,这些是您使用的规则。
【解决方案3】:

根据The C++ Programming Language (4th Edition)

§10.3.1:算术运算符的结果类型由一组称为“常规算术转换”的规则确定(§10.5.3)。总体目标是产生“最大”操作数类型的结果。

我相信这样做是为了不丢失存储在更大类型中的任何数据。

§10.5.3:这些转换是在二元运算符的操作数上执行的,以将它们转换为公共类型,然后将其用作结果的类型:

  1. 如果任一操作数的类型为 long double,则另一个将转换为 long double。
    • 否则,如果任一操作数为双精度,则将另一个转换为双精度。
    • 否则,如果任一操作数为浮点数,则将另一个转换为浮点数。
    • 否则,将对两个操作数执行整数提升 (§10.5.1)。
  2. 否则,如果任一操作数为 unsigned long long,则另一个将转换为 unsigned long long。
    • 否则,如果一个操作数是 long long int 而另一个是 unsigned long int,则如果 long long int 可以表示 unsigned long int 的所有值,则 unsigned long int 将转换为 long long int ;否则,两个操作数都将转换为 unsigned long long int。否则,如果任一操作数为 unsigned long long,则另一个将转换为 unsigned long long。
    • 否则,如果一个操作数是long int,另一个是unsigned int,那么如果long int 可以表示unsigned int 的所有值,则unsigned int 将转换为long int;否则,两个操作数都将转换为 unsigned long int。
    • 否则,如果任一操作数为 long,则将另一个转换为 long。
    • 否则,如果任一操作数是无符号的,则将另一个转换为无符号。
    • 否则,两个操作数都是整数。

这些规则使得将无符号整数转换为可能更大尺寸的有符号整数的结果由实现定义。这是避免混合无符号和有符号整数的另一个原因。

【讨论】:

    【解决方案4】:

    你可能对accuracy and precision有误解

    C++ 中的浮点类型没有不同的精度。它们具有固定位数,您不能以 1 位精度存储 1。它总是 53 位精度(假设 IEEE-754 双精度)。与 1.5 或 1.766569471 相同,无论您在文本中写了多少位

    计算机中的浮点类型不存储类型中的精度,因此1.51.50000001.500000000000 完全相同...

    【讨论】:

      【解决方案5】:

      这是由于大多数编程语言都内置了隐式类型转换,而不仅仅是 C++。更多详情,您可以查看此链接:
      http://www.cplusplus.com/doc/tutorial/typecasting/

      【讨论】:

      • 说“所有编程语言”太强了。例如,我知道几种完全不进行隐式类型转换的汇编语言。我建议将“全部”改为“大多数”。
      猜你喜欢
      • 2017-01-19
      • 2019-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多