gnuastro-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnuastro-commits] master a4c5b9d 012/125: Binary operator arithmetic wo


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master a4c5b9d 012/125: Binary operator arithmetic works on uncompiled types
Date: Sun, 23 Apr 2017 22:36:26 -0400 (EDT)

branch: master
commit a4c5b9dc6cd86a523f50e783a3072cb2fe24a338
Author: Mohammad Akhlaghi <address@hidden>
Commit: Mohammad Akhlaghi <address@hidden>

    Binary operator arithmetic works on uncompiled types
    
    Until now, if the inputs to the binary operators were an uncompiled type,
    `gal_data_arithmetic' would stop with an error. But now, there are checks
    before the actual operation and if the types of any of the inputs or output
    are not compiled, they will be convereted to an existing larger datatype.
    
    In `configure.ac', the check to set the printed value in the configure
    message was moved immediately after the value is set, so nothing in the
    middle can possibly change it, making the printed value more trustable.
    
    The new function `gal_data_type_string' was also created so it will be easy
    to print readable debugging messages, but it can be used in other contexts
    too.
---
 configure.ac                 |  22 ++--
 doc/gnuastro.texi            |  52 ++++----
 lib/data-arithmetic-binary.h | 279 +++++++++++++++++++++++++++++++++++++++----
 lib/data-arithmetic.c        |   8 +-
 lib/data.c                   |  74 +++++++++++-
 lib/gnuastro/data.h          |   5 +-
 6 files changed, 378 insertions(+), 62 deletions(-)

diff --git a/configure.ac b/configure.ac
index 2bda5cc..0ae190c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -296,10 +296,10 @@ AC_ARG_ENABLE([bin-op-uchar],
                     [Native binary operators on unsigned char data.])],
              [AS_IF([test "x$enable_bin_op_uchar" != xno],
                      [binop_uchar=1], [binop_uchar=0])], [])
+AS_IF([test "x$binop_uchar" != x0], [binoptprint=yes], [binoptprint=no])
 AC_DEFINE_UNQUOTED([GAL_CONFIG_BIN_OP_UCHAR], [$binop_uchar],
                    [Native binary operations on unsigned char data.])
 AC_SUBST(HAVE_BIN_OP_UCHAR, [$binop_uchar])
-AS_IF([test "x$binop_uchar" != x0], [binoptprint=yes], [binoptprint=no])
 AC_MSG_RESULT($binoptprint)
 
 AC_MSG_CHECKING(whether to compile char binary data operators)
@@ -308,10 +308,10 @@ AC_ARG_ENABLE([bin-op-char],
                     [Native binary operations on char data.])],
              [AS_IF([test "x$enable_bin_op_char" != xno],
                      [binop_char=1], [binop_char=0])], [])
+AS_IF([test "x$binop_char" != x0], [binoptprint=yes], [binoptprint=no])
 AC_DEFINE_UNQUOTED([GAL_CONFIG_BIN_OP_CHAR], [$binop_char],
                    [Native binary operations on char data.])
 AC_SUBST(HAVE_BIN_OP_CHAR, [$binop_char])
-AS_IF([test "x$binop_char" != x0], [binoptprint=yes], [binoptprint=no])
 AC_MSG_RESULT($binoptprint)
 
 AC_MSG_CHECKING(whether to compile unsigned short binary data operators)
@@ -320,10 +320,10 @@ AC_ARG_ENABLE([bin-op-ushort],
                     [Native binary operators on unsigned short data.])],
              [AS_IF([test "x$enable_bin_op_ushort" != xno],
                      [binop_ushort=1], [binop_ushort=0])], [])
+AS_IF([test "x$binop_ushort" != x0], [binoptprint=yes], [binoptprint=no])
 AC_DEFINE_UNQUOTED([GAL_CONFIG_BIN_OP_USHORT], [$binop_ushort],
                    [Native binary operations on unsigned short data.])
 AC_SUBST(HAVE_BIN_OP_USHORT, [$binop_ushort])
-AS_IF([test "x$binop_ushort" != x0], [binoptprint=yes], [binoptprint=no])
 AC_MSG_RESULT($binoptprint)
 
 AC_MSG_CHECKING(whether to compile short binary data operators)
@@ -332,10 +332,10 @@ AC_ARG_ENABLE([bin-op-short],
                     [Native binary operations on short data.])],
              [AS_IF([test "x$enable_bin_op_short" != xno],
                      [binop_short=1], [binop_short=0])], [])
+AS_IF([test "x$binop_short" != x0], [binoptprint=yes], [binoptprint=no])
 AC_DEFINE_UNQUOTED([GAL_CONFIG_BIN_OP_SHORT], [$binop_short],
                    [Native binary operations on short data.])
 AC_SUBST(HAVE_BIN_OP_SHORT, [$binop_short])
-AS_IF([test "x$binop_short" != x0], [binoptprint=yes], [binoptprint=no])
 AC_MSG_RESULT($binoptprint)
 
 AC_MSG_CHECKING(whether to compile unsigned int binary data operators)
@@ -344,10 +344,10 @@ AC_ARG_ENABLE([bin-op-uint],
                     [Native binary operators on unsigned int data.])],
              [AS_IF([test "x$enable_bin_op_uint" != xno],
                      [binop_uint=1], [binop_uint=0])], [])
+AS_IF([test "x$binop_uint" != x0], [binoptprint=yes], [binoptprint=no])
 AC_DEFINE_UNQUOTED([GAL_CONFIG_BIN_OP_UINT], [$binop_uint],
                    [Native binary operations on unsigned int data.])
 AC_SUBST(HAVE_BIN_OP_UINT, [$binop_uint])
-AS_IF([test "x$binop_uint" != x0], [binoptprint=yes], [binoptprint=no])
 AC_MSG_RESULT($binoptprint)
 
 AC_MSG_CHECKING(whether to compile int binary data operators)
@@ -356,10 +356,10 @@ AC_ARG_ENABLE([bin-op-int],
                     [Native binary operations on int data.])],
              [AS_IF([test "x$enable_bin_op_int" != xno],
                      [binop_int=1], [binop_int=0])], [])
+AS_IF([test "x$binop_int" != x0], [binoptprint=yes], [binoptprint=no])
 AC_DEFINE_UNQUOTED([GAL_CONFIG_BIN_OP_INT], [$binop_int],
                    [Native binary operations on int data.])
 AC_SUBST(HAVE_BIN_OP_INT, [$binop_int])
-AS_IF([test "x$binop_int" != x0], [binoptprint=yes], [binoptprint=no])
 AC_MSG_RESULT($binoptprint)
 
 AC_MSG_CHECKING(whether to compile unsigned long binary data operators)
@@ -368,10 +368,10 @@ AC_ARG_ENABLE([bin-op-ulong],
                     [Native binary operators on unsigned long data.])],
              [AS_IF([test "x$enable_bin_op_ulong" != xno],
                      [binop_ulong=1], [binop_ulong=0])], [])
+AS_IF([test "x$binop_ulong" != x0], [binoptprint=yes], [binoptprint=no])
 AC_DEFINE_UNQUOTED([GAL_CONFIG_BIN_OP_ULONG], [$binop_ulong],
                    [Native binary operations on unsigned long data.])
 AC_SUBST(HAVE_BIN_OP_ULONG, [$binop_ulong])
-AS_IF([test "x$binop_ulong" != x0], [binoptprint=yes], [binoptprint=no])
 AC_MSG_RESULT($binoptprint)
 
 AC_MSG_CHECKING(whether to compile long native binary data operators)
@@ -380,10 +380,10 @@ AC_ARG_ENABLE([bin-op-long],
                     [Native binary operations on long data.])],
              [AS_IF([test "x$enable_bin_op_long" != xno],
                      [binop_long=1], [binop_long=0])], [])
+AS_IF([test "x$binop_long" != x0], [binoptprint=yes], [binoptprint=no])
 AC_DEFINE_UNQUOTED([GAL_CONFIG_BIN_OP_LONG], [$binop_long],
                    [Native binary operations on long data.])
 AC_SUBST(HAVE_BIN_OP_LONG, [$binop_long])
-AS_IF([test "x$binop_long" != x0], [binoptprint=yes], [binoptprint=no])
 AC_MSG_RESULT($binoptprint)
 
 AC_MSG_CHECKING(whether to compile LONGLONG native binary data operators)
@@ -392,10 +392,10 @@ AC_ARG_ENABLE([bin-op-longlong],
                     [Native binary operations on LONGLONG data.])],
              [AS_IF([test "x$enable_bin_op_longlong" != xno],
                      [binop_longlong=1], [binop_longlong=0])], [])
+AS_IF([test "x$binop_longlong" != x0], [binoptprint=yes], [binoptprint=no])
 AC_DEFINE_UNQUOTED([GAL_CONFIG_BIN_OP_LONGLONG], [$binop_longlong],
                    [Native binary operations on LONGLONG data.])
 AC_SUBST(HAVE_BIN_OP_LONG, [$binop_longlong])
-AS_IF([test "x$binop_longlong" != x0], [binoptprint=yes], [binoptprint=no])
 AC_MSG_RESULT($binoptprint)
 
 AC_MSG_CHECKING(whether to compile float native binary data operators)
@@ -404,10 +404,10 @@ AC_ARG_ENABLE([bin-op-float],
                     [Native binary operations on float data.])],
              [AS_IF([test "x$enable_bin_op_float" != xno],
                      [binop_float=1], [binop_float=0])], [])
+AS_IF([test "x$binop_float" != x0], [binoptprint=yes], [binoptprint=no])
 AC_DEFINE_UNQUOTED([GAL_CONFIG_BIN_OP_FLOAT], [$binop_float],
                    [Native binary operations on float data.])
 AC_SUBST(HAVE_BIN_OP_FLOAT, [$binop_float])
-AS_IF([test "x$binop_float" != x0], [binoptprint=yes], [binoptprint=no])
 AC_MSG_RESULT($binoptprint)
 
 AC_MSG_CHECKING(whether to compile double native binary data operators)
@@ -416,10 +416,10 @@ AC_ARG_ENABLE([bin-op-double],
                     [Native binary operations on double data.])],
              [AS_IF([test "x$enable_bin_op_double" != xno],
                      [binop_double=1], [binop_double=0])], [])
+AS_IF([test "x$binop_double" != x0], [binoptprint=yes], [binoptprint=no])
 AC_DEFINE_UNQUOTED([GAL_CONFIG_BIN_OP_DOUBLE], [$binop_double],
                    [Native binary operations on double data.])
 AC_SUBST(HAVE_BIN_OP_DOUBLE, [$binop_double])
-AS_IF([test "x$binop_double" != x0], [binoptprint=yes], [binoptprint=no])
 AC_MSG_RESULT($binoptprint)
 
 
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index 10f574d..4a6bbb7 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -3142,19 +3142,21 @@ Enable the binary data-structure operators to work 
natively on the
 respective type of data (@option{u} stands for unsigned types). Some types
 are compiled by default, to disable them (or disable any other type),
 either run @option{enable-bin-op-TYPE=no}, or run
address@hidden You can tell which types are acceptable by
-default by inspecting the messages of @command{./configure}.
-
-Binary operators are some of the most common operators to the
address@hidden program or the @code{gal_data_arithmetic} function in
address@hidden library}. To operate most efficiently (as fast as possible
-without using too much of the system resources like memory or CPU), it is
-best to rely on the native types of the input data. For example, if you
-want to add an integer array with a floating point array, using the native
-types, means using the C language's internal type conversion. If we don't
-use the native conversion, then the integer array has to be converted to
-the same type as the floating point array to do the conversion. This will
-consume memory and CPU resources and ultimately slow down the running.
address@hidden You can tell which types are configured by
+default by inspecting the messages of @command{./configure} without any of
+these options.
+
+Binary operators, for example @code{+} or @code{>} (greater than), are some
+of the most common operators to the @ref{Arithmetic} program or the
address@hidden function in @ref{Gnuastro library}. To operate
+most efficiently (as fast as possible without using extra memory or CPU
+resources), it is best to rely on the native types of the input data. For
+example, if you want to add an integer array with a floating point array,
+using the native types, means relying the system's internal type conversion
+for each array element. If we don't use the native conversion, then the
+integer array has to be converted to the same type as the floating point
+array to do the conversion. This will consume memory and CPU resources and
+ultimately slow down the running.
 
 There are many binary operators and in order to have them operate natively
 on of each of the above types, the compiler has to prepare for many
@@ -3163,16 +3165,20 @@ address@hidden can also greatly increase the file size 
of the
 library, from a few hundred kilobytes to a few megabytes} (when you run
 @command{make}). For example, with only one type, compilation will take
 less than a minute, but if you enable all types, it can take upto an hour
-or more depending on your computer. However, this time that is invested
-once at compilation time will result in great profits each time you run
-Gnuastro programs or libraries, because no internal type conversion will be
-necessary.
-
-Therefore, if you commonly work with very specific data-types, you can add
-them (and remove the default ones you don't need them) with these options
-to speed up your work. Alternatively, GNU/Linux distribution package
-managers who compile once (for all the users who just download the compiled
-programs and executables), can enable all types to help their users.
+or more depending on your computer. However, the profits of significant
+investment at compilation time (only once) will be directly felt each time
+you run Gnuastro programs or libraries, because no internal type conversion
+will be necessary.
+
+If you commonly work with very specific data-types, you can add them (and
+remove the default ones you don't need) with these options to speed up your
+work. Alternatively, GNU/Linux distribution package managers who compile
+once (for a large audience of users who just download the compiled programs
+and executables), can enable all types to help their users. Since the
+outputs of comparison operators are @code{unsigned char} type and most
+astronomical datasets are in @code{float}, the recommended minimum enabled
+types are @code{unsigned char} and @code{float}.
+
 
 
 
diff --git a/lib/data-arithmetic-binary.h b/lib/data-arithmetic-binary.h
index 241d86c..cb08758 100644
--- a/lib/data-arithmetic-binary.h
+++ b/lib/data-arithmetic-binary.h
@@ -33,9 +33,9 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 /************************************************************************/
 #if GAL_CONFIG_BIN_OP_UCHAR == 1
 #define BINARY_LEFT_RIGHT_DONE_UCHAR(LT, RT, OP)                        \
-  case GAL_DATA_TYPE_UCHAR:                                             \
-    BINARY_OPERATOR_FOR_TYPE(LT, RT, unsigned char, OP);                \
-    break;
+    case GAL_DATA_TYPE_UCHAR:                                           \
+      BINARY_OPERATOR_FOR_TYPE(LT, RT, unsigned char, OP);              \
+      break;
 #define BINARY_LEFT_DONE_UCHAR(LT, OP)                                  \
     case GAL_DATA_TYPE_UCHAR:                                           \
       BINARY_LEFT_RIGHT_DONE(LT, unsigned char, OP);                    \
@@ -304,8 +304,186 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 /************************************************************************/
-/*************          Binary conversion macros        *****************/
+/*************       Macros for specifying the type     *****************/
 /************************************************************************/
+
+#define BINARY_TYPE_FOR_CONVERT_TO_COMPILED_TYPE(intype)                \
+  ntype=0;                                                              \
+  switch(intype)                                                        \
+    {                                                                   \
+    case GAL_DATA_TYPE_UCHAR:                                           \
+      if(GAL_CONFIG_BIN_OP_UCHAR) ntype=GAL_DATA_TYPE_UCHAR;            \
+      else                                                              \
+        {                                                               \
+          if     (GAL_CONFIG_BIN_OP_USHORT)   ntype=GAL_DATA_TYPE_USHORT;  \
+          else if(GAL_CONFIG_BIN_OP_SHORT)    ntype=GAL_DATA_TYPE_SHORT;   \
+          else if(GAL_CONFIG_BIN_OP_UINT)     ntype=GAL_DATA_TYPE_UINT;    \
+          else if(GAL_CONFIG_BIN_OP_INT)      ntype=GAL_DATA_TYPE_INT;     \
+          else if(GAL_CONFIG_BIN_OP_ULONG)    ntype=GAL_DATA_TYPE_ULONG;   \
+          else if(GAL_CONFIG_BIN_OP_LONG)     ntype=GAL_DATA_TYPE_LONG;    \
+          else if(GAL_CONFIG_BIN_OP_LONGLONG) ntype=GAL_DATA_TYPE_LONGLONG;\
+          else if(GAL_CONFIG_BIN_OP_FLOAT)    ntype=GAL_DATA_TYPE_FLOAT;   \
+          else if(GAL_CONFIG_BIN_OP_DOUBLE)   ntype=GAL_DATA_TYPE_DOUBLE;  \
+        }                                                               \
+      break;                                                            \
+                                                                        \
+    case GAL_DATA_TYPE_CHAR:                                            \
+      if(GAL_CONFIG_BIN_OP_CHAR) ntype=GAL_DATA_TYPE_CHAR;              \
+      else                                                              \
+        {                                                               \
+          if     (GAL_CONFIG_BIN_OP_SHORT)    ntype=GAL_DATA_TYPE_SHORT;   \
+          else if(GAL_CONFIG_BIN_OP_INT)      ntype=GAL_DATA_TYPE_INT;     \
+          else if(GAL_CONFIG_BIN_OP_LONG)     ntype=GAL_DATA_TYPE_LONG;    \
+          else if(GAL_CONFIG_BIN_OP_LONGLONG) ntype=GAL_DATA_TYPE_LONGLONG;\
+          else if(GAL_CONFIG_BIN_OP_FLOAT)    ntype=GAL_DATA_TYPE_FLOAT;   \
+          else if(GAL_CONFIG_BIN_OP_DOUBLE)   ntype=GAL_DATA_TYPE_DOUBLE;  \
+        }                                                               \
+      break;                                                            \
+                                                                        \
+    case GAL_DATA_TYPE_USHORT:                                          \
+      if(GAL_CONFIG_BIN_OP_USHORT) ntype=GAL_DATA_TYPE_USHORT;          \
+      else                                                              \
+        {                                                               \
+          if     (GAL_CONFIG_BIN_OP_UINT)     ntype=GAL_DATA_TYPE_UINT;    \
+          else if(GAL_CONFIG_BIN_OP_INT)      ntype=GAL_DATA_TYPE_INT;     \
+          else if(GAL_CONFIG_BIN_OP_ULONG)    ntype=GAL_DATA_TYPE_ULONG;   \
+          else if(GAL_CONFIG_BIN_OP_LONG)     ntype=GAL_DATA_TYPE_LONG;    \
+          else if(GAL_CONFIG_BIN_OP_LONGLONG) ntype=GAL_DATA_TYPE_LONGLONG;\
+          else if(GAL_CONFIG_BIN_OP_FLOAT)    ntype=GAL_DATA_TYPE_FLOAT;   \
+          else if(GAL_CONFIG_BIN_OP_DOUBLE)   ntype=GAL_DATA_TYPE_DOUBLE;  \
+        }                                                               \
+      break;                                                            \
+                                                                        \
+    case GAL_DATA_TYPE_SHORT:                                           \
+      if(GAL_CONFIG_BIN_OP_SHORT) ntype=GAL_DATA_TYPE_SHORT;            \
+      else                                                              \
+        {                                                               \
+          if     (GAL_CONFIG_BIN_OP_INT)      ntype=GAL_DATA_TYPE_INT;     \
+          else if(GAL_CONFIG_BIN_OP_LONG)     ntype=GAL_DATA_TYPE_LONG;    \
+          else if(GAL_CONFIG_BIN_OP_LONGLONG) ntype=GAL_DATA_TYPE_LONGLONG;\
+          else if(GAL_CONFIG_BIN_OP_FLOAT)    ntype=GAL_DATA_TYPE_FLOAT;   \
+          else if(GAL_CONFIG_BIN_OP_DOUBLE)   ntype=GAL_DATA_TYPE_DOUBLE;  \
+        }                                                               \
+      break;                                                            \
+                                                                        \
+    case GAL_DATA_TYPE_UINT:                                            \
+      if(GAL_CONFIG_BIN_OP_UINT) ntype=GAL_DATA_TYPE_UINT;              \
+      else                                                              \
+        {                                                               \
+          if     (GAL_CONFIG_BIN_OP_ULONG)    ntype=GAL_DATA_TYPE_ULONG;   \
+          else if(GAL_CONFIG_BIN_OP_LONG)     ntype=GAL_DATA_TYPE_LONG;    \
+          else if(GAL_CONFIG_BIN_OP_LONGLONG) ntype=GAL_DATA_TYPE_LONGLONG;\
+          else if(GAL_CONFIG_BIN_OP_FLOAT)    ntype=GAL_DATA_TYPE_FLOAT;   \
+          else if(GAL_CONFIG_BIN_OP_DOUBLE)   ntype=GAL_DATA_TYPE_DOUBLE;  \
+        }                                                               \
+      break;                                                            \
+                                                                        \
+    case GAL_DATA_TYPE_INT:                                             \
+      if(GAL_CONFIG_BIN_OP_INT) ntype=GAL_DATA_TYPE_INT;                \
+      else                                                              \
+        {                                                               \
+          if     (GAL_CONFIG_BIN_OP_LONG)     ntype=GAL_DATA_TYPE_LONG;    \
+          else if(GAL_CONFIG_BIN_OP_LONGLONG) ntype=GAL_DATA_TYPE_LONGLONG;\
+          else if(GAL_CONFIG_BIN_OP_FLOAT)    ntype=GAL_DATA_TYPE_FLOAT;   \
+          else if(GAL_CONFIG_BIN_OP_DOUBLE)   ntype=GAL_DATA_TYPE_DOUBLE;  \
+        }                                                               \
+      break;                                                            \
+                                                                        \
+    case GAL_DATA_TYPE_ULONG:                                           \
+      if(GAL_CONFIG_BIN_OP_ULONG) ntype=GAL_DATA_TYPE_ULONG;            \
+      else                                                              \
+        {                                                               \
+          if     (GAL_CONFIG_BIN_OP_LONGLONG) ntype=GAL_DATA_TYPE_LONGLONG;\
+          else if(GAL_CONFIG_BIN_OP_FLOAT)    ntype=GAL_DATA_TYPE_FLOAT;   \
+          else if(GAL_CONFIG_BIN_OP_DOUBLE)   ntype=GAL_DATA_TYPE_DOUBLE;  \
+        }                                                               \
+      break;                                                            \
+                                                                        \
+    case GAL_DATA_TYPE_LONG:                                            \
+      if(GAL_CONFIG_BIN_OP_LONG) ntype=GAL_DATA_TYPE_LONG;              \
+      else                                                              \
+        {                                                               \
+          if     (GAL_CONFIG_BIN_OP_LONGLONG) ntype=GAL_DATA_TYPE_LONGLONG;\
+          else if(GAL_CONFIG_BIN_OP_FLOAT)    ntype=GAL_DATA_TYPE_FLOAT;   \
+          else if(GAL_CONFIG_BIN_OP_DOUBLE)   ntype=GAL_DATA_TYPE_DOUBLE;  \
+        }                                                               \
+      break;                                                            \
+                                                                        \
+    case GAL_DATA_TYPE_LONGLONG:                                        \
+      if(GAL_CONFIG_BIN_OP_LONGLONG) ntype=GAL_DATA_TYPE_LONGLONG;      \
+      else                                                              \
+        {                                                               \
+          if     (GAL_CONFIG_BIN_OP_FLOAT)    ntype=GAL_DATA_TYPE_FLOAT;  \
+          else if(GAL_CONFIG_BIN_OP_DOUBLE)   ntype=GAL_DATA_TYPE_DOUBLE; \
+        }                                                               \
+      break;                                                            \
+                                                                        \
+    case GAL_DATA_TYPE_FLOAT:                                           \
+      if(GAL_CONFIG_BIN_OP_FLOAT) ntype=GAL_DATA_TYPE_FLOAT;            \
+      else                                                              \
+        {                                                               \
+          if     (GAL_CONFIG_BIN_OP_DOUBLE)   ntype=GAL_DATA_TYPE_DOUBLE; \
+        }                                                               \
+      break;                                                            \
+                                                                        \
+    case GAL_DATA_TYPE_DOUBLE:                                          \
+      if(GAL_CONFIG_BIN_OP_DOUBLE) ntype=GAL_DATA_TYPE_DOUBLE;          \
+      break;                                                            \
+                                                                        \
+    default:                                                            \
+      error(EXIT_FAILURE, 0, "type %d not recognized in "               \
+            "BINARY_CONVERT_TO_COMPILED_TYPE", intype);                 \
+    }
+
+
+
+
+
+/* Note that for signed types, we won't be considering the unsigned types
+   of the larger types. */
+#define BINARY_CONVERT_TO_COMPILED_TYPE(in, out)                        \
+                                                                        \
+  /* Initialize the values that will be set. */                         \
+  out=NULL;                                                             \
+                                                                        \
+  /* Set the values. */                                                 \
+  BINARY_TYPE_FOR_CONVERT_TO_COMPILED_TYPE(in->type);                   \
+                                                                        \
+  /* If type is not compiled, then convert the dataset to the */        \
+  /* first compiled larger type. */                                     \
+  if(in->type==ntype)                                                   \
+    out=in;                                                             \
+  else                                                                  \
+    {                                                                   \
+      if(ntype)                                                         \
+        {                                                               \
+          out=gal_data_copy_to_new_type(in, ntype);                     \
+          if(flags & GAL_DATA_ARITH_FREE)                               \
+            { gal_data_free(in); in=NULL; }                             \
+        }                                                               \
+      else                                                              \
+        {                                                               \
+          char *typestring=gal_data_type_string(in->type);              \
+          error(EXIT_FAILURE, 0, "The given %s type data given to "     \
+                "binary operators is not compiled for native operation "\
+                "and no larger types are compiled either.\n\nThe "      \
+                "largest type (which can act as a fallback for any "    \
+                "input type is double, so configure Gnuastro again "    \
+                "with `--enable-bin-op-double' to not get this error "  \
+                "any more. However, if you commonly deal with %s type " \
+                "data, also enable %s with a similar option at "        \
+                "configure time to greatly increase running time and "  \
+                "avoid unnecessary RAM and CPU resources. Run"          \
+                "`./configure --help' in Gnuastro's top source "        \
+                "directory (after unpacking the tarball) for the full " \
+                "list of options", typestring, typestring, typestring); \
+        }                                                               \
+    }
+
+
+
+
+
 #define BINARY_OPERATOR_FOR_TYPE(LT, RT, OT, OP){                       \
     LT *la=l->array;                                                    \
     RT *ra=r->array;                                                    \
