0

We have been asked to design a Vector3D class using memory on the stack. I need to divide the vector by a scalar, but what is the most appropriate behavior to prevent a divide by zero? I could throw an exception? I don't want to return a Vector3D of (0,0,0) because that would suggest that the operation was successful, when in fact it wasn't.

Vector3DStack Vector3DStack::operator / (float s) const
{
    if (s == 0)
    {
        // How should I handle division by zero?
        // Method is expecting a Vector3DStack to be returned.

    }

    return Vector3DStack(x / s, y / s, z / s);
}
Bart
  • 19,692
  • 7
  • 68
  • 77

5 Answers5

2

Throw a std::invalid_argument, which derives from a std::logic_error; it indicates there is something wrong with the logical flow of a program, through an invalid argument.

Alex Chamberlain
  • 4,147
  • 2
  • 22
  • 49
  • Hmm if you are writing a library for instance I believe invalid_argument is more appropriate. Of course this depends strongly on the particular case. – Ivaylo Strandjev Nov 07 '13 at 13:31
  • Judging by the name, I think this is intended for graphics, where you might have millions of generated or sourced vertices. You might want to normalize so you avoid overflows, only to find that the division can cause overflows too. It might just be unavoidable, without being what I would call a logic error. – John P May 13 '22 at 21:36
2

It really depends on what Vector3DStack will be used for.

You could

  • throw an exception
  • make it configurable (perhaps check only happens in debug mode)
  • just allow the div by zero to return a Nan - caller can check with std::isnan()
  • specify the problem away. Write down that it is the callers responsibility that it not set s to 0 (this is called a precondition)

Which is best depends.

Bull
  • 11,771
  • 9
  • 42
  • 53
  • Yet another solution: specify a return type of `boost::optional` and return `boost::none` if the input is wrong (would not recommend it for this particular case though). – Matthieu M. Nov 07 '13 at 14:00
0

You should definitely throw an exception.That is what exceptions are for - to indicate exceptional circumstances in your code. Actually you may allow a small tolerance around zero too, for instance:

Vector3DStack Vector3DStack::operator / (float s) const
{
    if (fabs(s) < 1e-10) {
      ... throw some exception to indicate you are dividing a vector by zero.
    }
    return Vector3DStack(x / s, y / s, z / s);
}
Ivaylo Strandjev
  • 69,226
  • 18
  • 123
  • 176
0

Since you have to return a value from the operator, you have two options:

  1. Throw an exception (definitely preferred)
  2. Return a vector consisting of three NaNs.

By the way, you should not chceck, whether a float value is equal to zero, because you'll get a lot false negatives. Due to specific floating point arithmetics, you should rather compare the divisor with a very small value (the one, which is smaller than anything you use in your algorithms - for instance, if you operate on 1e-9 values, choose 1e-20).

Spook
  • 25,318
  • 18
  • 90
  • 167
0

The appropriate behavior depends on the function's specification. The function can be written without any checking (this works just fine with IEEE-conformant floating-point math); it can check for 0 and throw an exception; it can check for 0 and abort; it can check for 0 and simply return. All of these behaviors are reasonable, and it's impossible to say what the best choice is without context. It's like asking "I'm going to go on a trip; should I drive or fly?".

Pete Becker
  • 74,985
  • 8
  • 76
  • 165