2
$\begingroup$

I need to deliberately return a 'NAN' from a LibraryLink function, which is expected to return mcomplex so it appears as Indeterminate in Mathematica.

MArgument_setComplex(Res, ???);
return LIBRARY_NO_ERROR;

What do I put in ????

$\endgroup$
4
  • $\begingroup$ Do you mean something like 0./0.? $\endgroup$
    – Michael E2
    Jun 20, 2017 at 1:28
  • $\begingroup$ @MichaelE2 Yes something like that. I could define an exception constant double myNaN = 0./0., but I don't know how to turn it into an mcomplex. $\endgroup$
    – QuantumDot
    Jun 20, 2017 at 1:30
  • $\begingroup$ My thought it to divide two complex zeros. If necessary define a variable zero, mcomplex z = {0.,0.}. Or maybe mcomplex zNaN = {0./0., 0./0.}? $\endgroup$
    – Michael E2
    Jun 20, 2017 at 1:37
  • $\begingroup$ Ok, that works; I didn't realize you could simply define an mcomplex like that. I wonder if that's the "official" way of making it return Indeterminate. $\endgroup$
    – QuantumDot
    Jun 20, 2017 at 1:48

1 Answer 1

2
$\begingroup$

It is not clear to me how well IEEE 754 NaNs or infinities are supported in Mathematica. I have seen values come out as an unusable expression (instead of Indeterminate) when sending them through MathLink. I do not understand when and why this happens, but it's good to keep in mind that NaNs have multiple representations, and there's multiple kinds of them.


You can create a NaN using the nan() function from the math.h header, and insert it into an mcomplex:

double dnan = nan("");
mcomplex cnan = {dnan, dnan};

With LTemplate, this is a bit simpler, as it uses std::complex<double> as the complex type. Thus std::nan("") can automatically be converted to the complex version.

Below is an LTemplate program that tests sending multiple kinds of NaNs in multiple ways (as a simple double, as part of an array, with or without MathLink). I tested it in 10.0.2 and 11.2.0 on OS X, and the result was always Indeterminate instead of an unusable value. Thus, at least on this platform, this seems to be a safe way to pass back an Indeterminate. Perhaps someone can test on other platforms.

SetDirectory@CreateDirectory[];
Needs["LTemplate`"]

tem = LClass["NaNDemo",
   {
    LFun["NaN", {}, Complex],
    LFun["quietNaN", {}, Real],
    LFun["signalingNaN", {}, Real],
    LFun["quietNaNML", LinkObject],
    LFun["signalingNaNML", LinkObject],
    LFun["arrayQuietNaN", {}, {Real, 1}],
    LFun["arraySignalingNaN", {}, {Real, 1}],
    LFun["arrayQuietNaNML", LinkObject],
    LFun["arraySignalingNaNML", LinkObject]
    }
   ];

code = "
  #include <mlstream.h>
  #include <cmath>
  #include <limits>

  struct NaNDemo {
    mma::complex_t NaN() { return std::nan(\"\"); }

    double quietNaN() { return std::numeric_limits<double>::quiet_NaN(); }
    double signalingNaN() { return std::numeric_limits<double>::signaling_NaN(); }

    void quietNaNML(MLINK link) {
        mlStream ml(link);
        ml >> mlCheckArgs(0);
        ml.newPacket();
        ml << quietNaN();
    }

    void signalingNaNML(MLINK link) {
        mlStream ml(link);
        ml >> mlCheckArgs(0);
        ml.newPacket();
        ml << signalingNaN();
    }

    mma::RealTensorRef arrayQuietNaN() {
        auto vec = mma::makeVector<double>(1);
        vec[0] = quietNaN();
        return vec;
    }

    mma::RealTensorRef arraySignalingNaN() {
        auto vec = mma::makeVector<double>(1);
        vec[0] = signalingNaN();
        return vec;
    }

    void arrayQuietNaNML(MLINK link) {
        mlStream ml(link);
        ml >> mlCheckArgs(0);
        ml.newPacket();
        ml << std::vector<double>({quietNaN()});
    }

    void arraySignalingNaNML(MLINK link) {
        mlStream ml(link);
        ml >> mlCheckArgs(0);
        ml.newPacket();
        ml << std::vector<double>({signalingNaN()});
    }
  };";
Export["NaNDemo.h", code, "String"]

CompileTemplate[tem, 
 "CompileOptions" -> {"-mmacosx-version-min=10.9"}]

LoadTemplate[tem]

obj = Make[NaNDemo];

obj@"NaN"[]
(* Indeterminate *)

obj@"quietNaN"[]
(* Indeterminate *)

obj@"signalingNaN"[]
(* Indeterminate *)

obj@"quietNaNML"[]
(* Indeterminate *)

obj@"signalingNaNML"[]
(* Indeterminate *)

obj@"arrayQuietNaN"[]
(* {Indeterminate} *)

obj@"arraySignalingNaN"[]
(* {Indeterminate} *)

obj@"arrayQuietNaNML"[]
(* {Indeterminate} *)

obj@"arraySignalingNaNML"[]
(* {Indeterminate} *)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.