代码之家  ›  专栏  ›  技术社区  ›  idan yossifov

整数的除法或乘法每次产生0.0000

  •  1
  • idan yossifov  · 技术社区  · 2 年前

    当我尝试打印preTopping时,即使事先添加(float),答案也总是0.0000

    int length, width;
    printf("Please enter your pizza's length (cm): ");
    scanf(" %d", &length);
    printf("Please enter your pizzas width (cm): ");
    scanf(" %d", &width);
    
    float preTopping, postTopping=0;
    preTopping = ((length * width) / (40 * 40)) * 60;
    printf("%f", preTopping);
    
    2 回复  |  直到 2 年前
        1
  •  4
  •   dbush    2 年前

    在这个表达式中:

    ((length * width) / (40 * 40)) * 60;
    

    所有操作数都有类型 int 这意味着完成了整数除法,并且整数除法截断任何分数部分。所以如果 length * width 小于1600,除法的结果将为0,因为这是结果的整数部分。

    如果要使用浮点除法,则需要将除法的至少一个操作数强制转换为浮点类型:

    preTopping = ((float)(length * width) / (40 * 40)) * 60;
    
        2
  •  1
  •   Lundin    2 年前

    认为一个表达式是在与结果分配给的类型相同的类型上执行的,这是初学者常见的错误;你的左边碰巧有什么类型的 = 一点也不重要。子表达式 ((length * width) / (40 * 40)) * 60 在上计算 int 类型无关紧要。

    请注意,诸如 40 也有一个类型,它是 int 。除非你写 40.0f =浮动或 40.0 =加倍。

    最佳实践:

    • 切勿在同一表达式中混合使用整数和浮点类型。以这种方式创建bug非常容易。
    • 你可能不应该使用 float 一点也不,但是 double ,假设您在x86 PC上编程 浮动 但它们仅限于Cortex M4的微控制器编程和具有单个精度FPU的类似设备。如果那是你正在使用的CPU,那么就不要使用 浮动 .

    如果您需要在表达式中使用整数变量,一个解决方案是将它们强制转换为所需的浮点类型:

    double preTopping = ((double)length * (double)width) / (40.0 * 40.0) * 60.0;
    

    在此表达式中,每个操作数的类型都是 双重的 并且没有发生隐式转换。这是一个好的、健壮的、可维护的代码。


    草率、脆弱的代码是另一种可能性:

    // BAD CODE
    double preTopping = ((double)length * width) / (40 * 40) * 60;
    

    这也有效,但这是一种“太聪明”的解决方案,应该像瘟疫一样避免。此代码依赖于隐式类型提升(特别是称为 常用的算术转换 ),即在我们有两个操作数的情况下 * 操作人员 (double)length 和一个 int width 这个 width 参数将隐式提升为 双重的 ,将在上进行计算 双重的 并且子表达式的结果是 双重的 .

    因此,这种隐含的提升在整个表达中不断升级。在这种情况下,我们有 * 和 / 具有相同的运算符优先级,但具有从左到右的关联性,这意味着 ((double)length * width) 将转换为 双重的 第一那么结果是 双重的 我们得到 "result" / 1600 其中 1600 操作数的类型为 int (因为40和40 int ).操作数一个接一个地隐式转换为 双重的 .

    然而,如果有人决定维护代码(真的发生了!),在运算符之间来回移动或在某个地方添加优先级更高的运算符,这可能会造成严重破坏。

    最佳实践:

    • 避免编写依赖于隐式类型提升的代码。

    • 编写尽可能“聪明”的代码实际上是愚蠢的。更难阅读,更难维护,更难排除故障。C编程传奇人物Brian Kernighan的一句名言:

      调试的难度是最初编写代码的两倍。因此,如果你尽可能聪明地编写代码,那么从定义上讲,你就不够聪明,无法调试它