这里有一个例子.

#include <stdio.h>

int main(void){
    int score1 = 70, score2 = 58, score3 = 99;

    float total = 3;
    printf("Average: %f\n", (score1 + score2 + score3)/total);
}

它给了我75.666664如果我把total替换成3.0,

#include <stdio.h>

int main(void){
    int score1 = 70, score2 = 58, score3 = 99;
    printf("Average: %f\n", (score1 + score2 + score3)/3.0);
}

它给了我75.666667.

推荐答案

C中的所有东西都有一个类型,其中包括数字常量/文字,如3.0.

  • 3的类型是int.
  • 3.0f的类型是float.
  • 3.0的类型是double.

进而,floatdouble在某个系统上可能具有相同的精度,也可能不具有相同的精度.显然,double在你的系统上有更高的精度,因此你会注意到不同之处.


关于implicit type promotions人的一些注意事项:

  • score1 + score2 + score3都是int类型,因此不会发生隐式提升,结果是int.

  • 将结果int与另一个类型为float的操作数放在一起的操作中,意味着在操作之前,int将被提升为float(根据"通常的算术转换",请参见上面的链接).

  • 或者在3.0的情况下,int的结果将被提升到double.

  • printf%f所做的事情碰巧总是期望double作为输入(%lf也可以),如果您给它float,它将被隐式地提升为double,这是一个针对变量函数的奇怪规则,称为"默认参数提升".

    但由于最后的类型升级发生在after,所以结果是计算出来的,这不会影响精度.


最佳实践:

  • 对于类型要明确,并避免包含隐式提升的代码.
  • 避免在同一表达式中混合使用int/float/double,因为这是众所周知的错误配方.坚持使用一种类型,并在需要的地方显式转换操作数.

例如,我会像这样重写您的代码:

(double)(score1 + score2 + score3) / 3.0

功能是100%等价的,但这是self 文档化的代码,不依赖于隐含的提升,比如"我知道我在做什么".

相反的--代码依赖于silent的隐性促销--说:"要么我知道我在做什么,依靠隐性促销,要么我不知道我在做什么,只是靠(坏)运气把这个表达弄对了/弄错了."

C++相关问答推荐

漏洞仅出现在FreeBSD上,但在Windows、Linux和MacOS上运行得非常好

gcc已编译的可执行文件TSB是否同时暗示最低有效字节和最低有效位?

返回一个包含数组的 struct

ZED for SDL上的C语言服务器

模拟shell并运行.sh文件

C是否用0填充多维数组的其余部分?

预先分配虚拟地址空间的区域

使用错误的命令执行程序

在句子中转换单词的问题

#定义SSL_CONNECTION_NO_CONST

C代码在字符串中删除不区分大小写的子字符串的问题

在libwget中启用Cookie会导致分段故障

理解bzip2的BZ2_解压缩函数中的状态重新分配

将某些内容添加到链接列表时,列表中的其他项将使用最后添加的项的名称

传递给函数的 struct 中的数组

从文件到链表读取日期

将char*铸造为空**

通过GTK';传递回调参数;s g_signal_connect()导致C中出现意外值

与指针的原始C数组或C++向量<;向量<;双>>;

GDB 跳过动态加载器代码