-3

I need to safely check is my complex number a zero (or very similar to it). How can I do it for floating point numbers?

Can I use something like:

std::complex<double> a;
if(std::abs(std::real(a)) <= std::numerical_limits<double>::epsilon() && std::abs(std::imag(a)) <= std::numerical_limits<double>::epsilon())
{
//...
}

I will divide values by a and don't want to get the INF as result.

Robotex
  • 1,064
  • 6
  • 17
  • 41
  • https://en.cppreference.com/w/cpp/types/numeric_limits/epsilon Returns the machine epsilon, that is, the difference between 1.0 and the next value representable by the floating-point type T. See the example in cppreference, floating number became less dense when you increase the magnitute of the numbers, you need to take in account scaling – Alessandro Teruzzi Nov 23 '21 at 15:06
  • 1
    Wouldn't `std::abs(a) < epsilon` be better than just comparing the real part? – Mestkon Nov 23 '21 at 15:07
  • That would make the "close enough" area square; numbers of the form `a + ai` would be "zero" further from actual zero than `a + 0i` or `0 + ai`. Wouldn't a circle, i.e. the magnitude `abs(a)`, be better? – molbdnilo Nov 23 '21 at 15:09
  • 1
    "to check is my complex number a zero" --> `x == 0.0` is enough. Comparing with _epsilon_ in a linear fashion takes the float out of floating point numbers. Post a real use case for more feedback. – chux - Reinstate Monica Nov 23 '21 at 15:16
  • The sample code you show suggests you want to test not whether the computed number is zero but whether it is near zero. Often this is done with the intent to test whether the result of doing the same calculations with the usual mathematical arithmetic, rather than limited-precision floating-point arithmetic, would be zero. But there is no uniform value for how much the error in final computed result can be; it can be zero, infinite, or NaN depending on what calculations were done with what data, and bounds can be absolute, relative to the value, or some complex function… – Eric Postpischil Nov 23 '21 at 17:30
  • 1
    … Further, any “fudging” of the comparison to zero trades false negatives for false positives or vice-versa, and the risks and rewards of these depend on the application. So there is no general answer to this. And you have not given any context, none at all, no indication of what calculations are being performed or what data is used. So there is no answer to your question. – Eric Postpischil Nov 23 '21 at 17:32
  • @Mestkon "Wouldn't std::abs(a) < epsilon be better than just comparing the real part? " -- Hmmm, maybe. Should I create a complex epsilon variable? – Robotex Nov 24 '21 at 11:02
  • @chux-ReinstateMonica "Post a real use case for more feedback." ax^4+bx^3+cx^2+dx+e == 0. I need to use cubic equation solver if a is very close to zero instead of quadratic – Robotex Nov 24 '21 at 11:04
  • @Robotex `std::abs(a)` returns a real value. The magnitude of a complex number is always real as it can be interpreted as the euclidian distance from the origin to the point `(a, b)` for a complex number `a + bi` – Mestkon Nov 24 '21 at 11:41
  • Robotex, Using `|a| <= epsilon` is the wrong approach as the test does not scale across floating point values. Something like `|x| <= epsilon*|y|` makes sense, aside from near zero. ax^4+bx^3+cx^2+dx+e == 0 is a start, but really need to see your code – chux - Reinstate Monica Nov 24 '21 at 14:51
  • @chux-ReinstateMonica https://gist.github.com/NicholasShatokhin/af285380668925fcac505673b3fe2582 – Robotex Nov 25 '21 at 17:57
  • Please post here as remote sites tend to disappear. BTW, why is, what looks like a [quartic](https://en.wikipedia.org/wiki/Quartic_equation) equation, called `solve_quadric()` (alternate spelling)? and why does code have no comments or context? – chux - Reinstate Monica Nov 25 '21 at 21:10
  • @chux-ReinstateMonica I tried to post here, but there is the symbols limits. "what looks like a quartic equation, called solve_quadric() (alternate spelling)" - yes, I made a mistake in name, English is not my native language. "why does code have no comments or context?" - because it is just my code that I didn't plan to show anybody and there are just a few calculations what don't need to be explained. – Robotex Nov 26 '21 at 09:16
  • @Robotex Consider 2 polynomials with _roots_: `r1,r2,r2,r4` and `s*r1,s*r2,s*r2,s*r4`. With one set, `islessequal(abs(real(a)), ... epsilon()) ...` may be true and with the other it is false. Because the compare is done with the magnitude of `a` and `epsilon` and not its relative magnitude. Here, as the magnitude of roots increase by `s`, the magnitude of `a` decreases by `cuberoot(s)`. These are _floating point_ numbers, not [fixed point](https://stackoverflow.com/q/7524838/2410359) ones. So the compare needs a scaled compare. For more, post local with comments. – chux - Reinstate Monica Nov 26 '21 at 11:09

2 Answers2

1

I need to check is my complex number a zero. How can I do it for floating point numbers?

You can compare it with a floating point literal with value of 0. You cannot use an integer literal with std::complex<double>. Example:

a == 0.0

Can I use something like ...

What you've shown doesn't compare whether the complex number is zero; it compares whether the complex number is near zero. This can be a reasonable operation for example in the case the number is result of a calculation with a known margin of error, and you want to know whether the result is within the margin. But it is a separate operation

Whether that is a good way to compare if the number is near zero depends on use case. For example, epsilon is not necessarily the best threshold of "near". Another thing that you might consider is whether you should compare std::abs(a) to the threshold instead of comparing the components separately i.e. whether you should use euclidean distance instead of manhattan distance.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Curious: Why "You cannot use an integer literal" ? Invalid to do _complex_ op _int_? – chux - Reinstate Monica Nov 23 '21 at 17:03
  • 1
    @chux-ReinstateMonica You can use integer literal if you used `std::complex` for example, but OP used `std::complex`. – eerorika Nov 23 '21 at 17:06
  • "What you've shown doesn't compare whether the complex number is zero; it compares whether the complex number is near zero." -- It is the only one way to compare floating points. There is impossible to compare is floating point number exactly zero – Robotex Nov 24 '21 at 11:00
  • 1
    @Robotex That's not true. What I've shown is possible, and it does compare whether the floating point number is exactly zero. – eerorika Nov 24 '21 at 11:06
  • @eerorika that statement will almost never be true – Robotex Nov 24 '21 at 12:41
  • @Robotex It's always true, with only theoretical exception being some uncommon floating point type that has no representation for zero. – eerorika Nov 24 '21 at 13:22
  • @eerorika Did you tried it? You can't guarantee that value in variable is exactly the same value that you expected if it is floating point https://0.30000000000000004.com/ 0.1 + 0.2 = 0.30000000000000004 – Robotex Nov 25 '21 at 10:45
  • @Robotex `You can't guarantee that value in variable is exactly the same value that you expected` Sure I can. When I write `float x = 0`, I expect that it's value will be 0, and I can guarantee with 100% certainty, that it is. – eerorika Nov 25 '21 at 10:48
  • @eeronika But I need to check the result of calculations, not the assigned value – Robotex Nov 25 '21 at 11:14
  • @Robotex As I mentioned in the answer, in that case it would be more useful to compare whether the result is near the target value, rather than whether it **is** the target value. – eerorika Nov 25 '21 at 11:45
  • @eerorika Yes, question exactly about this. I asked how to do it with complex numbers. – Robotex Nov 25 '21 at 11:47
  • @Robotex You asked how to compare whether complex number is zero. I answered that. You didn't ask how to compare whether it is near zero. I also answered that whether your attempt to compare if the value is near zero is good, depends on the use case. – eerorika Nov 25 '21 at 11:48
  • @eerorika I'm not accepting your answer. – Robotex Nov 26 '21 at 11:03
  • "Another thing that you might consider is whether you should compare std::abs(a) to the threshold instead of comparing the components separately" - why? Will I get INF if divide number by 0+10000*i ? – Robotex Dec 01 '21 at 09:49
1

Have you tried std::fpclassify from <cmath>?

if (std::fpclassify(a.real()) == FP_ZERO) {}

To check if both the real and imaginary part of a complex are 0:

if (a == 0.0) {}

As mentioned by @eerorika a long time before I did. An answer you rejected.
Floating point precision, rounding, flag raising, subnormal is all implementation-defined (See: [basic.fundamental], [support.limits.general], and ISO C 5.2.4.2.2).

viraltaco_
  • 814
  • 5
  • 14
  • How does this function works? Why do we check only the real part of number. Is division RealNumber/ImaginaryNumber or ImaginaryNumber/OtherImaginaryNumber forbidden? – Robotex Dec 02 '21 at 10:06
  • I didn't consider all that. Complex number theory is not really fresh in my head. I'm not sure, but if the imaginary part is 0: isn't it just a real number? – viraltaco_ Dec 02 '21 at 23:03
  • "isn't it just a real number" -- yes, in this case we got an error if real part is zero too. But I asked about case when real part is zero and imaginary not. – Robotex Dec 03 '21 at 14:11