Skip to main content
added 182 characters in body
Source Link
user555045
  • 10.7k
  • 1
  • 16
  • 32

Floating point equality

  bool operator==(const vector3d<T>& rhs) {
    return std::abs(x - rhs.x) < std::numeric_limits<T>::epsilon() &&
           std::abs(y - rhs.y) < std::numeric_limits<T>::epsilon() &&
           std::abs(z - rhs.z) < std::numeric_limits<T>::epsilon();
  }

We've probably all heard about the dangers of floating point equality, and seen the suggestion to compare them something like that. But this is probably not really what you want, for some different reasons.

  • Whether two vectors are "close", is a different question than whether each of the coordinates are "close". For example { 1e99, 1, 0 } and { 1e99, 0, 0 } would be considered different this way. That may be appropriate, but it may also not be. Those vectors have approximately the same length and have an angle of approximately zero degrees between them. On the other hand they are also legitimately different vectors by another measure: the difference between them is a nice vector with length 1.
  • This measure of closeness considers 1.0 and nextafter(1.0, 10) to be different. The distance between them is (by definition) epsilon, and epsilon is not less than epsilon, so the test fails. Should that be how it works? Maybe! That depends on what you want to happen. It's a suspicious behaviour though: it makes this test a test for exact equality for numbers that are 1.0 or higher, which looks unintentional.
  • This measure of closeness considered any pair of sufficiently small numbers to be equal, even they are relatively far apart. Again, maybe that's what you want, but it's suspicious.
  • The expected amount of numerical error for a given value depends not only on that value, but also on how it was computed.