@@ -369,33 +547,71 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/************************************************************************/
+/*************              Top level macro             *****************/
+/************************************************************************/
 /* Prepare the inputs and output for binary operations and do the job.*/
 #define BINARY_INTERNAL(OP, OUT_TYPE) {                                 \
                                                                         \
   /* Read the variable arguments. */                                    \
-  gal_data_t *l, *r;                                                    \
-  l = va_arg(va, gal_data_t *);                                         \
-  r = va_arg(va, gal_data_t *);                                         \
+  /* `lo' and `ro' keep the original data, in case their type isn't */  \
+  /* built (based on configure options are configure time). */          \
+  size_t out_size, minmapsize;                                          \
+  int ntype, otype, final_otype;                                        \
+  gal_data_t *l, *r, *lo, *ro, *tmp_o;                                  \
+                                                                        \
+                                                                        \
+  /* Prepare original data structures from the input arguments. */      \
+  lo = va_arg(va, gal_data_t *);                                        \
+  ro = va_arg(va, gal_data_t *);                                        \
                                                                         \
                                                                         \
   /* Simple sanity check on the input sizes */                          \
-  if( !( (flags & GAL_DATA_ARITH_NUMOK) && (l->size==1 || r->size==1))  \
-      && gal_data_dsize_is_different(l, r) )                            \
-    error(EXIT_FAILURE, 0, "The datasets don't have the same "          \
-          "dimension/size");                                            \
+  if( !( (flags & GAL_DATA_ARITH_NUMOK) && (lo->size==1 || ro->size==1))\
+      && gal_data_dsize_is_different(lo, ro) )                          \
+    error(EXIT_FAILURE, 0, "ini BINARY_INTERNAL, the input datasets "   \
+          "don't have the same dimension/size");                        \
                                                                         \
                                                                         \
   /* Set the output type and size. */                                   \
