The OP hasn't returned to the site yet, so I'll give a few ways to test if a number is close enough to be considered real. Equal
tests floating-point numbers with relative tolerance (the same up to the last seven bits, usually). So x - y == 0
means x
and y
are exactly equal, whereas x == y
means they agree to 46 bits or more (46 = 53-7), if they are machine precision; and x + y == x
means Abs[y]
is less than around Abs[x] * 2^7 * $MachineEpsilon
if they are machine precision reals. The standard C-like advice on comparing floats is not to use ==
but something like $|x-y| < t$, for some tolerance $t$ which may depend on $x$ and $y$. In Mathematica, Equal
has such a tolerance built in, which one may find convenient, and its design allows it to be used for both exact equality and relative equality.
The tests take advantage of Equal
except the last, which is a structural test and not a numeric one. The additional numbers, shown below the divider, show the edge cases of each test.
realTests = {
Abs[#] == Abs@Re[#] &,
Re[#] + Im[#] == Re[#] &,
Im[#] == 0 &,
Head[#] === Real &}; (* effectively the same as MatchQ[#,_Real]& *)
mydata = {0.312712544956844,
0.287641445144978 - 0.306854031390629*I,
0.287641445144978 + 0.306854031390629*I,
0.287641445144978 + 0.*I,
0.287641445144978 + $MinMachineNumber*I,
0.287641445144978 (1 + (2^7 - 1)*$MachineEpsilon/2*I),
0.287641445144978 (1 + (2^7 - 0)*$MachineEpsilon/2*I),
0.287641445144978 + ( 2^-24.301)*I,
0.287641445144978 + ( 2^-24.300)*I};
Grid[
Join[
{Prepend[#, ""]},
Join[Transpose@{mydata}, Through /@ # /@ mydata, 2]] /.
True -> Style[True, Darker@Magenta],
Dividers -> {{False, True, {False}},
{False, True, False, False, True, {False}}},
Alignment -> {{Left, {Center}}, Automatic}
] &@realTests
These tests may be used in the several selectors of Mathematica:
With[{test = realTests[[2]]},
Column@{
Select[mydata, test],
Pick[mydata, test /@ mydata],
Cases[mydata, z_?test :> Re[z]]
}]
Instead of Re[z]
in Cases
above, you can apply Re
to the results to discard the imaginary parts of the selected numbers for any of the tests. Below I also include a particularly efficient method for large data using the vectorization of Im
and Sign
.
With[{test = realTests[[3]]},
Column@{
Re@ Select[mydata, test],
Re@ Pick[mydata, test /@ mydata],
Re@ Pick[mydata, Sign@Im@mydata, 0],
Re@ Cases[mydata, z_?test]
}]
Exact numbers like 7
and 3 - 2 I
behave differently, but consideration of them does not seem within the scope of the question.
1. + 1.*10^-300 I
? I would expect round-off error in both the real and imaginary parts. If you know already that you do not have such edge cases as the example, then proceed withIm[#] == 0
and so forth. If you're generating data and need code to handle whatever comes up, then I suggest you need to handle the edge cases in a deliberate way $\endgroup$list /. _Complex :> Nothing
$\endgroup$