2

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 ????

QuantumDot
  • 19,601
  • 7
  • 45
  • 121
  • Do you mean something like 0./0.? – Michael E2 Jun 20 '17 at 01:28
  • @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. – QuantumDot Jun 20 '17 at 01:30
  • 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.}? – Michael E2 Jun 20 '17 at 01:37
  • 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. – QuantumDot Jun 20 '17 at 01:48

1 Answers1

2

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} *)
Szabolcs
  • 234,956
  • 30
  • 623
  • 1,263