-  out_type = OUT_TYPE ? OUT_TYPE : gal_data_out_type(l, r);             \
-  out_size = l->size > r->size ? l->size : r->size;                     \
+  minmapsize = ( lo->minmapsize < ro->minmapsize                        \
+                 ? lo->minmapsize : ro->minmapsize );                   \
+  out_size = lo->size > ro->size ? lo->size : ro->size;                 \
+  final_otype = OUT_TYPE ? OUT_TYPE : gal_data_out_type(lo, ro);        \
+                                                                        \
+                                                                        \
+  /* Make sure the input arrays have one of the compiled types. */      \
+  BINARY_CONVERT_TO_COMPILED_TYPE(lo, l);                               \
+  BINARY_CONVERT_TO_COMPILED_TYPE(ro, r);                               \
+                                                                        \
+                                                                        \
+  /* Temporary output type (in case its type isn't compiled). */        \
+  /* Note that the final output of this macro is put in `ntype'. */     \
+  BINARY_TYPE_FOR_CONVERT_TO_COMPILED_TYPE(final_otype);                \
+  otype=ntype;                                                          \
                                                                         \
                                                                         \
   /* If we want inplace output, set the output pointer to one input. */ \
   /* Note that the output type can be different from both inputs.    */ \
   if(flags & GAL_DATA_ARITH_INPLACE)                                    \
     {                                                                   \
-      if(l->type==out_type && out_size==l->size)        o = l;          \
-      else if(r->type==out_type && out_size==r->size)   o = r;          \
+      if     (l->type==otype && out_size==l->size)   o = l;             \
+      else if(r->type==otype && out_size==r->size)   o = r;             \
     }                                                                   \
                                                                         \
                                                                         \