Since you are using these vectors in a specific context, there may be an appropriate implementation for operator== (in which case, I don't expect that the current one does what you need it to do), but there may also not be. It's entirely possible that some of your vectors need to be compared for closeness one way, and some other vectors in another way. Just to make up some random examples: 1 meter above the ground is still 1 meter above the ground when the horizontal distance from the origin is large, that doesn't suddenly become "pretty much on the ground" just because we're located in a different corner of the map. On the other hand, two directions with an angle of almost 0 between them are close, regardless of any differences between the coordinates.

It seems reasonable to me to not implement operator== at all, and always explicitly state how vectors are to be compared (length of their difference, angle, or something else).

Floating point equality

  bool operator==(const vector3d<T>& rhs) {
    return std::abs(x - rhs.x) < std::numeric_limits<T>::epsilon() &&
           std::abs(y - rhs.y) < std::numeric_limits<T>::epsilon() &&
           std::abs(z - rhs.z) < std::numeric_limits<T>::epsilon();
  }

We've probably all heard about the dangers of floating point equality, and seen the suggestion to compare them something like that. But this is probably not really what you want, for some different reasons.

  • Whether two vectors are "close", is a different question than whether each of the coordinates are "close". For example { 1e99, 1, 0 } and { 1e99, 0, 0 } would be considered different this way. That may be appropriate, but it may also not be. Those vectors have approximately the same length and have an angle of approximately zero degrees between them. On the other hand they are also legitimately different vectors by another measure: the difference between them is a nice vector with length 1.
  • This measure of closeness considers 1.0 and nextafter(1.0, 10) to be different. The distance between them is (by definition) epsilon, and epsilon is not less than epsilon, so the test fails. Should that be how it works? Maybe! That depends on what you want to happen. It's a suspicious behaviour though: it makes this test a test for exact equality for numbers that are 1.0 or higher, which looks unintentional.
  • This measure of closeness considered any pair of sufficiently small numbers to be equal, even they are relatively far apart. Again, maybe that's what you want, but it's suspicious.
  • The expected amount of numerical error for a given value depends not only on that value, but also on how it was computed.

Since you are using these vectors in a specific context, there may be an appropriate implementation for operator== (in which case, I don't expect that the current one does what you need it to do), but there may also not be. It's entirely possible that some of your vectors need to be compared for closeness one way, and some other vectors in another way. Just to make up some random examples: 1 meter above the ground is still 1 meter above the ground when the horizontal distance from the origin is large, that doesn't suddenly become "pretty much on the ground" just because we're located in a different corner of the map. On the other hand, two directions with an angle of almost 0 between them are close, regardless of any differences between the coordinates.

Floating point equality

  bool operator==(const vector3d<T>& rhs) {
    return std::abs(x - rhs.x) < std::numeric_limits<T>::epsilon() &&
           std::abs(y - rhs.y) < std::numeric_limits<T>::epsilon() &&
           std::abs(z - rhs.z) < std::numeric_limits<T>::epsilon();
  }

We've probably all heard about the dangers of floating point equality, and seen the suggestion to compare them something like that. But this is probably not really what you want, for some different reasons.

  • Whether two vectors are "close", is a different question than whether each of the coordinates are "close". For example { 1e99, 1, 0 } and { 1e99, 0, 0 } would be considered different this way. That may be appropriate, but it may also not be. Those vectors have approximately the same length and have an angle of approximately zero degrees between them. On the other hand they are also legitimately different vectors by another measure: the difference between them is a nice vector with length 1.
  • This measure of closeness considers 1.0 and nextafter(1.0, 10) to be different. The distance between them is (by definition) epsilon, and epsilon is not less than epsilon, so the test fails. Should that be how it works? Maybe! That depends on what you want to happen. It's a suspicious behaviour though: it makes this test a test for exact equality for numbers that are 1.0 or higher, which looks unintentional.
  • This measure of closeness considered any pair of sufficiently small numbers to be equal, even they are relatively far apart. Again, maybe that's what you want, but it's suspicious.
  • The expected amount of numerical error for a given value depends not only on that value, but also on how it was computed.

Since you are using these vectors in a specific context, there may be an appropriate implementation for operator== (in which case, I don't expect that the current one does what you need it to do), but there may also not be. It's entirely possible that some of your vectors need to be compared for closeness one way, and some other vectors in another way. Just to make up some random examples: 1 meter above the ground is still 1 meter above the ground when the horizontal distance from the origin is large, that doesn't suddenly become "pretty much on the ground" just because we're located in a different corner of the map. On the other hand, two directions with an angle of almost 0 between them are close, regardless of any differences between the coordinates.

It seems reasonable to me to not implement operator== at all, and always explicitly state how vectors are to be compared (length of their difference, angle, or something else).

Source Link
user555045
  • 10.7k
  • 1
  • 16
  • 32

Floating point equality

  bool operator==(const vector3d<T>& rhs) {
    return std::abs(x - rhs.x) < std::numeric_limits<T>::epsilon() &&
           std::abs(y - rhs.y) < std::numeric_limits<T>::epsilon() &&
           std::abs(z - rhs.z) < std::numeric_limits<T>::epsilon();
  }

We've probably all heard about the dangers of floating point equality, and seen the suggestion to compare them something like that. But this is probably not really what you want, for some different reasons.

  • Whether two vectors are "close", is a different question than whether each of the coordinates are "close". For example { 1e99, 1, 0 } and { 1e99, 0, 0 } would be considered different this way. That may be appropriate, but it may also not be. Those vectors have approximately the same length and have an angle of approximately zero degrees between them. On the other hand they are also legitimately different vectors by another measure: the difference between them is a nice vector with length 1.
  • This measure of closeness considers 1.0 and nextafter(1.0, 10) to be different. The distance between them is (by definition) epsilon, and epsilon is not less than epsilon, so the test fails. Should that be how it works? Maybe! That depends on what you want to happen. It's a suspicious behaviour though: it makes this test a test for exact equality for numbers that are 1.0 or higher, which looks unintentional.
  • This measure of closeness considered any pair of sufficiently small numbers to be equal, even they are relatively far apart. Again, maybe that's what you want, but it's suspicious.
  • The expected amount of numerical error for a given value depends not only on that value, but also on how it was computed.

Since you are using these vectors in a specific context, there may be an appropriate implementation for operator== (in which case, I don't expect that the current one does what you need it to do), but there may also not be. It's entirely possible that some of your vectors need to be compared for closeness one way, and some other vectors in another way. Just to make up some random examples: 1 meter above the ground is still 1 meter above the ground when the horizontal distance from the origin is large, that doesn't suddenly become "pretty much on the ground" just because we're located in a different corner of the map. On the other hand, two directions with an angle of almost 0 between them are close, regardless of any differences between the coordinates.