I am trying to grovel the value of HUGE_VAL from math.h. This:
(constant (huge-val "HUGE_VAL") :type double-float)
doesn't work, presumably because HUGE_VAL isn't a proper float on my system (but rather some special positive infinity double float). I get this error:
The value NLOPT::INF is not of type REAL.
I need to use HUGE_VAL in the arguments in my NLOpt bindings (hence the package name in NLOPT::INF, though I don't think I even typed INF into the system). I believe that I can't use, say, most-positive-double-float, as there is special behavior when the value HUGE_VAL is used, i.e. it isn't just a large number.
Interestingly, I can grovel HUGE_VAL as an integer with value 18446744073709551615 which, presumably, if I used the ieee-floats system:
(ieee-floats:decode-float64 18446744073709551615) == HUGE_VAL
However, I'm not sure of that and that form naturally produces an overflow error. This is a value that cannot actually be represented as a float, after all. Anyway, I'm not sure that this helps me as I have to pass it to a function that expects a double (actually I pass it as an element in an array of doubles that gets passed to the function):
nlopt_result nlopt_set_lower_bounds(nlopt_opt opt, const double* lb);
So, I think I need to hold the sizeof(double) bytes in memory (whatever the value of HUGE_VAL is) so that I can write it out to an array later. This is doable, but I am having trouble figuring out the syntax to have the groveler automate the task of getting those sizeof(double) bytes in the first place.
Is there a way to deal with this? Even better, is there a way that CFFI makes this much simpler so I can just pass define whatever holds HUGE_VAL as an opaque object that can be used as a double? Even better yet, the value of HUGE_VAL provided by CFFI already and I am just not seeing it?
Thanks for reading, any help is appreciated, Zach
On Thu, 2013-04-25 at 16:31 -0600, Zach wrote:
I am trying to grovel the value of HUGE_VAL from math.h. This: (constant (huge-val "HUGE_VAL") :type double-float) doesn't work, presumably because HUGE_VAL isn't a proper float on my system (but rather some special positive infinity double float). I get this error:
The value NLOPT::INF is not of type REAL.
I need to use HUGE_VAL in the arguments in my NLOpt bindings (hence the package name in NLOPT::INF, though I don't think I even typed INF into the system). I believe that I can't use, say, most-positive-double-float, as there is special behavior when the value HUGE_VAL is used, i.e. it isn't just a large number.
Interestingly, I can grovel HUGE_VAL as an integer with value 18446744073709551615 which, presumably, if I used the ieee-floats system:
(ieee-floats:decode-float64 18446744073709551615) == HUGE_VAL
However, I'm not sure of that and that form naturally produces an overflow error. This is a value that cannot actually be represented as a float, after all. Anyway, I'm not sure that this helps me as I have to pass it to a function that expects a double (actually I pass it as an element in an array of doubles that gets passed to the function): nlopt_result nlopt_set_lower_bounds(nlopt_opt opt, const double* lb); So, I think I need to hold the sizeof(double) bytes in memory (whatever the value of HUGE_VAL is) so that I can write it out to an array later. This is doable, but I am having trouble figuring out the syntax to have the groveler automate the task of getting those sizeof(double) bytes in the first place.
Is there a way to deal with this? Even better, is there a way that CFFI makes this much simpler so I can just pass define whatever holds HUGE_VAL as an opaque object that can be used as a double? Even better yet, the value of HUGE_VAL provided by CFFI already and I am just not seeing it?
Remember that CFFI is untyped, so every (de)reference is an implicit cast. As long as you're careful about the type sizes, you can do something like this:
(with-foreign-object (huge :uint64) (setf (mem-ref huge :uint64) (expt 2 63)) (mem-ref huge :double))
When defining the binding to nlopt_set_lower_bounds, the second argument will be a (generic) pointer and you can pass a pointer to anything.
(constant (+huge-val+ "HUGE_VAL") :type integer)
then
(with-foreign-object (huge-ptr :uint64) (setf (mem-ref huge-ptr :uint64) +huge-val+) (nlopt-set-lower-bound opts huge-ptr))
(constant (+huge-val+ "HUGE_VAL") :type integer)
then
(with-foreign-object (huge-ptr :uint64) (setf (mem-ref huge-ptr :uint64) +huge-val+) (nlopt-set-lower-bound opts huge-ptr))
I have also been thinking along these lines. The only thing I worry about is whether this is strictly correct or just correct in practice. Is there a guarantee that a double float is always the same size as a uint64. It's true on every platform I have ever programmed for (I think), but will it always be true? Back when I programmed in C more often, hard coding data type sizes into a program just seemed wrong so I didn't do it, so I guess I wouldn't know. Perhaps I am sweating a non-issue...
Thanks for the advice.
On Thu, 25 Apr 2013 20:55:38 -0600, Zach said:
(constant (+huge-val+ "HUGE_VAL") :type integer)
then
(with-foreign-object (huge-ptr :uint64) (setf (mem-ref huge-ptr :uint64) +huge-val+) (nlopt-set-lower-bound opts huge-ptr))
I have also been thinking along these lines. The only thing I worry about is whether this is strictly correct or just correct in practice. Is there a guarantee that a double float is always the same size as a uint64. It's true on every platform I have ever programmed for (I think), but will it always be true? Back when I programmed in C more often, hard coding data type sizes into a program just seemed wrong so I didn't do it, so I guess I wouldn't know. Perhaps I am sweating a non-issue...
That's not the only problem -- on some platforms, HUGE_VAL is not a compile-time constant. It looks like the only portable way to get the value is to write a C helper function to return it.
Thanks Martin, that's just what I'll do.
However, isn't the entire point of a groveler to build a little C program that gathers information like this for later use? If one were to write a general purpose way to do this, wouldn't the logical place to put that code be in cffi-groveler? Is the main hurdle here the fact that HUGE_VAL doesn't necessarily have a representation as a Lisp interger or double-float, the only two types that cvar allows? Even though some of these sound a bit rhetorical, these are honest questions.
Zach
On Fri, Apr 26, 2013 at 8:25 AM, Martin Simmons martin@lispworks.comwrote:
On Thu, 25 Apr 2013 20:55:38 -0600, Zach said:
(constant (+huge-val+ "HUGE_VAL") :type integer)
then
(with-foreign-object (huge-ptr :uint64) (setf (mem-ref huge-ptr :uint64) +huge-val+) (nlopt-set-lower-bound opts huge-ptr))
I have also been thinking along these lines. The only thing I worry
about
is whether this is strictly correct or just correct in practice. Is
there
a guarantee that a double float is always the same size as a uint64.
It's
true on every platform I have ever programmed for (I think), but will it always be true? Back when I programmed in C more often, hard coding data type sizes into a program just seemed wrong so I didn't do it, so I
guess I
wouldn't know. Perhaps I am sweating a non-issue...
That's not the only problem -- on some platforms, HUGE_VAL is not a compile-time constant. It looks like the only portable way to get the value is to write a C helper function to return it.
-- Martin Simmons LispWorks Ltd http://www.lispworks.com/
On Fri, 2013-04-26 at 08:40 -0600, Zach wrote:
Thanks Martin, that's just what I'll do. However, isn't the entire point of a groveler to build a little C program that gathers information like this for later use?
The groveler can only deal with compile-time constants. What Martin means, I suppose, is that HUGE_VAL could be defined as a function call to a compiler intrinsic, for instance. See http://cvsweb.netbsd.org/bsdweb.cgi/src/include/math.h?rev=1.62
If one were to write a general purpose way to do this, wouldn't the logical place to put that code be in cffi-groveler?
To do what exactly ?
Is the main hurdle here the fact that HUGE_VAL doesn't necessarily have a representation as a Lisp integer or double-float, the only two types that cvar allows?
That too is an issue. There's another ASDF component in cffi-grovel, named wrapper-file, that can help with automatically generating a shared library that contains functions that wrap values which cannot be portably grovelled, so your best choice might be to generate a wrapper that returns an uint64_t which you then pass to nlopt_set_lower_bounds(), completely avoiding the use of Lisp floats.