@@ -406,12 +622,11 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
   /* So we just have to choose the smaller minmapsize of the two to */  \
   /* decide if the output array should be in RAM or not. */             \
   if(o==NULL)                                                           \
-    o = gal_data_alloc(NULL, out_type,                                  \
+    o = gal_data_alloc(NULL, otype,                                     \
                        l->size>1 ? l->ndim  : r->ndim,                  \
                        l->size>1 ? l->dsize : r->dsize,                 \
-                       l->size>1 ? l->wcs : r->wcs, 0,                  \
-                       ( l->minmapsize<r->minmapsize                    \
-                         ? l->minmapsize : r->minmapsize ) );           \
+                       l->size>1 ? l->wcs : r->wcs, 0, minmapsize );    \
+                                                                        \
                                                                         \
   /* Do the operations based on the different types. */                 \
   switch(l->type)                                                       \
@@ -434,13 +649,37 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
             "for l->type in BINARY_MULTISWITCH", l->type);              \
     }                                                                   \
                                                                         \
-  /* Clean up. */                                                       \
+                                                                        \
+  /* Clean up. Note that if the input arrays can be freed, and any of */\
+  /* right or left arrays needed conversion, */                         \
+  /*`BINARY_CONVERT_TO_COMPILED_TYPE' has already freed the input */    \
+  /* arrays, and we only have `r' and `l' allocated in any case. */     \
+  /* Alternatively, when the inputs shouldn't be freed, the only */     \
+  /* allocated spaces are the `r' and `l' arrays if their types */      \
+  /* weren't compiled for binary operations, we can tell this from */   \
+  /* the pointers: if they are different from the original pointers, */ \
+  /* they were allocated. */                                            \
   if(flags & GAL_DATA_ARITH_FREE)                                       \
     {                                                                   \
       if     (o==l)       gal_data_free(r);                             \
       else if(o==r)       gal_data_free(l);                             \
       else              { gal_data_free(l); gal_data_free(r); }         \
     }                                                                   \
