Arithmetic overflow: Using operator '*' on a 4 byte value then casting the result to a 8 byte value

耗尽温柔 提交于 2019-12-23 05:35:17

问题


I am trying to write a program to solve a quadratic equation whose coefficients' values do not exceed 100 by absolute value and it is guaranteed that if any roots exist, they are integers. Here's what I've tried:

#include <cmath>
#include <iostream>

int main() {
  int a, b, c;  // coefficients of quadratic equation
  std::cin >> a >> b >> c;
  int d = b * b - 4 * a * c;  // discriminant

  if (d < 0)
    std::cout << "No roots";
  else if (d == 0)
    std::cout << "One root: " << -b / (2 * a);
  else
    std::cout << "Two roots: " << (-b - std::sqrt(d)) / (2 * a) << " "
              << (-b + std::sqrt(d)) / (2 * a);

  return 0;
}

It works fine, however, Visual Studio 2019 shows this warning:

Arithmetic overflow: Using operator '*' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator '*' to avoid overflow (io.2).

Exactly why does this warning pop up and what is it trying to tell me? What am I doing wrong and how can I fix the problem?

I've seen this on SO, but I don't believe it's a bug.


回答1:


It's not a bug. Here:

(-b - std::sqrt(d)) / (2 * a)

The result of the expression is a double. But result of 2 * a is an int and it's eventually converted to a double. It is possible that 2 * a overflows if a is too large before it's converted to double. But since the eventual result is already a double, you could cast 2 or a to double as well and avoid the risk of overflow once and for all. So the compiler is telling you that the Right ThingTM to do is:

(-b - std::sqrt(d)) / (2.0 * a)

It won't overflow (result of (2.0 * a) is a double) and it's probably already what you want.




回答2:


The root cause here (pun very much accepted) is that the quadratic equation is not a Diophantine equation. It applies to real numbers, and in particular sqrt(d) is usually not an integer.

In C++, the return type of sqrt(IntegralType) is double. Thus 2*a is converted to double too, but only after multiplying. And Visual Studio very reasonably notes that you're better off doing the conversion before multiplying. It just doesn't note that you can even make a,b,c all doubles from the start.




回答3:


The way to fix this is to static_cast<long long> because long long is 8 bytes and it is large enough to hold the information in the event of an overflow. An overflow occurs when you try to hold a number when you do not have enough bits to do so and as a result some of them get chopped off.

Here is an example without the warning:

std::cout << "Two roots: " << (-b - std::sqrt(d)) / (2 * static_cast<long long>(a)) << " "
          << (-b + std::sqrt(d)) / (2 * static_cast<long long>(a));



来源:https://stackoverflow.com/questions/59308422/arithmetic-overflow-using-operator-on-a-4-byte-value-then-casting-the-resul

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!