Hi all,
After some off-list discussion with Chris I have fixed his fix in
longlong-double-fix branch. It seems to work, passes all tests and is more
or less ready for merging to master.
Travis-CI is all green see https://travis-ci.org/PDLPorters/pdl/builds/77348194
All changes:
https://github.com/PDLPorters/pdl/compare/master...longlong-double-fix#files_bucket
The main idea is a new type PDL_Anyval capable of keeping values of all
types without loosing any precision. Like this:
typedef enum { PDL_B, PDL_S, PDL_US, PDL_L, PDL_IND, PDL_LL, PDL_F, PDL_D }
pdl_datatypes;
typedef struct {
pdl_datatypes type;
union {
PDL_Byte B;
PDL_Short S;
PDL_Ushort U;
PDL_Long L;
PDL_Indx N;
PDL_LongLong Q;
PDL_Float F;
PDL_Double D;
} value;
} PDL_Anyval;
There are still some questions that I want to discuss here:
_*1/ "broken" C API (not that much, but still)*_
Using PDL_Anyval struct (instead of plain double) has some side effects
concerning C API, namely:
PDL->put_offs(..)
PDL->get_offs(..)
PDL->get(..)
PDL->get_pdl_badvalue(..)
The relevant declarations in Core structure were not changed:
void (*put_offs)(pdl *pdl,PDL_Indx offs, PDL_Anyval val);
PDL_Anyval (*get_offs)(pdl *pdl,PDL_Indx offs);
PDL_Anyval (*get)(pdl *pdl,PDL_Indx *inds);
PDL_Anyval (*get_pdl_badvalue)(pdl *it);
however the old code like:
if( PDL->get_pdl_badvalue(a) == 0 ) { ... }
does not work anymore (it does not even compile) from obvious reason.
The new style should be
double bad_a;
ANYVAL_TO_CTYPE(bad_a, double, PDL->get_pdl_badvalue(a));
if( bad_a == 0 ) { ... }
BTW: via http://grep.cpan.me/ I have found only one Zaki's module that is
affected (+of course possibly a lot of code not on CPAN)
There are also four newly introduced ANYVAL_* macros in pdl.h for handling
PDL_Anyval from C code.
#define ANYVAL_TO_SV(outsv,inany) ...
#define ANYVAL_FROM_CTYPE(outany,avtype,inval) ...
#define ANYVAL_TO_CTYPE(outval,ctype,inany) ...
#define ANYVAL_EQ_ANYVAL(x,y) ...
Which will be a pain for those who want to write their modules/program so
that it works with old PDL versions (without these macros) as well as with
the new version. The only recommendation I have for this scenario is the
following set of defines that has to be added to the C code for
compatibility with older PDL.
#if PDL_CORE_VERSION < 12
#define ANYVAL_TO_SV(outsv,inany) outsv = newSVnv((NV)(inany)
#define ANYVAL_FROM_CTYPE(outany,avtype,inval) outany = (PDL_Double)(inval)
#define ANYVAL_TO_CTYPE(outval,ctype,inany) outval = (ctype)(inany)
#define ANYVAL_EQ_ANYVAL(x,y) (x == y)
#endif
_*2/ typemap & undef handling*_
I am not quite sure what is the expected behaviour when undef SV argument
has to be converted to PDL_Anyval. Now I convert it into a invalid
PDL_Anyval { type=-1, value.B=0 } which might not be the best idea.
The old behaviour was always (even for undef) use:
$var = (double)SvNV($arg)
The difference can be seen for example here:
my $p = sequence(4);
PDL::Core::set_c($p, [1], undef);
print $p
The old behaviour is "undefined ... warning" + setting the value to 0
(zero). The new behaviour is to croak.
Of course it would be easy to change croak() to silently setting 0 value
but I want to ask: what is correct/expected/best behaviour in this case?
We are talking here about a typemap so we do not have any context (e.g.
type of a piddle where PDL_Anyval value will be later assigned) therefore
the obvious suggestion for using badval for undef is not possible as it is
not clear which badval.
_*3/ PDL data type auto-detection*_
Auto-detection (we have a SV and want to decide for the best PDL datatype)
is implemented at couple of places. Based on perl's SV type (int/IV or
double/NV) we decide for PDL_Long (on perl with 64bit int for PDL_LongLong)
or PDL_Double.
Simplified code works like this:
if (SvIOK(sv)) {
#if IVSIZE == 8
val = (PDL_LongLong)SvIV(sv)
#else
val = (PDL_Long)SvIV(sv)
#endif
} else if (SvOK(sv)) {
val = (PDL_Double)SvNV(sv) /* tries also to convert strings */
} else {
// do some magick in undef case
}
or even simpler:
if (SvIOK(sv)) {
#if IVSIZE == 8
val = (PDL_LongLong)SvIV(sv)
#else
val = (PDL_Long)SvIV(sv)
#endif
} else {
val = (PDL_Double)SvNV(sv) /* tries also to convert strings + undef */
}
This kind of works but I am open to any comments/improvements.
BTW: let's have:
$p = pdl( [ 1, 2, 3] ); # perl integers
print $p;
Is it correct that type of $p is always Double? although LongLong would be
more than enough?
Thanks in advance for any feedback.
--
kmx
------------------------------------------------------------------------------
_______________________________________________
pdl-devel mailing list
pdl-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/pdl-devel