+  else                                                                  \
+    {                                                                   \
+      if(l!=lo)           gal_data_free(l);                             \
+      if(r!=ro)           gal_data_free(r);                             \
+    }                                                                   \
+                                                                        \
+                                                                        \
+  /* In case otype and final_otype aren't equal, we need to convert */  \
+  /* the output data structure to the proper type. */                   \
+  if(otype!=final_otype)                                                \
+    {                                                                   \
+      tmp_o=gal_data_copy_to_new_type(o, final_otype);                  \
+      gal_data_free(o);                                                 \
+      o=tmp_o;                                                          \
+    }                                                                   \
 }
 
 
diff --git a/lib/data-arithmetic.c b/lib/data-arithmetic.c
index 77acfa2..1cc7794 100644
--- a/lib/data-arithmetic.c
+++ b/lib/data-arithmetic.c
@@ -39,8 +39,6 @@ gal_data_t *
 gal_data_arithmetic(int operator, unsigned char flags, ...)
 {
   va_list va;
-  int out_type;
-  size_t out_size;
   gal_data_t *o=NULL;
 
   /* Prepare the variable arguments (starting after the flags argument). */
@@ -50,9 +48,9 @@ gal_data_arithmetic(int operator, unsigned char flags, ...)
   switch(operator)
     {
     case GAL_DATA_OPERATOR_PLUS:     BINARY_INTERNAL(+, 0); break;
-    case GAL_DATA_OPERATOR_MINUS:    BINARY_INTERNAL(-,  0); break;
-    case GAL_DATA_OPERATOR_MULTIPLY: BINARY_INTERNAL(*,  0); break;
-    case GAL_DATA_OPERATOR_DIVIDE:   BINARY_INTERNAL(/,  0); break;
+    case GAL_DATA_OPERATOR_MINUS:    BINARY_INTERNAL(-, 0); break;
+    case GAL_DATA_OPERATOR_MULTIPLY: BINARY_INTERNAL(*, 0); break;
+    case GAL_DATA_OPERATOR_DIVIDE:   BINARY_INTERNAL(/, 0); break;
 
     case GAL_DATA_OPERATOR_LT:  BINARY_INTERNAL(<,  GAL_DATA_TYPE_UCHAR); 
break;
     case GAL_DATA_OPERATOR_LE:  BINARY_INTERNAL(<=, GAL_DATA_TYPE_UCHAR); 
break;
diff --git a/lib/data.c b/lib/data.c
index 155c93c..87a8fcb 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -45,7 +45,6 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 
-
 /*********************************************************************/
 /*************          Size and allocation        *******************/
 /*********************************************************************/
@@ -878,8 +877,79 @@ gal_data_blank_to_value(gal_data_t *data, void *value)
 
 
 /*************************************************************
- **************             Copy           ***************
+ **************       Types and copying       ***************
  *************************************************************/
+char *
+gal_data_type_string(int type)
+{
+  switch(type)
+    {
+    case GAL_DATA_TYPE_BIT:
+      return "bit";
+
+    case GAL_DATA_TYPE_UCHAR:
+      return "unsigned char";
+
+      /* CFITSIO says "int for keywords, char for table columns". Here we
+         are only assuming table columns. So in practice this also applies
+         to TSBYTE.*/
+    case GAL_DATA_TYPE_CHAR: case GAL_DATA_TYPE_LOGICAL:
+      return "char";
+
+    case GAL_DATA_TYPE_STRING:
+      return "string";
+
+    case GAL_DATA_TYPE_USHORT:
+      return "unsigned short";
+
+    case GAL_DATA_TYPE_SHORT:
+      return "short";
+
+    case GAL_DATA_TYPE_UINT:
+      return "unsigned int";
+
+    case GAL_DATA_TYPE_INT:
+      return "int";
+
+    case GAL_DATA_TYPE_ULONG:
+      return "unsigned long";
+
+    case GAL_DATA_TYPE_LONG:
+      return "long";
+
+    case GAL_DATA_TYPE_LONGLONG:
+      return "LONGLONG";
+
+    case GAL_DATA_TYPE_FLOAT:
+      return "float";
+
+    case GAL_DATA_TYPE_DOUBLE:
+      return "double";
+
+    case GAL_DATA_TYPE_COMPLEX:
+      return "complex float";
+
+    case GAL_DATA_TYPE_DCOMPLEX:
+      return "complex double";
+
+    default:
+      error(EXIT_FAILURE, 0, "type value of %d not recognized in "
+            "`gal_data_type_string'", type);
+    }
+
+  /* Any of the cases above should return this function, so if control
+     reaches here, there is a bug. */
+  error(EXIT_FAILURE, 0, "a bug! Please contact us at %s so we can address "
+        "the problem. For some reason control has reached the end of "
+        "the `gal_data_type_string' function. This must not happen",
+        PACKAGE_BUGREPORT);
+  return NULL;
+}
+
+
+
+
+
 gal_data_t *
 gal_data_copy(gal_data_t *in)
 {
diff --git a/lib/gnuastro/data.h b/lib/gnuastro/data.h
index 8545033..dd89444 100644
--- a/lib/gnuastro/data.h
+++ b/lib/gnuastro/data.h
@@ -250,8 +250,11 @@ gal_data_blank_to_value(gal_data_t *data, void *value);
 
 
 /*************************************************************
- **************             Copy               ***************
+ **************       Types and copying        ***************
  *************************************************************/
+char *
+gal_data_type_string(int type);
+
 gal_data_t *
 gal_data_copy(gal_data_t *in);
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]