gnuastro-commits
[Top][All Lists]
Advanced

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

[gnuastro-commits] master b470ee4 023/125: More efficient macro implemen


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master b470ee4 023/125: More efficient macro implementation for binary operators
Date: Sun, 23 Apr 2017 22:36:29 -0400 (EDT)

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

    More efficient macro implementation for binary operators
    
    Previsouly, the macro implementation for the various types of binary
    operators also iterated (with switch expressions) over types for the
    output. However, the output type is determined from the input types or the
    operators, it isn't random. With this commit, this fact is taken into
    account in defining the macros of `data-arithmetic_binary.c' and
    `data_arithmetic_onlyint.c'. With the full set of types enabled,
    compilation time on my system decreased from about 40 minutes to 17
    minutes.
    
    The book was also modified/updated/edited to better explain the issues.
---
 doc/gnuastro.texi             | 194 ++++++-----
 lib/data-arithmetic-binary.c  | 744 ++++++++++++++----------------------------
 lib/data-arithmetic-onlyint.c | 612 +++++++++++-----------------------
 lib/data.c                    | 191 +++++++++++
 lib/gnuastro/data.h           |   5 +
 5 files changed, 735 insertions(+), 1011 deletions(-)

diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index 4e97e3c..7c47b18 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -3140,12 +3140,12 @@ install all the other programs except this one.
 @itemx --enable-bin-op-float
 @itemx --enable-bin-op-double
 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 configured by
-default by inspecting the messages of @command{./configure} without any of
-these options.
+respective type of data (@option{u} stands for unsigned types, see
address@hidden types}). Some are compiled by default, to disable them (or
+disable any other type), either run @option{enable-bin-op-TYPE=no}, or run
address@hidden The final list of enabled/disabled types
+can be inspected in the outputs of @command{./configure} (close to the
+end).
 
 Binary operators, for example @code{+} or @code{>} (greater than), are some
 of the most common operators to the @ref{Arithmetic} program or the
@@ -3154,31 +3154,34 @@ 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.
+for each array element, see @ref{Invoking astarithmetic}. 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 (to copy the integer array into a new float array) and CPU
+(integer types need much less processing) 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
-different conditions. This can greatly slow down the
+on of each of the above types, the compiler has to prepare for all the
+different combinations of these types. This can greatly slow down the
 address@hidden can also greatly increase the file size of the
-library, from a few hundred kilobytes to a few megabytes} (when you run
address@hidden). 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, 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.
+library, from a few hundred kilobytes to a few megabytes.} (when you run
address@hidden). For example, with only one type, @command{make} will
+finish in less than a minute, but if you enable all types, it can take
+roughly half an hour. However, the profits of this one-time investment at
+compilation time will be directly felt (more significantly on large
+images/datasets) 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}.
+If build time is important for you and you commonly work with very specific
+data-types, you can add them (and remove the default ones you don't need)
+with these configuration 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}.
 
 
 
@@ -7407,7 +7410,9 @@ $ astarithmetic in.fits reference.fits 100 gt new.fits 
where
 
 In the example above, any of the @file{in.fits} pixels that has a value in
 @file{reference.fits} greater than @command{100}, will be replaced with the
-corresponding pixel in @file{new.fits}.
+corresponding pixel in @file{new.fits}. Finally, the input operands are
+read and used independently, so you can use the same file more than once as
+any of the operands.
 
 @item bitand
 Bitwise AND operator: only bits with values of 1 in both popped operands
@@ -7502,8 +7507,8 @@ data types.
 is floating point type, blank values are NaN. One aspect of NaN values is
 that by definition they will fail on @emph{any} comparison. Hence both
 equal and not-equal operators will fail when both their operands are NaN!
-The only way to guarantee that select blank pixels is through the
address@hidden operator explained above.
+Therefore, the only way to guarantee selection of blank pixels is through
+the @command{isblank} operator explained above.
 
 One way you can exploit this property of the NaN value to your advantage is
 when you want a fully zero-valued image (even over the blank pixels) based
@@ -7525,9 +7530,10 @@ floating point number in Gnuastro isn't case-sensitive.
 @subsection Invoking Arithmetic
 
 Arithmetic will do pixel to pixel arithmetic operations on the individual
-pixels of input data and/or numbers. Any single element input (number or
-single pixel FITS image file) will be read as a number, the rest of the
-inputs must have the same dimensions. The general template is:
+pixels of input data and/or numbers. Any operand that only has a single
+element (number, or single pixel FITS image file) will be read as a number,
+the rest of the inputs must have the same dimensions. The general template
+is:
 
 @example
 $ astarithmetic [OPTION...] ASTRdata1 [ASTRdata2] OPERATOR ...
@@ -7548,26 +7554,38 @@ $ astarithmetic img1.fits img2.fits img3.fits median    
            \
                 -h0 -h1 -h2 --out=median.fits
 @end example
 
+If the output is an image, and the @option{--output} option is not given,
+automatic output will use the name of the first FITS image encountered to
+generate an output file name, see @ref{Automatic output}. Also, output WCS
+information will be taken from the first input image encountered. If the
+output is a single number, that number will be printed in the standard
+output. See @ref{Reverse polish notation} for the notation used to mix
+operands and operators on the command-line. To ignore certain pixels (see
address@hidden pixels}), you can specify a mask image, see @ref{Mask image}. In
+that case, when reading the first FITS image, all the masked pixels will be
+set to a blank value depending on the type of the image.
+
 Arithmetic accepts two kinds of input: images and numbers. Images are
 considered to be any of the inputs that is a file name of a recognized type
-(see @ref{Arguments}) and has more than one element. Numbers will be read
-into the smallest type that can store them, so @command{-2} will be read as
-a @code{char} type (which is signed on most systems and can thus keep
-negative values), @command{2500} will be read as an @code{unsigned short}
-(all positive numbers will be read as unsigned), while
address@hidden will be read as a @code{double} and
address@hidden will be read as a @code{float}. To force a number to be read as
-float, add a @code{f} after it, so @command{5f} will be added to the stack
-as @code{float} (see @ref{Reverse polish notation}).
+(see @ref{Arguments}) and has more than one element/pixel. Numbers on the
+command-line will be read into the smallest type (see @ref{Data types})
+that can store them, so @command{-2} will be read as a @code{char} type
+(which is signed on most systems and can thus keep negative values),
address@hidden will be read as an @code{unsigned short} (all positive
+numbers will be read as unsigned), while @code{3.1415926535897} will be
+read as a @code{double} and @code{3.14} will be read as a @code{float}. To
+force a number to be read as float, add a @code{f} after it, so
address@hidden will be added to the stack as @code{float} (see @ref{Reverse
+polish notation}).
 
 Unless otherwise stated (in @ref{Arithmetic operators}), the operators can
 deal with multiple datatypes. For example in address@hidden b.fits +}'',
 the image types can be @code{long} and @code{float}. In such cases, C's
-internal type conversion will be used, and the output will have the larger
-type of the two inputs. Unsigned integer types have smaller ranking than
-their signed counterparts and floating points types have higher ranking
-than the integer types. So the internal C type conversions done in the
-example above are equivalent to this piece of C:
+internal type conversion will be used. The output type will be set to the
+higher-ranking type of the two inputs. Unsigned integer types have smaller
+ranking than their signed counterparts and floating point types have higher
+ranking than the integer types. So the internal C type conversions done in
+the example above are equivalent to this piece of C:
 
 @example
 size_t i;
@@ -7580,63 +7598,59 @@ for(i=0;i<100;++i) out[i]=a[i]+b[i];
 Relying on the default C type conversion significantly speeds up the
 processing and also requires less RAM (when using very large
 images). However this great advantage comes at the cost of preparing for
-all the combinations of types while building/compiling Gnuastro, see the
-list of @option{--enable-bin-op-XXXX} options in @ref{Gnuastro configure
-options}. With the full list of types, compilation can take up to an hour
-or more. When a type isn't enabled for binary operators, the input data
-will be internally converted to the smallest larger type that was
-enabled. This can slow down your processing and consume more RAM, so if you
-often deal with data of a specific types, it is much better to make the
-one-time investment at compilation time and reap the benefits each time you
-run Gnuastro.
+all the combinations of types while building/compiling Gnuastro. With the
+full list of CFITSIO types, compilation can take roughly half an
+hour. However, some types are not too common, therfore Gnuastro comes with
+a set of configure time options letting you enable certain types for native
+compilation. You can see the full list of @option{--enable-bin-op-XXXX}
+options in @ref{Gnuastro configure options}.
+
+When a type isn't enabled for native binary operations, the input data will
+be internally converted to the smallest, larger type that was enabled. This
+can slow down your processing (which is faster for smaller/integer types)
+and consume more RAM (to copy the new type), so if you often deal with data
+of a specific types, it is much better to make the one-time investment at
+compilation time and reap the benefits each time you run
+Gnuastro/Arithmetic. Note all arithmetic operations are done by
address@hidden function in @ref{Gnuastro library}, so the
+choice of native binary operator types will affect any program (within
+Gnuastro or outside of it) that uses this function (including Arithmetic).
 
 Some operators can only work on integer types (of any length, for example
 bitwise operators) while others only work on floating point types,
 (currently only the @code{pow} operator). In such cases, if the operand
 type(s) are different an error will be printed and internal conversion
 won't occur. Arithmetic also comes with internal type conversion operators
-which you can use to convert the data into the appropriate format, see
+which you can use to convert the data into the appropriate type, see
 @ref{Arithmetic operators}.
 
-If the output is an image, and the @option{--output} option is not given,
-automatic output will use the name of the first FITS image encountered to
-generate an output file name, see @ref{Automatic output}. Also, output WCS
-information will be taken from the first input image encountered. If the
-output is a single number, that number will be printed in the standard
-output. See @ref{Reverse polish notation} for the notation used to mix
-operands and operators on the command-line. To ignore certain pixels (see
address@hidden pixels}), you can specify a mask image, see @ref{Mask image}. In
-that case, when reading the first FITS image, all the masked pixels will be
-set to a blank value depending on the type of the image.
-
 @cindex Options
 The hyphen (@command{-}) can be used both to specify options (see
 @ref{Options}) and also to specify a negative number which might be
-necessary in your arithmetic. In order to enable you to do this,
-Arithmetic will first parse all the input strings and if the first
-character after a hyphen is a digit, then that hyphen is temporarily
-replaced by the vertical tab character which is not commonly used. The
-arguments are then parsed and these strings will not be specified as
-an option. Then the given arguments are parsed and any vertical tabs
-are replaced back with a hyphen so they can be read as negative
-numbers. So as long as the names of the files you want to work on do
-not start with a vertical tab followed by a digit, there is no
-problem. An important consequence of this implementation is that you
-should not write negative fractions like this: @command{-.3}, instead
-write them as @command{-0.3}.
+necessary in your arithmetic. In order to enable you to do this, Arithmetic
+will first parse all the input strings and if the first character after a
+hyphen is a digit, then that hyphen is temporarily replaced by the vertical
+tab character which is not commonly used. The arguments are then parsed and
+these strings will not be specified as an option. Then the given arguments
+are parsed and any vertical tabs are replaced back with a hyphen so they
+can be read as negative numbers. Therefore, as long as the names of the
+files you want to work on, don't start with a vertical tab followed by a
+digit, there is no problem. An important consequence of this implementation
+is that you should not write negative fractions like this: @command{-.3},
+instead write them as @command{-0.3}.
 
 @cindex AWK
 @cindex GNU AWK
-Without any images, Arithmetic will act like a simple calculator and
-print the resulting output number on the standard output like the
-first example above. If you really want such calculator operations on
-the command-line, AWK (GNU AWK is the most common implementation) is
-much faster, easier and much more powerful. For example, the numerical
-one-line example above can be done with the following command. In
-general AWK is a fantastic tool and GNU AWK has a wonderful manual
-(@url{https://www.gnu.org/software/gawk/manual/}). So if you confront
-situations like this a lot or have to work with large text
-tables/catalogs, be sure to checkout AWK and simplify your life.
+Without any images, Arithmetic will act like a simple calculator and print
+the resulting output number on the standard output like the first example
+above. If you really want such calculator operations on the command-line,
+AWK (GNU AWK is the most common implementation) is much faster, easier and
+much more powerful. For example, the numerical one-line example above can
+be done with the following command. In general AWK is a fantastic tool and
+GNU AWK has a wonderful manual
+(@url{https://www.gnu.org/software/gawk/manual/}). So if you often confront
+situations like this, or have to work with large text tables/catalogs, be
+sure to checkout AWK and simplify your life.
 
 @example
 $ echo "" | awk '@{print (10.32-3.84)address@hidden'
diff --git a/lib/data-arithmetic-binary.c b/lib/data-arithmetic-binary.c
index 8c8e8ea..d53c06a 100644
--- a/lib/data-arithmetic-binary.c
+++ b/lib/data-arithmetic-binary.c
@@ -28,30 +28,27 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <stdlib.h>
 
 #include <gnuastro/data.h>
-#include <data-arithmetic-binary.h>
+
+
+
 
 
 
 /************************************************************************/
-/*************      Possibly set binary types to convert    *************/
+/*************            Native type macros            *****************/
 /************************************************************************/
 #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;
-#define BINARY_LEFT_DONE_UCHAR(LT, OP)                                  \
-    case GAL_DATA_TYPE_UCHAR:                                           \
-      BINARY_LEFT_RIGHT_DONE(LT, unsigned char, OP);                    \
-      break;
-#define BINARY_MULTISWITCH_UCHAR(OP)                                    \
-    case GAL_DATA_TYPE_UCHAR:                                           \
-      BINARY_LEFT_DONE(unsigned char, OP);                              \
-      break;
+#define BINARY_LT_IS_UCHAR                                         \
+  case GAL_DATA_TYPE_UCHAR:                                        \
+    BINARY_LT_SET(unsigned char);                                  \
+    break;
+#define BINARY_LT_SET_RT_IS_UCHAR(LT)                              \
+  case GAL_DATA_TYPE_UCHAR:                                        \
+    BINARY_RT_LT_SET(unsigned char, LT);                           \
+    break;
 #else
-#define BINARY_LEFT_RIGHT_DONE_UCHAR(LT, RT, OP)
-#define BINARY_LEFT_DONE_UCHAR(LT, OP)
-#define BINARY_MULTISWITCH_UCHAR(OP)
+#define BINARY_LT_IS_UCHAR
+#define BINARY_LT_SET_RT_IS_UCHAR(LT)
 #endif
 
 
@@ -59,22 +56,17 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 #if GAL_CONFIG_BIN_OP_CHAR == 1
-#define BINARY_LEFT_RIGHT_DONE_CHAR(LT, RT, OP)                         \
-  case GAL_DATA_TYPE_CHAR:                                              \
-    BINARY_OPERATOR_FOR_TYPE(LT, RT, char, OP);                         \
+#define BINARY_LT_IS_CHAR                                          \
+  case GAL_DATA_TYPE_CHAR:                                         \
+    BINARY_LT_SET(char);                                           \
+    break;
+#define BINARY_LT_SET_RT_IS_CHAR(LT)                               \
+  case GAL_DATA_TYPE_CHAR:                                         \
+    BINARY_RT_LT_SET(char, LT);                                    \
     break;
-#define BINARY_LEFT_DONE_CHAR(LT, OP)                                   \
-    case GAL_DATA_TYPE_CHAR:                                            \
-      BINARY_LEFT_RIGHT_DONE(LT, char, OP);                             \
-      break;
-#define BINARY_MULTISWITCH_CHAR(OP)                                     \
-    case GAL_DATA_TYPE_CHAR:                                            \
-      BINARY_LEFT_DONE(char, OP);                                       \
-      break;
 #else
-#define BINARY_LEFT_RIGHT_DONE_CHAR(LT, RT, OP)
-#define BINARY_LEFT_DONE_CHAR(LT, OP)
-#define BINARY_MULTISWITCH_CHAR(OP)
+#define BINARY_LT_IS_CHAR
+#define BINARY_LT_SET_RT_IS_CHAR(LT)
 #endif
 
 
@@ -82,22 +74,17 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 #if GAL_CONFIG_BIN_OP_USHORT == 1
-#define BINARY_LEFT_RIGHT_DONE_USHORT(LT, RT, OP)                       \
-  case GAL_DATA_TYPE_USHORT:                                            \
-    BINARY_OPERATOR_FOR_TYPE(LT, RT, unsigned short, OP);               \
+#define BINARY_LT_IS_USHORT                                        \
+  case GAL_DATA_TYPE_USHORT:                                       \
+    BINARY_LT_SET(unsigned short);                                 \
+    break;
+#define BINARY_LT_SET_RT_IS_USHORT(LT)                             \
+  case GAL_DATA_TYPE_USHORT:                                       \
+    BINARY_RT_LT_SET(unsigned short, LT);                          \
     break;
-#define BINARY_LEFT_DONE_USHORT(LT, OP)                                 \
-    case GAL_DATA_TYPE_USHORT:                                          \
-      BINARY_LEFT_RIGHT_DONE(LT, unsigned short, OP);                   \
-      break;
-#define BINARY_MULTISWITCH_USHORT(OP)                                   \
-    case GAL_DATA_TYPE_USHORT:                                          \
-      BINARY_LEFT_DONE(unsigned short, OP);                             \
-      break;
 #else
-#define BINARY_LEFT_RIGHT_DONE_USHORT(LT, RT, OP)
-#define BINARY_LEFT_DONE_USHORT(LT, OP)
-#define BINARY_MULTISWITCH_USHORT(OP)
+#define BINARY_LT_IS_USHORT
+#define BINARY_LT_SET_RT_IS_USHORT(LT)
 #endif
 
 
@@ -105,22 +92,17 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 #if GAL_CONFIG_BIN_OP_SHORT == 1
-#define BINARY_LEFT_RIGHT_DONE_SHORT(LT, RT, OP)                        \
-  case GAL_DATA_TYPE_SHORT:                                             \
-    BINARY_OPERATOR_FOR_TYPE(LT, RT, short, OP);                        \
+#define BINARY_LT_IS_SHORT                                         \
+  case GAL_DATA_TYPE_SHORT:                                        \
+    BINARY_LT_SET(short);                                          \
+    break;
+#define BINARY_LT_SET_RT_IS_SHORT(LT)                              \
+  case GAL_DATA_TYPE_SHORT:                                        \
+    BINARY_RT_LT_SET(short, LT);                                   \
     break;
-#define BINARY_LEFT_DONE_SHORT(LT, OP)                                  \
-    case GAL_DATA_TYPE_SHORT:                                           \
-      BINARY_LEFT_RIGHT_DONE(LT, short, OP);                            \
-      break;
-#define BINARY_MULTISWITCH_SHORT(OP)                                    \
-    case GAL_DATA_TYPE_SHORT:                                           \
-      BINARY_LEFT_DONE(short, OP);                                      \
-      break;
 #else
-#define BINARY_LEFT_RIGHT_DONE_SHORT(LT, RT, OP)
-#define BINARY_LEFT_DONE_SHORT(LT, OP)
-#define BINARY_MULTISWITCH_SHORT(OP)
+#define BINARY_LT_IS_SHORT
+#define BINARY_LT_SET_RT_IS_SHORT(LT)
 #endif
 
 
@@ -128,22 +110,17 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 #if GAL_CONFIG_BIN_OP_UINT == 1
-#define BINARY_LEFT_RIGHT_DONE_UINT(LT, RT, OP)                         \
-  case GAL_DATA_TYPE_UINT:                                              \
-    BINARY_OPERATOR_FOR_TYPE(LT, RT, unsigned int, OP);                 \
+#define BINARY_LT_IS_UINT                                          \
+  case GAL_DATA_TYPE_UINT:                                         \
+    BINARY_LT_SET(unsigned int);                                   \
+    break;
+#define BINARY_LT_SET_RT_IS_UINT(LT)                               \
+  case GAL_DATA_TYPE_UINT:                                         \
+    BINARY_RT_LT_SET(unsigned int, LT);                            \
     break;
-#define BINARY_LEFT_DONE_UINT(LT, OP)                                   \
-    case GAL_DATA_TYPE_UINT:                                            \
-      BINARY_LEFT_RIGHT_DONE(LT, unsigned int, OP);                     \
-      break;
-#define BINARY_MULTISWITCH_UINT(OP)                                     \
-    case GAL_DATA_TYPE_UINT:                                            \
-      BINARY_LEFT_DONE(unsigned int, OP);                               \
-      break;
 #else
-#define BINARY_LEFT_RIGHT_DONE_UINT(LT, RT, OP)
-#define BINARY_LEFT_DONE_UINT(LT, OP)
-#define BINARY_MULTISWITCH_UINT(OP)
+#define BINARY_LT_IS_UINT
+#define BINARY_LT_SET_RT_IS_UINT(LT)
 #endif
 
 
@@ -151,22 +128,17 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 #if GAL_CONFIG_BIN_OP_INT == 1
-#define BINARY_LEFT_RIGHT_DONE_INT(LT, RT, OP)                          \
-  case GAL_DATA_TYPE_INT:                                               \
-    BINARY_OPERATOR_FOR_TYPE(LT, RT, int, OP);                          \
+#define BINARY_LT_IS_INT                                           \
+  case GAL_DATA_TYPE_INT:                                          \
+    BINARY_LT_SET(int);                                            \
+    break;
+#define BINARY_LT_SET_RT_IS_INT(LT)                                \
+  case GAL_DATA_TYPE_INT:                                          \
+    BINARY_RT_LT_SET(int, LT);                                     \
     break;
-#define BINARY_LEFT_DONE_INT(LT, OP)                                    \
-    case GAL_DATA_TYPE_INT:                                             \
-      BINARY_LEFT_RIGHT_DONE(LT, int, OP);                              \
-      break;
-#define BINARY_MULTISWITCH_INT(OP)                                      \
-    case GAL_DATA_TYPE_INT:                                             \
-      BINARY_LEFT_DONE(int, OP);                                        \
-      break;
 #else
-#define BINARY_LEFT_RIGHT_DONE_INT(LT, RT, OP)
-#define BINARY_LEFT_DONE_INT(LT, OP)
-#define BINARY_MULTISWITCH_INT(OP)
+#define BINARY_LT_IS_INT
+#define BINARY_LT_SET_RT_IS_INT(LT)
 #endif
 
 
@@ -174,22 +146,17 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 #if GAL_CONFIG_BIN_OP_ULONG == 1
-#define BINARY_LEFT_RIGHT_DONE_ULONG(LT, RT, OP)                        \
-    case GAL_DATA_TYPE_ULONG:                                           \
-      BINARY_OPERATOR_FOR_TYPE(LT, RT, unsigned long, OP);              \
-      break;
-#define BINARY_LEFT_DONE_ULONG(LT, OP)                                  \
-    case GAL_DATA_TYPE_ULONG:                                           \
-      BINARY_LEFT_RIGHT_DONE(LT, unsigned long, OP);                    \
-      break;
-#define BINARY_MULTISWITCH_ULONG(OP)                                    \
-    case GAL_DATA_TYPE_ULONG:                                           \
-      BINARY_LEFT_DONE(unsigned long, OP);                              \
-      break;
+#define BINARY_LT_IS_ULONG                                         \
+  case GAL_DATA_TYPE_ULONG:                                        \
+    BINARY_LT_SET(unsigned long);                                  \
+    break;
+#define BINARY_LT_SET_RT_IS_ULONG(LT)                              \
+  case GAL_DATA_TYPE_ULONG:                                        \
+    BINARY_RT_LT_SET(unsigned long, LT);                           \
+    break;
 #else
-#define BINARY_LEFT_RIGHT_DONE_ULONG(LT, RT, OP)
-#define BINARY_LEFT_DONE_ULONG(LT, OP)
-#define BINARY_MULTISWITCH_ULONG(OP)
+#define BINARY_LT_IS_ULONG
+#define BINARY_LT_SET_RT_IS_ULONG(LT)
 #endif
 
 
@@ -197,22 +164,17 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 #if GAL_CONFIG_BIN_OP_LONG == 1
-#define BINARY_LEFT_RIGHT_DONE_LONG(LT, RT, OP)                         \
-    case GAL_DATA_TYPE_LONG:                                            \
-      BINARY_OPERATOR_FOR_TYPE(LT, RT, long, OP);                       \
-      break;
-#define BINARY_LEFT_DONE_LONG(LT, OP)                                   \
-    case GAL_DATA_TYPE_LONG:                                            \
-      BINARY_LEFT_RIGHT_DONE(LT, long, OP);                             \
-      break;
-#define BINARY_MULTISWITCH_LONG(OP)                                     \
-    case GAL_DATA_TYPE_LONG:                                            \
-      BINARY_LEFT_DONE(long, OP);                                       \
-      break;
+#define BINARY_LT_IS_LONG                                          \
+  case GAL_DATA_TYPE_LONG:                                         \
+    BINARY_LT_SET(long);                                           \
+    break;
+#define BINARY_LT_SET_RT_IS_LONG(LT)                               \
+  case GAL_DATA_TYPE_LONG:                                         \
+    BINARY_RT_LT_SET(long, LT);                                    \
+    break;
 #else
-#define BINARY_LEFT_RIGHT_DONE_LONG(LT, RT, OP)
-#define BINARY_LEFT_DONE_LONG(LT, OP)
-#define BINARY_MULTISWITCH_LONG(OP)
+#define BINARY_LT_IS_LONG
+#define BINARY_LT_SET_RT_IS_LONG(LT)
 #endif
 
 
@@ -220,22 +182,17 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 #if GAL_CONFIG_BIN_OP_LONGLONG == 1
-#define BINARY_LEFT_RIGHT_DONE_LONGLONG(LT, RT, OP)                     \
-    case GAL_DATA_TYPE_LONGLONG:                                        \
-      BINARY_OPERATOR_FOR_TYPE(LT, RT, LONGLONG, OP);                   \
-      break;
-#define BINARY_LEFT_DONE_LONGLONG(LT, OP)                               \
-    case GAL_DATA_TYPE_LONGLONG:                                        \
-      BINARY_LEFT_RIGHT_DONE(LT, long long, OP);                        \
-      break;
-#define BINARY_MULTISWITCH_LONGLONG(OP)                                 \
-    case GAL_DATA_TYPE_LONGLONG:                                        \
-      BINARY_LEFT_DONE(LONGLONG, OP);                                   \
-      break;
+#define BINARY_LT_IS_LONGLONG                                      \
+  case GAL_DATA_TYPE_LONGLONG:                                     \
+    BINARY_LT_SET(LONGLONG);                                       \
+    break;
+#define BINARY_LT_SET_RT_IS_LONGLONG(LT)                           \
+  case GAL_DATA_TYPE_LONGLONG:                                     \
+    BINARY_RT_LT_SET(LONGLONG, LT);                                \
+    break;
 #else
-#define BINARY_LEFT_RIGHT_DONE_LONGLONG(LT, RT, OP)
-#define BINARY_LEFT_DONE_LONGLONG(LT, OP)
-#define BINARY_MULTISWITCH_LONGLONG(OP)
+#define BINARY_LT_IS_LONGLONG
+#define BINARY_LT_SET_RT_IS_LONGLONG(LT)
 #endif
 
 
@@ -243,22 +200,17 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 #if GAL_CONFIG_BIN_OP_FLOAT == 1
-#define BINARY_LEFT_RIGHT_DONE_FLOAT(LT, RT, OP)                        \
-    case GAL_DATA_TYPE_FLOAT:                                           \
-      BINARY_OPERATOR_FOR_TYPE(LT, RT, float, OP);                      \
-      break;
-#define BINARY_LEFT_DONE_FLOAT(LT, OP)                                  \
-    case GAL_DATA_TYPE_FLOAT:                                           \
-      BINARY_LEFT_RIGHT_DONE(LT, float, OP);                            \
-      break;
-#define BINARY_MULTISWITCH_FLOAT(OP)                                    \
-    case GAL_DATA_TYPE_FLOAT:                                           \
-      BINARY_LEFT_DONE(float, OP);                                      \
-      break;
+#define BINARY_LT_IS_FLOAT                                         \
+  case GAL_DATA_TYPE_FLOAT:                                        \
+    BINARY_LT_SET(float);                                          \
+    break;
+#define BINARY_LT_SET_RT_IS_FLOAT(LT)                              \
+  case GAL_DATA_TYPE_FLOAT:                                        \
+    BINARY_RT_LT_SET(float, LT);                                   \
+    break;
 #else
-#define BINARY_LEFT_RIGHT_DONE_FLOAT(LT, RT, OP)
-#define BINARY_LEFT_DONE_FLOAT(LT, OP)
-#define BINARY_MULTISWITCH_FLOAT(OP)
+#define BINARY_LT_IS_FLOAT
+#define BINARY_LT_SET_RT_IS_FLOAT(LT)
 #endif
 
 
@@ -266,22 +218,17 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 #if GAL_CONFIG_BIN_OP_DOUBLE == 1
-#define BINARY_LEFT_RIGHT_DONE_DOUBLE(LT, RT, OP)                       \
-    case GAL_DATA_TYPE_DOUBLE:                                          \
-      BINARY_OPERATOR_FOR_TYPE(LT, RT, double, OP);                     \
-      break;
-#define BINARY_LEFT_DONE_DOUBLE(LT, OP)                                 \
-    case GAL_DATA_TYPE_DOUBLE:                                          \
-      BINARY_LEFT_RIGHT_DONE(LT, double, OP);                           \
-      break;
-#define BINARY_MULTISWITCH_DOUBLE(OP)                                   \
-    case GAL_DATA_TYPE_DOUBLE:                                          \
-      BINARY_LEFT_DONE(double, OP);                                     \
-      break;
+#define BINARY_LT_IS_DOUBLE                                        \
+  case GAL_DATA_TYPE_DOUBLE:                                       \
+    BINARY_LT_SET(double);                                         \
+    break;
+#define BINARY_LT_SET_RT_IS_DOUBLE(LT)                             \
+  case GAL_DATA_TYPE_DOUBLE:                                       \
+    BINARY_RT_LT_SET(double, LT);                                  \
+    break;
 #else
-#define BINARY_LEFT_RIGHT_DONE_DOUBLE(LT, RT, OP)
-#define BINARY_LEFT_DONE_DOUBLE(LT, OP)
-#define BINARY_MULTISWITCH_DOUBLE(OP)
+#define BINARY_LT_IS_DOUBLE
+#define BINARY_LT_SET_RT_IS_DOUBLE(LT)
 #endif
 
 
@@ -302,97 +249,102 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 
-
-
-
-
-
 /************************************************************************/
-/*************       Macros for specifying the type     *****************/
+/*************              High level macros           *****************/
 /************************************************************************/
-
-#define BINARY_OPERATOR_FOR_TYPE(LT, RT, OT, OP){                       \
-    LT *la=l->array;                                                    \
-    RT *ra=r->array;                                                    \
-    OT *oa=o->array, *of=oa + o->size;                                  \
-    if(l->size==r->size) do *oa = *la++ OP *ra++; while(++oa<of);       \
-    else if(l->size==1)  do *oa = *la   OP *ra++; while(++oa<of);       \
-    else                 do *oa = *la++ OP *ra;   while(++oa<of);       \
+/* Final step to be used by all operators and all types. */
+#define BINARY_OP_OT_RT_LT_SET(OP, OT, RT, LT) {                   \
+    LT *la=l->array;                                               \
+    RT *ra=r->array;                                               \
+    OT *oa=o->array, *of=oa + o->size;                             \
+    if(l->size==r->size) do *oa = *la++ OP *ra++; while(++oa<of);  \
+    else if(l->size==1)  do *oa = *la   OP *ra++; while(++oa<of);  \
+    else                 do *oa = *la++ OP *ra;   while(++oa<of);  \
   }
 
 
 
 
 
-#define BINARY_LEFT_RIGHT_DONE(LT, RT, OP)                              \
-  switch(o->type)                                                       \
-    {                                                                   \
-                                                                        \
-    BINARY_LEFT_RIGHT_DONE_UCHAR(LT, RT, OP)                            \
-    BINARY_LEFT_RIGHT_DONE_CHAR(LT, RT, OP)                             \
-    BINARY_LEFT_RIGHT_DONE_SHORT(LT, RT, OP)                            \
-    BINARY_LEFT_RIGHT_DONE_USHORT(LT, RT, OP)                           \
-    BINARY_LEFT_RIGHT_DONE_INT(LT, RT, OP)                              \
-    BINARY_LEFT_RIGHT_DONE_UINT(LT, RT, OP)                             \
-    BINARY_LEFT_RIGHT_DONE_ULONG(LT, RT, OP)                            \
-    BINARY_LEFT_RIGHT_DONE_LONG(LT, RT, OP)                             \
-    BINARY_LEFT_RIGHT_DONE_LONGLONG(LT, RT, OP)                         \
-    BINARY_LEFT_RIGHT_DONE_FLOAT(LT, RT, OP)                            \
-    BINARY_LEFT_RIGHT_DONE_DOUBLE(LT, RT, OP)                           \
-                                                                        \
-    default:                                                            \
-      error(EXIT_FAILURE, 0, "type %d not recognized in "               \
-            "for o->type in BINARY_LEFT_RIGHT_DONE", o->type);          \
+/* For operators whose type may be any of the given inputs. */
+#define BINARY_OP_RT_LT_SET(OP, RT, LT)                            \
+  if(o->type==l->type)                                             \
+    BINARY_OP_OT_RT_LT_SET(OP, LT, RT, LT)                         \
+  else                                                             \
+    BINARY_OP_OT_RT_LT_SET(OP, RT, RT, LT)
+
+
+
+
+
+/* Left and right types set, choose what to do based on operator. */
+#define BINARY_RT_LT_SET(RT, LT)                                   \
+  switch(operator)                                                 \
+    {                                                              \
+    case GAL_DATA_OPERATOR_PLUS:                                   \
+      BINARY_OP_RT_LT_SET(+, RT, LT);                              \
+      break;                                                       \
+    case GAL_DATA_OPERATOR_MINUS:                                  \
+      BINARY_OP_RT_LT_SET(-, RT, LT);                              \
+      break;                                                       \
+    case GAL_DATA_OPERATOR_MULTIPLY:                               \
+      BINARY_OP_RT_LT_SET(*, RT, LT);                              \
+      break;                                                       \
+    case GAL_DATA_OPERATOR_DIVIDE:                                 \
+      BINARY_OP_RT_LT_SET(/, RT, LT);                              \
+      break;                                                       \
+    case GAL_DATA_OPERATOR_LT:                                     \
+      BINARY_OP_OT_RT_LT_SET(<, unsigned char, RT, LT);            \
+      break;                                                       \
+    case GAL_DATA_OPERATOR_LE:                                     \
+      BINARY_OP_OT_RT_LT_SET(<=, unsigned char, RT, LT);           \
+      break;                                                       \
+    case GAL_DATA_OPERATOR_GT:                                     \
+      BINARY_OP_OT_RT_LT_SET(>, unsigned char, RT, LT);            \
+      break;                                                       \
+    case GAL_DATA_OPERATOR_GE:                                     \
+      BINARY_OP_OT_RT_LT_SET(>=, unsigned char, RT, LT);           \
+      break;                                                       \
+    case GAL_DATA_OPERATOR_EQ:                                     \
+      BINARY_OP_OT_RT_LT_SET(==, unsigned char, RT, LT);           \
+      break;                                                       \
+    case GAL_DATA_OPERATOR_NE:                                     \
+      BINARY_OP_OT_RT_LT_SET(!=, unsigned char, RT, LT);           \
+      break;                                                       \
+    case GAL_DATA_OPERATOR_AND:                                    \
+      BINARY_OP_OT_RT_LT_SET(&&, unsigned char, RT, LT);           \
+      break;                                                       \
+    case GAL_DATA_OPERATOR_OR:                                     \
+      BINARY_OP_OT_RT_LT_SET(||, unsigned char, RT, LT);           \
+      break;                                                       \
+    default:                                                       \
+      error(EXIT_FAILURE, 0, "operator code %d not recognized in " \
+            "`BINARY_RT_LT_SET", operator);                        \
     }
 
 
 
 
 
-#define BINARY_LEFT_DONE(LT, OP)                                        \
-  switch(r->type)                                                       \
-    {                                                                   \
-                                                                        \
-    BINARY_LEFT_DONE_UCHAR(LT, OP)                                      \
-    BINARY_LEFT_DONE_CHAR(LT, OP)                                       \
-    BINARY_LEFT_DONE_USHORT(LT, OP)                                     \
-    BINARY_LEFT_DONE_SHORT(LT, OP)                                      \
-    BINARY_LEFT_DONE_UINT(LT, OP)                                       \
-    BINARY_LEFT_DONE_INT(LT, OP)                                        \
-    BINARY_LEFT_DONE_ULONG(LT, OP)                                      \
-    BINARY_LEFT_DONE_LONG(LT, OP)                                       \
-    BINARY_LEFT_DONE_LONGLONG(LT, OP)                                   \
-    BINARY_LEFT_DONE_FLOAT(LT, OP)                                      \
-    BINARY_LEFT_DONE_DOUBLE(LT, OP)                                     \
-                                                                        \
-    default:                                                            \
-      error(EXIT_FAILURE, 0, "type %d not recognized in "               \
-            "for r->type in BINARY_LEFT_DONE", r->type);                \
-    }
 
-
-
-
-
-#define BINARY_OPERATOR_DONE(OP)                                        \
-  switch(l->type)                                                       \
-    {                                                                   \
-                                                                        \
-      BINARY_MULTISWITCH_UCHAR(OP);                                     \
-      BINARY_MULTISWITCH_CHAR(OP);                                      \
-      BINARY_MULTISWITCH_USHORT(OP);                                    \
-      BINARY_MULTISWITCH_SHORT(OP);                                     \
-      BINARY_MULTISWITCH_UINT(OP);                                      \
-      BINARY_MULTISWITCH_INT(OP);                                       \
-      BINARY_MULTISWITCH_ULONG(OP);                                     \
-      BINARY_MULTISWITCH_LONG(OP);                                      \
-      BINARY_MULTISWITCH_LONGLONG(OP);                                  \
-      BINARY_MULTISWITCH_FLOAT(OP);                                     \
-      BINARY_MULTISWITCH_DOUBLE(OP);                                    \
-                                                                        \
-    default:                                                            \
-      error(EXIT_FAILURE, 0, "type %d not recognized in "               \
-            "for l->type in data_arithmetic_binary", l->type);          \
+/* Left operand type set, see what the right operand type is. */
+#define BINARY_LT_SET(LT)                                          \
+  switch(r->type)                                                  \
+    {                                                              \
+      BINARY_LT_SET_RT_IS_UCHAR(LT);                               \
+      BINARY_LT_SET_RT_IS_CHAR(LT);                                \
+      BINARY_LT_SET_RT_IS_USHORT(LT);                              \
+      BINARY_LT_SET_RT_IS_SHORT(LT);                               \
+      BINARY_LT_SET_RT_IS_UINT(LT);                                \
+      BINARY_LT_SET_RT_IS_INT(LT);                                 \
+      BINARY_LT_SET_RT_IS_ULONG(LT);                               \
+      BINARY_LT_SET_RT_IS_LONG(LT);                                \
+      BINARY_LT_SET_RT_IS_LONGLONG(LT);                            \
+      BINARY_LT_SET_RT_IS_FLOAT(LT);                               \
+      BINARY_LT_SET_RT_IS_DOUBLE(LT);                              \
+    default:                                                       \
+      error(EXIT_FAILURE, 0, "type code %d not recognized in "     \
+            "`BINARY_LT_SET'", r->type);                           \
     }
 
 
@@ -414,214 +366,6 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 
-/********************************************************************/
-/****************        Intermediate functions       ***************/
-/********************************************************************/
-static int
-binary_type_for_convert_to_compiled_type(int intype)
-{
-  switch(intype)
-    {
-    case GAL_DATA_TYPE_UCHAR:
-      if(GAL_CONFIG_BIN_OP_UCHAR) return GAL_DATA_TYPE_UCHAR;
-      else
-        {
-          if     (GAL_CONFIG_BIN_OP_USHORT)   return GAL_DATA_TYPE_USHORT;
-          else if(GAL_CONFIG_BIN_OP_SHORT)    return GAL_DATA_TYPE_SHORT;
-          else if(GAL_CONFIG_BIN_OP_UINT)     return GAL_DATA_TYPE_UINT;
-          else if(GAL_CONFIG_BIN_OP_INT)      return GAL_DATA_TYPE_INT;
-          else if(GAL_CONFIG_BIN_OP_ULONG)    return GAL_DATA_TYPE_ULONG;
-          else if(GAL_CONFIG_BIN_OP_LONG)     return GAL_DATA_TYPE_LONG;
-          else if(GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
-          else if(GAL_CONFIG_BIN_OP_FLOAT)    return GAL_DATA_TYPE_FLOAT;
-          else if(GAL_CONFIG_BIN_OP_DOUBLE)   return GAL_DATA_TYPE_DOUBLE;
-        }
-      break;
-
-    case GAL_DATA_TYPE_CHAR:
-      if(GAL_CONFIG_BIN_OP_CHAR) return GAL_DATA_TYPE_CHAR;
-      else
-        {
-          if     (GAL_CONFIG_BIN_OP_SHORT)    return GAL_DATA_TYPE_SHORT;
-          else if(GAL_CONFIG_BIN_OP_INT)      return GAL_DATA_TYPE_INT;
-          else if(GAL_CONFIG_BIN_OP_LONG)     return GAL_DATA_TYPE_LONG;
-          else if(GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
-          else if(GAL_CONFIG_BIN_OP_FLOAT)    return GAL_DATA_TYPE_FLOAT;
-          else if(GAL_CONFIG_BIN_OP_DOUBLE)   return GAL_DATA_TYPE_DOUBLE;
-        }
-      break;
-
-    case GAL_DATA_TYPE_USHORT:
-      if(GAL_CONFIG_BIN_OP_USHORT) return GAL_DATA_TYPE_USHORT;
-      else
-        {
-          if     (GAL_CONFIG_BIN_OP_UINT)     return GAL_DATA_TYPE_UINT;
-          else if(GAL_CONFIG_BIN_OP_INT)      return GAL_DATA_TYPE_INT;
-          else if(GAL_CONFIG_BIN_OP_ULONG)    return GAL_DATA_TYPE_ULONG;
-          else if(GAL_CONFIG_BIN_OP_LONG)     return GAL_DATA_TYPE_LONG;
-          else if(GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
-          else if(GAL_CONFIG_BIN_OP_FLOAT)    return GAL_DATA_TYPE_FLOAT;
-          else if(GAL_CONFIG_BIN_OP_DOUBLE)   return GAL_DATA_TYPE_DOUBLE;
-        }
-      break;
-
-    case GAL_DATA_TYPE_SHORT:
-      if(GAL_CONFIG_BIN_OP_SHORT) return GAL_DATA_TYPE_SHORT;
-      else
-        {
-          if     (GAL_CONFIG_BIN_OP_INT)      return GAL_DATA_TYPE_INT;
-          else if(GAL_CONFIG_BIN_OP_LONG)     return GAL_DATA_TYPE_LONG;
-          else if(GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
-          else if(GAL_CONFIG_BIN_OP_FLOAT)    return GAL_DATA_TYPE_FLOAT;
-          else if(GAL_CONFIG_BIN_OP_DOUBLE)   return GAL_DATA_TYPE_DOUBLE;
-        }
-      break;
-
-    case GAL_DATA_TYPE_UINT:
-      if(GAL_CONFIG_BIN_OP_UINT) return GAL_DATA_TYPE_UINT;
-      else
-        {
-          if     (GAL_CONFIG_BIN_OP_ULONG)    return GAL_DATA_TYPE_ULONG;
-          else if(GAL_CONFIG_BIN_OP_LONG)     return GAL_DATA_TYPE_LONG;
-          else if(GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
-          else if(GAL_CONFIG_BIN_OP_FLOAT)    return GAL_DATA_TYPE_FLOAT;
-          else if(GAL_CONFIG_BIN_OP_DOUBLE)   return GAL_DATA_TYPE_DOUBLE;
-        }
-      break;
-
-    case GAL_DATA_TYPE_INT:
-      if(GAL_CONFIG_BIN_OP_INT) return GAL_DATA_TYPE_INT;
-      else
-        {
-          if     (GAL_CONFIG_BIN_OP_LONG)     return GAL_DATA_TYPE_LONG;
-          else if(GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
-          else if(GAL_CONFIG_BIN_OP_FLOAT)    return GAL_DATA_TYPE_FLOAT;
-          else if(GAL_CONFIG_BIN_OP_DOUBLE)   return GAL_DATA_TYPE_DOUBLE;
-        }
-      break;
-
-    case GAL_DATA_TYPE_ULONG:
-      if(GAL_CONFIG_BIN_OP_ULONG) return GAL_DATA_TYPE_ULONG;
-      else
-        {
-          if     (GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
-          else if(GAL_CONFIG_BIN_OP_FLOAT)    return GAL_DATA_TYPE_FLOAT;
-          else if(GAL_CONFIG_BIN_OP_DOUBLE)   return GAL_DATA_TYPE_DOUBLE;
-        }
-      break;
-
-    case GAL_DATA_TYPE_LONG:
-      if(GAL_CONFIG_BIN_OP_LONG) return GAL_DATA_TYPE_LONG;
-      else
-        {
-          if     (GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
-          else if(GAL_CONFIG_BIN_OP_FLOAT)    return GAL_DATA_TYPE_FLOAT;
-          else if(GAL_CONFIG_BIN_OP_DOUBLE)   return GAL_DATA_TYPE_DOUBLE;
-        }
-      break;
-
-    case GAL_DATA_TYPE_LONGLONG:
-      if(GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
-      else
-        {
-          if     (GAL_CONFIG_BIN_OP_FLOAT)    return GAL_DATA_TYPE_FLOAT;
-          else if(GAL_CONFIG_BIN_OP_DOUBLE)   return GAL_DATA_TYPE_DOUBLE;
-        }
-      break;
-
-    case GAL_DATA_TYPE_FLOAT:
-      if(GAL_CONFIG_BIN_OP_FLOAT) return GAL_DATA_TYPE_FLOAT;
-      else
-        {
-          if     (GAL_CONFIG_BIN_OP_DOUBLE)   return GAL_DATA_TYPE_DOUBLE;
-        }
-      break;
-
-    case GAL_DATA_TYPE_DOUBLE:
-      if         (GAL_CONFIG_BIN_OP_DOUBLE)   return GAL_DATA_TYPE_DOUBLE;
-      break;
-
-    default:
-      error(EXIT_FAILURE, 0, "type %d not recognized in "
-            "BINARY_CONVERT_TO_COMPILED_TYPE", intype);
-    }
-
-  return 0;
-}
-
-
-
-
-
-/* Note that for signed types, we won't be considering the unsigned types
-   of the larger types. */
-gal_data_t *
-binary_convert_to_compiled_type(gal_data_t *in, unsigned char flags)
-{
-  int ntype;
-  char *typestring;
-  gal_data_t *out=NULL;
-
-  /* Set the best compiled type. */
-  ntype=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
-        {
-          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);
-        }
-    }
-
-  /* Return the output data structure */
-  if(out==NULL)
-    error(EXIT_FAILURE, 0, "A bug! Please contact us at %s, so we can fix "
-          "the problem. For some reason, the `out' array in "
-          "`binary_convert_to_compiled_type' is not set", PACKAGE_BUGREPORT);
-  return out;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 /************************************************************************/
 /*************              Top level function          *****************/
 /************************************************************************/
@@ -632,51 +376,49 @@ data_arithmetic_binary(int operator, unsigned char flags, 
gal_data_t *lo,
   /* Read the variable arguments. `lo' and `ro' keep the original data, in
      case their type isn't built (based on configure options are configure
      time). */
+  int otype;
   size_t out_size, minmapsize;
   gal_data_t *l, *r, *o=NULL, *tmp_o;
-  int out_type=0, otype, final_otype;
 
 
   /* Simple sanity check on the input sizes */
   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");
+    error(EXIT_FAILURE, 0, "the non-number inputs to %s don't have the "
+          "same dimension/size", gal_data_operator_string(operator));
 
 
-  /* Make sure the input arrays have one of the compiled types. */
-  l=binary_convert_to_compiled_type(lo, flags);
-  r=binary_convert_to_compiled_type(ro, flags);
+  /* Make sure the input arrays have one of the compiled types. From this
+     point on, until the cleaning up section of this function, we won't be
+     using the `lo' and `ro' pointers. */
+  l=data_arithmetic_convert_to_compiled_type(lo, flags);
+  r=data_arithmetic_convert_to_compiled_type(ro, flags);
 
 
-  /* Set the output type. By default, `out_type' is initialized to zero,
-     this means that the type of the output data structure will be
-     determined based on the inputs. However, for the comparison operators,
-     the output type is either 0 or 1, so we will set the output to
-     unsigned character to save space and memory. Note that since this
-     switch check, is only relevant for certain operators, we don't need a
-     `default' statement.*/
+  /* Set the output type. For the comparison operators, the output type is
+     either 0 or 1, so we will set the output type to `unsigned char' for
+     efficient memory and CPU usage. Since the number of operators without
+     a fixed output type (like the conditionals) is less, by `default' we
+     will set the output type to `unsigned char', and if any of the other
+     operatrs are given, it will be chosen based on the input types.*/
   switch(operator)
     {
-    case GAL_DATA_OPERATOR_LT:
-    case GAL_DATA_OPERATOR_LE:
-    case GAL_DATA_OPERATOR_GT:
-    case GAL_DATA_OPERATOR_GE:
-    case GAL_DATA_OPERATOR_EQ:
-    case GAL_DATA_OPERATOR_NE:
-    case GAL_DATA_OPERATOR_AND:
-    case GAL_DATA_OPERATOR_OR:
-      out_type=GAL_DATA_TYPE_UCHAR;
+    case GAL_DATA_OPERATOR_PLUS:
+    case GAL_DATA_OPERATOR_MINUS:
+    case GAL_DATA_OPERATOR_MULTIPLY:
+    case GAL_DATA_OPERATOR_DIVIDE:
+      otype=gal_data_out_type(l, r);
       break;
+
+    default:
+      otype=GAL_DATA_TYPE_UCHAR;
     }
-  final_otype = out_type ? out_type : gal_data_out_type(lo, ro);
-  otype=binary_type_for_convert_to_compiled_type(final_otype);
 
 
   /* Set the output sizes. */
-  minmapsize = ( lo->minmapsize < ro->minmapsize
-                 ? lo->minmapsize : ro->minmapsize );
-  out_size = lo->size > ro->size ? lo->size : ro->size;
+  minmapsize = ( l->minmapsize < r->minmapsize
+                 ? l->minmapsize : r->minmapsize );
+  out_size = l->size > r->size ? l->size : r->size;
 
 
   /* If we want inplace output, set the output pointer to one input. Note
@@ -698,39 +440,37 @@ data_arithmetic_binary(int operator, unsigned char flags, 
gal_data_t *lo,
     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, minmapsize );
+                       l->size>1 ? l->wcs   : r->wcs,
+                       0, minmapsize );
 
 
   /* Start setting the operator and operands. */
-  switch(operator)
+  switch(l->type)
     {
-    case GAL_DATA_OPERATOR_PLUS:       BINARY_OPERATOR_DONE( +  ); break;
-    case GAL_DATA_OPERATOR_MINUS:      BINARY_OPERATOR_DONE( -  ); break;
-    case GAL_DATA_OPERATOR_MULTIPLY:   BINARY_OPERATOR_DONE( *  ); break;
-    case GAL_DATA_OPERATOR_DIVIDE:     BINARY_OPERATOR_DONE( /  ); break;
-    case GAL_DATA_OPERATOR_LT:         BINARY_OPERATOR_DONE( <  ); break;
-    case GAL_DATA_OPERATOR_LE:         BINARY_OPERATOR_DONE( <= ); break;
-    case GAL_DATA_OPERATOR_GT:         BINARY_OPERATOR_DONE( >  ); break;
-    case GAL_DATA_OPERATOR_GE:         BINARY_OPERATOR_DONE( >= ); break;
-    case GAL_DATA_OPERATOR_EQ:         BINARY_OPERATOR_DONE( == ); break;
-    case GAL_DATA_OPERATOR_NE:         BINARY_OPERATOR_DONE( != ); break;
-    case GAL_DATA_OPERATOR_AND:        BINARY_OPERATOR_DONE( && ); break;
-    case GAL_DATA_OPERATOR_OR:         BINARY_OPERATOR_DONE( || ); break;
+      BINARY_LT_IS_UCHAR;
+      BINARY_LT_IS_CHAR;
+      BINARY_LT_IS_USHORT;
+      BINARY_LT_IS_SHORT;
+      BINARY_LT_IS_UINT;
+      BINARY_LT_IS_INT;
+      BINARY_LT_IS_ULONG;
+      BINARY_LT_IS_LONG;
+      BINARY_LT_IS_LONGLONG;
+      BINARY_LT_IS_FLOAT;
+      BINARY_LT_IS_DOUBLE;
     default:
-      error(EXIT_FAILURE, 0, "Operator code %d not recognized in "
-            "data_arithmetic_binary when preparing for the operation",
-            operator);
+      error(EXIT_FAILURE, 0, "type code %d not recognized in "
+            "`data_arithmetic_binary'", l->type);
     }
 
 
   /* 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. */
+     has already freed the input arrays, so only `r' and `l' need
+     freeing. 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);
@@ -743,11 +483,15 @@ data_arithmetic_binary(int operator, unsigned char flags, 
gal_data_t *lo,
       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)
+  /* The type of the output dataset (`o->type') was chosen from `l' and `r'
+     (copies of the orignal operands but in a compiled type, not
+     necessarily the original `lo' and `ro' data structures). So we need to
+     to get the final type based on the original operands and check if the
+     final output needs changing. */
+  otype=gal_data_out_type(lo, ro);
+  if( o->type != otype )
     {
-      tmp_o=gal_data_copy_to_new_type(o, final_otype);
+      tmp_o=gal_data_copy_to_new_type(o, otype);
       gal_data_free(o);
       o=tmp_o;
     }
diff --git a/lib/data-arithmetic-onlyint.c b/lib/data-arithmetic-onlyint.c
index 5bf729a..f1a5f43 100644
--- a/lib/data-arithmetic-onlyint.c
+++ b/lib/data-arithmetic-onlyint.c
@@ -32,26 +32,23 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 
+
+
 /************************************************************************/
-/*************      Possibly set onlyint types to convert    *************/
+/*************            Native type macros            *****************/
 /************************************************************************/
 #if GAL_CONFIG_BIN_OP_UCHAR == 1
-#define ONLYINT_LEFT_RIGHT_DONE_UCHAR(LT, RT, OP)                       \
-    case GAL_DATA_TYPE_UCHAR:                                           \
-      ONLYINT_OPERATOR_FOR_TYPE(LT, RT, unsigned char, OP);             \
-      break;
-#define ONLYINT_LEFT_DONE_UCHAR(LT, OP)                                 \
-    case GAL_DATA_TYPE_UCHAR:                                           \
-      ONLYINT_LEFT_RIGHT_DONE(LT, unsigned char, OP);                   \
-      break;
-#define ONLYINT_MULTISWITCH_UCHAR(OP)                                   \
-    case GAL_DATA_TYPE_UCHAR:                                           \
-      ONLYINT_LEFT_DONE(unsigned char, OP);                             \
-      break;
+#define BINOIN_LT_IS_UCHAR                                         \
+  case GAL_DATA_TYPE_UCHAR:                                        \
+    BINOIN_LT_SET(unsigned char);                                  \
+    break;
+#define BINOIN_LT_SET_RT_IS_UCHAR(LT)                              \
+  case GAL_DATA_TYPE_UCHAR:                                        \
+    BINOIN_RT_LT_SET(unsigned char, LT);                           \
+    break;
 #else
-#define ONLYINT_LEFT_RIGHT_DONE_UCHAR(LT, RT, OP)
-#define ONLYINT_LEFT_DONE_UCHAR(LT, OP)
-#define ONLYINT_MULTISWITCH_UCHAR(OP)
+#define BINOIN_LT_IS_UCHAR
+#define BINOIN_LT_SET_RT_IS_UCHAR(LT)
 #endif
 
 
@@ -59,22 +56,17 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 #if GAL_CONFIG_BIN_OP_CHAR == 1
-#define ONLYINT_LEFT_RIGHT_DONE_CHAR(LT, RT, OP)                        \
-  case GAL_DATA_TYPE_CHAR:                                              \
-    ONLYINT_OPERATOR_FOR_TYPE(LT, RT, char, OP);                        \
+#define BINOIN_LT_IS_CHAR                                          \
+  case GAL_DATA_TYPE_CHAR:                                         \
+    BINOIN_LT_SET(char);                                           \
+    break;
+#define BINOIN_LT_SET_RT_IS_CHAR(LT)                               \
+  case GAL_DATA_TYPE_CHAR:                                         \
+    BINOIN_RT_LT_SET(char, LT);                                    \
     break;
-#define ONLYINT_LEFT_DONE_CHAR(LT, OP)                                  \
-    case GAL_DATA_TYPE_CHAR:                                            \
-      ONLYINT_LEFT_RIGHT_DONE(LT, char, OP);                            \
-      break;
-#define ONLYINT_MULTISWITCH_CHAR(OP)                                    \
-    case GAL_DATA_TYPE_CHAR:                                            \
-      ONLYINT_LEFT_DONE(char, OP);                                      \
-      break;
 #else
-#define ONLYINT_LEFT_RIGHT_DONE_CHAR(LT, RT, OP)
-#define ONLYINT_LEFT_DONE_CHAR(LT, OP)
-#define ONLYINT_MULTISWITCH_CHAR(OP)
+#define BINOIN_LT_IS_CHAR
+#define BINOIN_LT_SET_RT_IS_CHAR(LT)
 #endif
 
 
@@ -82,22 +74,17 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 #if GAL_CONFIG_BIN_OP_USHORT == 1
-#define ONLYINT_LEFT_RIGHT_DONE_USHORT(LT, RT, OP)                      \
-  case GAL_DATA_TYPE_USHORT:                                            \
-    ONLYINT_OPERATOR_FOR_TYPE(LT, RT, unsigned short, OP);              \
+#define BINOIN_LT_IS_USHORT                                        \
+  case GAL_DATA_TYPE_USHORT:                                       \
+    BINOIN_LT_SET(unsigned short);                                 \
+    break;
+#define BINOIN_LT_SET_RT_IS_USHORT(LT)                             \
+  case GAL_DATA_TYPE_USHORT:                                       \
+    BINOIN_RT_LT_SET(unsigned short, LT);                          \
     break;
-#define ONLYINT_LEFT_DONE_USHORT(LT, OP)                                \
-    case GAL_DATA_TYPE_USHORT:                                          \
-      ONLYINT_LEFT_RIGHT_DONE(LT, unsigned short, OP);                  \
-      break;
-#define ONLYINT_MULTISWITCH_USHORT(OP)                                  \
-    case GAL_DATA_TYPE_USHORT:                                          \
-      ONLYINT_LEFT_DONE(unsigned short, OP);                            \
-      break;
 #else
-#define ONLYINT_LEFT_RIGHT_DONE_USHORT(LT, RT, OP)
-#define ONLYINT_LEFT_DONE_USHORT(LT, OP)
-#define ONLYINT_MULTISWITCH_USHORT(OP)
+#define BINOIN_LT_IS_USHORT
+#define BINOIN_LT_SET_RT_IS_USHORT(LT)
 #endif
 
 
@@ -105,22 +92,17 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 #if GAL_CONFIG_BIN_OP_SHORT == 1
-#define ONLYINT_LEFT_RIGHT_DONE_SHORT(LT, RT, OP)                       \
-  case GAL_DATA_TYPE_SHORT:                                             \
-    ONLYINT_OPERATOR_FOR_TYPE(LT, RT, short, OP);                       \
+#define BINOIN_LT_IS_SHORT                                         \
+  case GAL_DATA_TYPE_SHORT:                                        \
+    BINOIN_LT_SET(short);                                          \
+    break;
+#define BINOIN_LT_SET_RT_IS_SHORT(LT)                              \
+  case GAL_DATA_TYPE_SHORT:                                        \
+    BINOIN_RT_LT_SET(short, LT);                                   \
     break;
-#define ONLYINT_LEFT_DONE_SHORT(LT, OP)                                 \
-    case GAL_DATA_TYPE_SHORT:                                           \
-      ONLYINT_LEFT_RIGHT_DONE(LT, short, OP);                           \
-      break;
-#define ONLYINT_MULTISWITCH_SHORT(OP)                                   \
-    case GAL_DATA_TYPE_SHORT:                                           \
-      ONLYINT_LEFT_DONE(short, OP);                                     \
-      break;
 #else
-#define ONLYINT_LEFT_RIGHT_DONE_SHORT(LT, RT, OP)
-#define ONLYINT_LEFT_DONE_SHORT(LT, OP)
-#define ONLYINT_MULTISWITCH_SHORT(OP)
+#define BINOIN_LT_IS_SHORT
+#define BINOIN_LT_SET_RT_IS_SHORT(LT)
 #endif
 
 
@@ -128,22 +110,17 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 #if GAL_CONFIG_BIN_OP_UINT == 1
-#define ONLYINT_LEFT_RIGHT_DONE_UINT(LT, RT, OP)                        \
-  case GAL_DATA_TYPE_UINT:                                              \
-    ONLYINT_OPERATOR_FOR_TYPE(LT, RT, unsigned int, OP);                \
+#define BINOIN_LT_IS_UINT                                          \
+  case GAL_DATA_TYPE_UINT:                                         \
+    BINOIN_LT_SET(unsigned int);                                   \
+    break;
+#define BINOIN_LT_SET_RT_IS_UINT(LT)                               \
+  case GAL_DATA_TYPE_UINT:                                         \
+    BINOIN_RT_LT_SET(unsigned int, LT);                            \
     break;
-#define ONLYINT_LEFT_DONE_UINT(LT, OP)                                  \
-    case GAL_DATA_TYPE_UINT:                                            \
-      ONLYINT_LEFT_RIGHT_DONE(LT, unsigned int, OP);                    \
-      break;
-#define ONLYINT_MULTISWITCH_UINT(OP)                                    \
-    case GAL_DATA_TYPE_UINT:                                            \
-      ONLYINT_LEFT_DONE(unsigned int, OP);                              \
-      break;
 #else
-#define ONLYINT_LEFT_RIGHT_DONE_UINT(LT, RT, OP)
-#define ONLYINT_LEFT_DONE_UINT(LT, OP)
-#define ONLYINT_MULTISWITCH_UINT(OP)
+#define BINOIN_LT_IS_UINT
+#define BINOIN_LT_SET_RT_IS_UINT(LT)
 #endif
 
 
@@ -151,22 +128,17 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 #if GAL_CONFIG_BIN_OP_INT == 1
-#define ONLYINT_LEFT_RIGHT_DONE_INT(LT, RT, OP)                         \
-  case GAL_DATA_TYPE_INT:                                               \
-    ONLYINT_OPERATOR_FOR_TYPE(LT, RT, int, OP);                         \
+#define BINOIN_LT_IS_INT                                           \
+  case GAL_DATA_TYPE_INT:                                          \
+    BINOIN_LT_SET(int);                                            \
+    break;
+#define BINOIN_LT_SET_RT_IS_INT(LT)                                \
+  case GAL_DATA_TYPE_INT:                                          \
+    BINOIN_RT_LT_SET(int, LT);                                     \
     break;
-#define ONLYINT_LEFT_DONE_INT(LT, OP)                                   \
-    case GAL_DATA_TYPE_INT:                                             \
-      ONLYINT_LEFT_RIGHT_DONE(LT, int, OP);                             \
-      break;
-#define ONLYINT_MULTISWITCH_INT(OP)                                     \
-    case GAL_DATA_TYPE_INT:                                             \
-      ONLYINT_LEFT_DONE(int, OP);                                       \
-      break;
 #else
-#define ONLYINT_LEFT_RIGHT_DONE_INT(LT, RT, OP)
-#define ONLYINT_LEFT_DONE_INT(LT, OP)
-#define ONLYINT_MULTISWITCH_INT(OP)
+#define BINOIN_LT_IS_INT
+#define BINOIN_LT_SET_RT_IS_INT(LT)
 #endif
 
 
@@ -174,22 +146,17 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 #if GAL_CONFIG_BIN_OP_ULONG == 1
-#define ONLYINT_LEFT_RIGHT_DONE_ULONG(LT, RT, OP)                       \
-    case GAL_DATA_TYPE_ULONG:                                           \
-      ONLYINT_OPERATOR_FOR_TYPE(LT, RT, unsigned long, OP);             \
-      break;
-#define ONLYINT_LEFT_DONE_ULONG(LT, OP)                                 \
-    case GAL_DATA_TYPE_ULONG:                                           \
-      ONLYINT_LEFT_RIGHT_DONE(LT, unsigned long, OP);                   \
-      break;
-#define ONLYINT_MULTISWITCH_ULONG(OP)                                   \
-    case GAL_DATA_TYPE_ULONG:                                           \
-      ONLYINT_LEFT_DONE(unsigned long, OP);                             \
-      break;
+#define BINOIN_LT_IS_ULONG                                         \
+  case GAL_DATA_TYPE_ULONG:                                        \
+    BINOIN_LT_SET(unsigned long);                                  \
+    break;
+#define BINOIN_LT_SET_RT_IS_ULONG(LT)                              \
+  case GAL_DATA_TYPE_ULONG:                                        \
+    BINOIN_RT_LT_SET(unsigned long, LT);                           \
+    break;
 #else
-#define ONLYINT_LEFT_RIGHT_DONE_ULONG(LT, RT, OP)
-#define ONLYINT_LEFT_DONE_ULONG(LT, OP)
-#define ONLYINT_MULTISWITCH_ULONG(OP)
+#define BINOIN_LT_IS_ULONG
+#define BINOIN_LT_SET_RT_IS_ULONG(LT)
 #endif
 
 
@@ -197,22 +164,17 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 #if GAL_CONFIG_BIN_OP_LONG == 1
-#define ONLYINT_LEFT_RIGHT_DONE_LONG(LT, RT, OP)                        \
-    case GAL_DATA_TYPE_LONG:                                            \
-      ONLYINT_OPERATOR_FOR_TYPE(LT, RT, long, OP);                      \
-      break;
-#define ONLYINT_LEFT_DONE_LONG(LT, OP)                                  \
-    case GAL_DATA_TYPE_LONG:                                            \
-      ONLYINT_LEFT_RIGHT_DONE(LT, long, OP);                            \
-      break;
-#define ONLYINT_MULTISWITCH_LONG(OP)                                    \
-    case GAL_DATA_TYPE_LONG:                                            \
-      ONLYINT_LEFT_DONE(long, OP);                                      \
-      break;
+#define BINOIN_LT_IS_LONG                                          \
+  case GAL_DATA_TYPE_LONG:                                         \
+    BINOIN_LT_SET(long);                                           \
+    break;
+#define BINOIN_LT_SET_RT_IS_LONG(LT)                               \
+  case GAL_DATA_TYPE_LONG:                                         \
+    BINOIN_RT_LT_SET(long, LT);                                    \
+    break;
 #else
-#define ONLYINT_LEFT_RIGHT_DONE_LONG(LT, RT, OP)
-#define ONLYINT_LEFT_DONE_LONG(LT, OP)
-#define ONLYINT_MULTISWITCH_LONG(OP)
+#define BINOIN_LT_IS_LONG
+#define BINOIN_LT_SET_RT_IS_LONG(LT)
 #endif
 
 
@@ -220,22 +182,17 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 #if GAL_CONFIG_BIN_OP_LONGLONG == 1
-#define ONLYINT_LEFT_RIGHT_DONE_LONGLONG(LT, RT, OP)                    \
-    case GAL_DATA_TYPE_LONGLONG:                                        \
-      ONLYINT_OPERATOR_FOR_TYPE(LT, RT, LONGLONG, OP);                  \
-      break;
-#define ONLYINT_LEFT_DONE_LONGLONG(LT, OP)                              \
-    case GAL_DATA_TYPE_LONGLONG:                                        \
-      ONLYINT_LEFT_RIGHT_DONE(LT, long long, OP);                       \
-      break;
-#define ONLYINT_MULTISWITCH_LONGLONG(OP)                                \
-    case GAL_DATA_TYPE_LONGLONG:                                        \
-      ONLYINT_LEFT_DONE(LONGLONG, OP);                                  \
-      break;
+#define BINOIN_LT_IS_LONGLONG                                      \
+  case GAL_DATA_TYPE_LONGLONG:                                     \
+    BINOIN_LT_SET(LONGLONG);                                       \
+    break;
+#define BINOIN_LT_SET_RT_IS_LONGLONG(LT)                           \
+  case GAL_DATA_TYPE_LONGLONG:                                     \
+    BINOIN_RT_LT_SET(LONGLONG, LT);                                \
+    break;
 #else
-#define ONLYINT_LEFT_RIGHT_DONE_LONGLONG(LT, RT, OP)
-#define ONLYINT_LEFT_DONE_LONGLONG(LT, OP)
-#define ONLYINT_MULTISWITCH_LONGLONG(OP)
+#define BINOIN_LT_IS_LONGLONG
+#define BINOIN_LT_SET_RT_IS_LONGLONG(LT)
 #endif
 
 
@@ -256,265 +213,84 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 
-
 /************************************************************************/
-/*************       Macros for specifying the type     *****************/
+/*************              High level macros           *****************/
 /************************************************************************/
-
-#define ONLYINT_OPERATOR_FOR_TYPE(LT, RT, OT, OP){                      \
-    LT *la=l->array;                                                    \
-    RT *ra=r->array;                                                    \
-    OT *oa=o->array, *of=oa + o->size;                                  \
-    if(l->size==r->size) do *oa = *la++ OP *ra++; while(++oa<of);       \
-    else if(l->size==1)  do *oa = *la   OP *ra++; while(++oa<of);       \
-    else                 do *oa = *la++ OP *ra;   while(++oa<of);       \
+/* Final step to be used by all operators and all types. */
+#define BINOIN_OP_OT_RT_LT_SET(OP, OT, RT, LT) {                   \
+    LT *la=l->array;                                               \
+    RT *ra=r->array;                                               \
+    OT *oa=o->array, *of=oa + o->size;                             \
+    if(l->size==r->size) do *oa = *la++ OP *ra++; while(++oa<of);  \
+    else if(l->size==1)  do *oa = *la   OP *ra++; while(++oa<of);  \
+    else                 do *oa = *la++ OP *ra;   while(++oa<of);  \
   }
 
 
 
 
 
-#define ONLYINT_LEFT_RIGHT_DONE(LT, RT, OP)                             \
-  switch(o->type)                                                       \
-    {                                                                   \
-                                                                        \
-      ONLYINT_LEFT_RIGHT_DONE_UCHAR(LT, RT, OP);                        \
-      ONLYINT_LEFT_RIGHT_DONE_CHAR(LT, RT, OP);                         \
-      ONLYINT_LEFT_RIGHT_DONE_SHORT(LT, RT, OP);                        \
-      ONLYINT_LEFT_RIGHT_DONE_USHORT(LT, RT, OP);                       \
-      ONLYINT_LEFT_RIGHT_DONE_INT(LT, RT, OP);                          \
-      ONLYINT_LEFT_RIGHT_DONE_UINT(LT, RT, OP);                         \
-      ONLYINT_LEFT_RIGHT_DONE_ULONG(LT, RT, OP);                        \
-      ONLYINT_LEFT_RIGHT_DONE_LONG(LT, RT, OP);                         \
-      ONLYINT_LEFT_RIGHT_DONE_LONGLONG(LT, RT, OP);                     \
-                                                                        \
-    default:                                                            \
-      error(EXIT_FAILURE, 0, "type %d not recognized in "               \
-            "for o->type in ONLYINT_LEFT_RIGHT_DONE", o->type);         \
-    }
+/* For operators whose type may be any of the given inputs. */
+#define BINOIN_OP_RT_LT_SET(OP, RT, LT)                            \
+  if(o->type==l->type)                                             \
+    BINOIN_OP_OT_RT_LT_SET(OP, LT, RT, LT)                         \
+  else                                                             \
+    BINOIN_OP_OT_RT_LT_SET(OP, RT, RT, LT)
 
 
 
 
 
-#define ONLYINT_LEFT_DONE(LT, OP)                                       \
-  switch(r->type)                                                       \
-    {                                                                   \
-                                                                        \
-      ONLYINT_LEFT_DONE_UCHAR(LT, OP);                                  \
-      ONLYINT_LEFT_DONE_CHAR(LT, OP);                                   \
-      ONLYINT_LEFT_DONE_USHORT(LT, OP);                                 \
-      ONLYINT_LEFT_DONE_SHORT(LT, OP);                                  \
-      ONLYINT_LEFT_DONE_UINT(LT, OP);                                   \
-      ONLYINT_LEFT_DONE_INT(LT, OP);                                    \
-      ONLYINT_LEFT_DONE_ULONG(LT, OP);                                  \
-      ONLYINT_LEFT_DONE_LONG(LT, OP);                                   \
-      ONLYINT_LEFT_DONE_LONGLONG(LT, OP);                               \
-                                                                        \
-    default:                                                            \
-      error(EXIT_FAILURE, 0, "type %d not recognized in "               \
-            "for r->type in ONLYINT_LEFT_DONE", r->type);               \
+/* Left and right types set, choose what to do based on operator. */
+#define BINOIN_RT_LT_SET(RT, LT)                                   \
+  switch(operator)                                                 \
+    {                                                              \
+    case GAL_DATA_OPERATOR_MODULO:                                 \
+      BINOIN_OP_RT_LT_SET(%, RT, LT);                              \
+      break;                                                       \
+    case GAL_DATA_OPERATOR_BITAND:                                 \
+      BINOIN_OP_RT_LT_SET(&, RT, LT);                              \
+      break;                                                       \
+    case GAL_DATA_OPERATOR_BITOR:                                  \
+      BINOIN_OP_RT_LT_SET(|, RT, LT);                              \
+      break;                                                       \
+    case GAL_DATA_OPERATOR_BITXOR:                                 \
+      BINOIN_OP_RT_LT_SET(^, RT, LT);                              \
+      break;                                                       \
+    case GAL_DATA_OPERATOR_BITLSH:                                 \
+      BINOIN_OP_RT_LT_SET(<<, RT, LT);                             \
+      break;                                                       \
+    case GAL_DATA_OPERATOR_BITRSH:                                 \
+      BINOIN_OP_RT_LT_SET(>>, RT, LT);                             \
+      break;                                                       \
+    default:                                                       \
+      error(EXIT_FAILURE, 0, "operator code %d not recognized in " \
+            "`BINOIN_RT_LT_SET", operator);                        \
     }
 
 
 
 
 
-#define ONLYINT_OPERATOR_DONE(OP)                                       \
-  switch(l->type)                                                       \
-    {                                                                   \
-                                                                        \
-      ONLYINT_MULTISWITCH_UCHAR(OP);                                    \
-      ONLYINT_MULTISWITCH_CHAR(OP);                                     \
-      ONLYINT_MULTISWITCH_USHORT(OP);                                   \
-      ONLYINT_MULTISWITCH_SHORT(OP);                                    \
-      ONLYINT_MULTISWITCH_UINT(OP);                                     \
-      ONLYINT_MULTISWITCH_INT(OP);                                      \
-      ONLYINT_MULTISWITCH_ULONG(OP);                                    \
-      ONLYINT_MULTISWITCH_LONG(OP);                                     \
-      ONLYINT_MULTISWITCH_LONGLONG(OP);                                 \
-                                                                        \
-    default:                                                            \
-      error(EXIT_FAILURE, 0, "type %d not recognized in "               \
-            "for l->type in data_arithmetic_onlyint", l->type);         \
-    }
-
-
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-/********************************************************************/
-/****************        Intermediate functions       ***************/
-/********************************************************************/
-static int
-onlyint_type_for_convert_to_compiled_type(int intype)
-{
-  switch(intype)
-    {
-    case GAL_DATA_TYPE_UCHAR:
-      if(GAL_CONFIG_BIN_OP_UCHAR) return GAL_DATA_TYPE_UCHAR;
-      else
-        {
-          if     (GAL_CONFIG_BIN_OP_USHORT)   return GAL_DATA_TYPE_USHORT;
-          else if(GAL_CONFIG_BIN_OP_SHORT)    return GAL_DATA_TYPE_SHORT;
-          else if(GAL_CONFIG_BIN_OP_UINT)     return GAL_DATA_TYPE_UINT;
-          else if(GAL_CONFIG_BIN_OP_INT)      return GAL_DATA_TYPE_INT;
-          else if(GAL_CONFIG_BIN_OP_ULONG)    return GAL_DATA_TYPE_ULONG;
-          else if(GAL_CONFIG_BIN_OP_LONG)     return GAL_DATA_TYPE_LONG;
-          else if(GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
-        }
-      break;
-
-    case GAL_DATA_TYPE_CHAR:
-      if(GAL_CONFIG_BIN_OP_CHAR) return GAL_DATA_TYPE_CHAR;
-      else
-        {
-          if     (GAL_CONFIG_BIN_OP_SHORT)    return GAL_DATA_TYPE_SHORT;
-          else if(GAL_CONFIG_BIN_OP_INT)      return GAL_DATA_TYPE_INT;
-          else if(GAL_CONFIG_BIN_OP_LONG)     return GAL_DATA_TYPE_LONG;
-          else if(GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
-        }
-      break;
-
-    case GAL_DATA_TYPE_USHORT:
-      if(GAL_CONFIG_BIN_OP_USHORT) return GAL_DATA_TYPE_USHORT;
-      else
-        {
-          if     (GAL_CONFIG_BIN_OP_UINT)     return GAL_DATA_TYPE_UINT;
-          else if(GAL_CONFIG_BIN_OP_INT)      return GAL_DATA_TYPE_INT;
-          else if(GAL_CONFIG_BIN_OP_ULONG)    return GAL_DATA_TYPE_ULONG;
-          else if(GAL_CONFIG_BIN_OP_LONG)     return GAL_DATA_TYPE_LONG;
-          else if(GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
-        }
-      break;
-
-    case GAL_DATA_TYPE_SHORT:
-      if(GAL_CONFIG_BIN_OP_SHORT) return GAL_DATA_TYPE_SHORT;
-      else
-        {
-          if     (GAL_CONFIG_BIN_OP_INT)      return GAL_DATA_TYPE_INT;
-          else if(GAL_CONFIG_BIN_OP_LONG)     return GAL_DATA_TYPE_LONG;
-          else if(GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
-        }
-      break;
-
-    case GAL_DATA_TYPE_UINT:
-      if(GAL_CONFIG_BIN_OP_UINT) return GAL_DATA_TYPE_UINT;
-      else
-        {
-          if     (GAL_CONFIG_BIN_OP_ULONG)    return GAL_DATA_TYPE_ULONG;
-          else if(GAL_CONFIG_BIN_OP_LONG)     return GAL_DATA_TYPE_LONG;
-          else if(GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
-        }
-      break;
-
-    case GAL_DATA_TYPE_INT:
-      if(GAL_CONFIG_BIN_OP_INT) return GAL_DATA_TYPE_INT;
-      else
-        {
-          if     (GAL_CONFIG_BIN_OP_LONG)     return GAL_DATA_TYPE_LONG;
-          else if(GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
-        }
-      break;
-
-    case GAL_DATA_TYPE_ULONG:
-      if(GAL_CONFIG_BIN_OP_ULONG) return GAL_DATA_TYPE_ULONG;
-      else
-        {
-          if     (GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
-        }
-      break;
-
-    case GAL_DATA_TYPE_LONG:
-      if(GAL_CONFIG_BIN_OP_LONG) return GAL_DATA_TYPE_LONG;
-      else
-        {
-          if     (GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
-        }
-      break;
-
-    case GAL_DATA_TYPE_LONGLONG:
-      if(GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
-      break;
-
-    default:
-      error(EXIT_FAILURE, 0, "type %d not recognized in "
-            "ONLYINT_CONVERT_TO_COMPILED_TYPE (note that onlyint "
-            "operators only accept integer types)", intype);
-    }
-
-  return 0;
-}
-
-
-
-
-
-/* Note that for signed types, we won't be considering the unsigned types
-   of the larger types. */
-gal_data_t *
-onlyint_convert_to_compiled_type(gal_data_t *in, unsigned char flags)
-{
-  int ntype;
-  char *typestring;
-  gal_data_t *out=NULL;
-
-  /* Set the best compiled type. */
-  ntype=onlyint_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
-        {
-          typestring=gal_data_type_string(in->type);
-          error(EXIT_FAILURE, 0, "The given %s type data given to "
-                "onlyint 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);
-        }
+/* Left operand type set, see what the right operand type is. */
+#define BINOIN_LT_SET(LT)                                          \
+  switch(r->type)                                                  \
+    {                                                              \
+      BINOIN_LT_SET_RT_IS_UCHAR(LT);                               \
+      BINOIN_LT_SET_RT_IS_CHAR(LT);                                \
+      BINOIN_LT_SET_RT_IS_USHORT(LT);                              \
+      BINOIN_LT_SET_RT_IS_SHORT(LT);                               \
+      BINOIN_LT_SET_RT_IS_UINT(LT);                                \
+      BINOIN_LT_SET_RT_IS_INT(LT);                                 \
+      BINOIN_LT_SET_RT_IS_ULONG(LT);                               \
+      BINOIN_LT_SET_RT_IS_LONG(LT);                                \
+      BINOIN_LT_SET_RT_IS_LONGLONG(LT);                            \
+    default:                                                       \
+      error(EXIT_FAILURE, 0, "type code %d not recognized in "     \
+            "`BINOIN_LT_SET'", r->type);                           \
     }
 
-  /* Return the output data structure */
-  if(out==NULL)
-    error(EXIT_FAILURE, 0, "A bug! Please contact us at %s, so we can fix "
-          "the problem. For some reason, the `out' array in "
-          "`onlyint_convert_to_compiled_type' is not set", PACKAGE_BUGREPORT);
-  return out;
-}
 
 
 
@@ -544,51 +320,39 @@ data_arithmetic_onlyint_binary(int operator, unsigned 
char flags,
   /* Read the variable arguments. `lo' and `ro' keep the original data, in
      case their type isn't built (based on configure options are configure
      time). */
+  int otype;
   size_t out_size, minmapsize;
   gal_data_t *l, *r, *o=NULL, *tmp_o;
-  int out_type=0, otype, final_otype;
+  char *opstring=gal_data_operator_string(operator);
 
 
-  /* Simple sanity check on the input sizes */
+  /* Simple sanity check on the input sizes and types */
   if( !( (flags & GAL_DATA_ARITH_NUMOK) && (lo->size==1 || ro->size==1))
       && gal_data_dsize_is_different(lo, ro) )
-    error(EXIT_FAILURE, 0, "ini ONLYINT_INTERNAL, the input datasets "
-          "don't have the same dimension/size");
+    error(EXIT_FAILURE, 0, "the non-number inputs to %s don't have the "
+          "same dimension/size", opstring);
 
+  if( lo->type==GAL_DATA_TYPE_FLOAT || lo->type==GAL_DATA_TYPE_DOUBLE
+      || ro->type==GAL_DATA_TYPE_FLOAT || ro->type==GAL_DATA_TYPE_DOUBLE )
+      error(EXIT_FAILURE, 0, "the %s operator can only work on integer "
+            "type operands", opstring);
 
-  /* Make sure the input arrays have one of the compiled types. */
-  l=onlyint_convert_to_compiled_type(lo, flags);
-  r=onlyint_convert_to_compiled_type(ro, flags);
 
+  /* Make sure the input arrays have one of the compiled types. From this
+     point on, until the cleaning up section of this function, we won't be
+     using the `lo' and `ro' pointers. */
+  l=data_arithmetic_convert_to_compiled_type(lo, flags);
+  r=data_arithmetic_convert_to_compiled_type(ro, flags);
 
-  /* For the left/right shift bitwise operators, the length of the integer
-     matters. So if the lengths of the inputs have changed with these two
-     operators, then print a warning. */
-  if(operator==GAL_DATA_OPERATOR_BITLSH || GAL_DATA_OPERATOR_BITRSH)
-    if(lo->type!=l->type || ro->type!=r->type)
-      error(EXIT_FAILURE, 0, "at least one of the input types to the bitwise "
-            "left or right shift operators was not compiled. The result "
-            "will thus not be what is expected. To configure Gnuastro with "
-            "the respective type, use the following options at configure "
-            "time: `--enable-bin-op-TYPE', run `./configure --help' to see "
-            "the full list.");
 
-
-  /* Set the output type. By default, `out_type' is initialized to zero,
-     this means that the type of the output data structure will be
-     determined based on the inputs. However, for the comparison operators,
-     the output type is either 0 or 1, so we will set the output to
-     unsigned character to save space and memory. Note that since this
-     switch check, is only relevant for certain operators, we don't need a
-     `default' statement.*/
-  final_otype = out_type ? out_type : gal_data_out_type(lo, ro);
-  otype=onlyint_type_for_convert_to_compiled_type(final_otype);
+  /* Set the output type. */
+  otype=gal_data_out_type(l, r);
 
 
   /* Set the output sizes. */
-  minmapsize = ( lo->minmapsize < ro->minmapsize
-                 ? lo->minmapsize : ro->minmapsize );
-  out_size = lo->size > ro->size ? lo->size : ro->size;
+  minmapsize = ( l->minmapsize < r->minmapsize
+                 ? l->minmapsize : r->minmapsize );
+  out_size = l->size > r->size ? l->size : r->size;
 
 
   /* If we want inplace output, set the output pointer to one input. Note
@@ -610,33 +374,35 @@ data_arithmetic_onlyint_binary(int operator, unsigned 
char flags,
     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, minmapsize );
+                       l->size>1 ? l->wcs   : r->wcs,
+                       0, minmapsize );
 
 
   /* Start setting the operator and operands. */
-  switch(operator)
+  switch(l->type)
     {
-    case GAL_DATA_OPERATOR_MODULO:     ONLYINT_OPERATOR_DONE( %  ); break;
-    case GAL_DATA_OPERATOR_BITAND:     ONLYINT_OPERATOR_DONE( &  ); break;
-    case GAL_DATA_OPERATOR_BITOR:      ONLYINT_OPERATOR_DONE( |  ); break;
-    case GAL_DATA_OPERATOR_BITXOR:     ONLYINT_OPERATOR_DONE( ^  ); break;
-    case GAL_DATA_OPERATOR_BITLSH:     ONLYINT_OPERATOR_DONE( << ); break;
-    case GAL_DATA_OPERATOR_BITRSH:     ONLYINT_OPERATOR_DONE( >> ); break;
+      BINOIN_LT_IS_UCHAR;
+      BINOIN_LT_IS_CHAR;
+      BINOIN_LT_IS_USHORT;
+      BINOIN_LT_IS_SHORT;
+      BINOIN_LT_IS_UINT;
+      BINOIN_LT_IS_INT;
+      BINOIN_LT_IS_ULONG;
+      BINOIN_LT_IS_LONG;
+      BINOIN_LT_IS_LONGLONG;
     default:
-      error(EXIT_FAILURE, 0, "Operator code %d not recognized in "
-            "data_arithmetic_onlyint when preparing for the operation",
-            operator);
+      error(EXIT_FAILURE, 0, "type code %d not recognized in "
+            "`data_arithmetic_binary'", l->type);
     }
 
 
   /* Clean up. Note that if the input arrays can be freed, and any of right
-     or left arrays needed conversion, `ONLYINT_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 onlyint operations, we can tell this from
-     the pointers: if they are different from the original pointers, they
-     were allocated. */
+     or left arrays needed conversion, `BINOIN_CONVERT_TO_COMPILED_TYPE'
+     has already freed the input arrays, so only `r' and `l' need
+     freeing. 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);
@@ -649,11 +415,15 @@ data_arithmetic_onlyint_binary(int operator, unsigned 
char flags,
       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)
+  /* The type of the output dataset (`o->type') was chosen from `l' and `r'
+     (copies of the orignal operands but in a compiled type, not
+     necessarily the original `lo' and `ro' data structures). So we need to
+     to get the final type based on the original operands and check if the
+     final output needs changing. */
+  otype=gal_data_out_type(lo, ro);
+  if( o->type != otype )
     {
-      tmp_o=gal_data_copy_to_new_type(o, final_otype);
+      tmp_o=gal_data_copy_to_new_type(o, otype);
       gal_data_free(o);
       o=tmp_o;
     }
diff --git a/lib/data.c b/lib/data.c
index f862bca..41dd5fc 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -1697,6 +1697,197 @@ gal_data_operator_string(int operator)
 
 
 
+static int
+data_arithmetic_nearest_compiled_type(int intype)
+{
+  switch(intype)
+    {
+    case GAL_DATA_TYPE_UCHAR:
+      if(GAL_CONFIG_BIN_OP_UCHAR) return GAL_DATA_TYPE_UCHAR;
+      else
+        {
+          if     (GAL_CONFIG_BIN_OP_USHORT)   return GAL_DATA_TYPE_USHORT;
+          else if(GAL_CONFIG_BIN_OP_SHORT)    return GAL_DATA_TYPE_SHORT;
+          else if(GAL_CONFIG_BIN_OP_UINT)     return GAL_DATA_TYPE_UINT;
+          else if(GAL_CONFIG_BIN_OP_INT)      return GAL_DATA_TYPE_INT;
+          else if(GAL_CONFIG_BIN_OP_ULONG)    return GAL_DATA_TYPE_ULONG;
+          else if(GAL_CONFIG_BIN_OP_LONG)     return GAL_DATA_TYPE_LONG;
+          else if(GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
+          else if(GAL_CONFIG_BIN_OP_FLOAT)    return GAL_DATA_TYPE_FLOAT;
+          else if(GAL_CONFIG_BIN_OP_DOUBLE)   return GAL_DATA_TYPE_DOUBLE;
+        }
+      break;
+
+    case GAL_DATA_TYPE_CHAR:
+      if(GAL_CONFIG_BIN_OP_CHAR) return GAL_DATA_TYPE_CHAR;
+      else
+        {
+          if     (GAL_CONFIG_BIN_OP_SHORT)    return GAL_DATA_TYPE_SHORT;
+          else if(GAL_CONFIG_BIN_OP_INT)      return GAL_DATA_TYPE_INT;
+          else if(GAL_CONFIG_BIN_OP_LONG)     return GAL_DATA_TYPE_LONG;
+          else if(GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
+          else if(GAL_CONFIG_BIN_OP_FLOAT)    return GAL_DATA_TYPE_FLOAT;
+          else if(GAL_CONFIG_BIN_OP_DOUBLE)   return GAL_DATA_TYPE_DOUBLE;
+        }
+      break;
+
+    case GAL_DATA_TYPE_USHORT:
+      if(GAL_CONFIG_BIN_OP_USHORT) return GAL_DATA_TYPE_USHORT;
+      else
+        {
+          if     (GAL_CONFIG_BIN_OP_UINT)     return GAL_DATA_TYPE_UINT;
+          else if(GAL_CONFIG_BIN_OP_INT)      return GAL_DATA_TYPE_INT;
+          else if(GAL_CONFIG_BIN_OP_ULONG)    return GAL_DATA_TYPE_ULONG;
+          else if(GAL_CONFIG_BIN_OP_LONG)     return GAL_DATA_TYPE_LONG;
+          else if(GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
+          else if(GAL_CONFIG_BIN_OP_FLOAT)    return GAL_DATA_TYPE_FLOAT;
+          else if(GAL_CONFIG_BIN_OP_DOUBLE)   return GAL_DATA_TYPE_DOUBLE;
+        }
+      break;
+
+    case GAL_DATA_TYPE_SHORT:
+      if(GAL_CONFIG_BIN_OP_SHORT) return GAL_DATA_TYPE_SHORT;
+      else
+        {
+          if     (GAL_CONFIG_BIN_OP_INT)      return GAL_DATA_TYPE_INT;
+          else if(GAL_CONFIG_BIN_OP_LONG)     return GAL_DATA_TYPE_LONG;
+          else if(GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
+          else if(GAL_CONFIG_BIN_OP_FLOAT)    return GAL_DATA_TYPE_FLOAT;
+          else if(GAL_CONFIG_BIN_OP_DOUBLE)   return GAL_DATA_TYPE_DOUBLE;
+        }
+      break;
+
+    case GAL_DATA_TYPE_UINT:
+      if(GAL_CONFIG_BIN_OP_UINT) return GAL_DATA_TYPE_UINT;
+      else
+        {
+          if     (GAL_CONFIG_BIN_OP_ULONG)    return GAL_DATA_TYPE_ULONG;
+          else if(GAL_CONFIG_BIN_OP_LONG)     return GAL_DATA_TYPE_LONG;
+          else if(GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
+          else if(GAL_CONFIG_BIN_OP_FLOAT)    return GAL_DATA_TYPE_FLOAT;
+          else if(GAL_CONFIG_BIN_OP_DOUBLE)   return GAL_DATA_TYPE_DOUBLE;
+        }
+      break;
+
+    case GAL_DATA_TYPE_INT:
+      if(GAL_CONFIG_BIN_OP_INT) return GAL_DATA_TYPE_INT;
+      else
+        {
+          if     (GAL_CONFIG_BIN_OP_LONG)     return GAL_DATA_TYPE_LONG;
+          else if(GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
+          else if(GAL_CONFIG_BIN_OP_FLOAT)    return GAL_DATA_TYPE_FLOAT;
+          else if(GAL_CONFIG_BIN_OP_DOUBLE)   return GAL_DATA_TYPE_DOUBLE;
+        }
+      break;
+
+    case GAL_DATA_TYPE_ULONG:
+      if(GAL_CONFIG_BIN_OP_ULONG) return GAL_DATA_TYPE_ULONG;
+      else
+        {
+          if     (GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
+          else if(GAL_CONFIG_BIN_OP_FLOAT)    return GAL_DATA_TYPE_FLOAT;
+          else if(GAL_CONFIG_BIN_OP_DOUBLE)   return GAL_DATA_TYPE_DOUBLE;
+        }
+      break;
+
+    case GAL_DATA_TYPE_LONG:
+      if(GAL_CONFIG_BIN_OP_LONG) return GAL_DATA_TYPE_LONG;
+      else
+        {
+          if     (GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
+          else if(GAL_CONFIG_BIN_OP_FLOAT)    return GAL_DATA_TYPE_FLOAT;
+          else if(GAL_CONFIG_BIN_OP_DOUBLE)   return GAL_DATA_TYPE_DOUBLE;
+        }
+      break;
+
+    case GAL_DATA_TYPE_LONGLONG:
+      if(GAL_CONFIG_BIN_OP_LONGLONG) return GAL_DATA_TYPE_LONGLONG;
+      else
+        {
+          if     (GAL_CONFIG_BIN_OP_FLOAT)    return GAL_DATA_TYPE_FLOAT;
+          else if(GAL_CONFIG_BIN_OP_DOUBLE)   return GAL_DATA_TYPE_DOUBLE;
+        }
+      break;
+
+    case GAL_DATA_TYPE_FLOAT:
+      if(GAL_CONFIG_BIN_OP_FLOAT) return GAL_DATA_TYPE_FLOAT;
+      else
+        {
+          if     (GAL_CONFIG_BIN_OP_DOUBLE)   return GAL_DATA_TYPE_DOUBLE;
+        }
+      break;
+
+    case GAL_DATA_TYPE_DOUBLE:
+      if         (GAL_CONFIG_BIN_OP_DOUBLE)   return GAL_DATA_TYPE_DOUBLE;
+      break;
+
+    default:
+      error(EXIT_FAILURE, 0, "type %d not recognized in "
+            "binary_type_for_convert_to_compiled_type", intype);
+    }
+
+  return 0;
+}
+
+
+
+
+
+/* Note that for signed types, we won't be considering the unsigned types
+   of the larger types. */
+gal_data_t *
+data_arithmetic_convert_to_compiled_type(gal_data_t *in, unsigned char flags)
+{
+  int ntype;
+  char *typestring;
+  gal_data_t *out=NULL;
+
+  /* Set the best compiled type. */
+  ntype=data_arithmetic_nearest_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
+        {
+          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 decrease 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);
+        }
+    }
+
+  /* Return the output data structure */
+  if(out==NULL)
+    error(EXIT_FAILURE, 0, "A bug! Please contact us at %s, so we can fix "
+          "the problem. For some reason, the `out' array in "
+          "`binary_convert_to_compiled_type' is not set", PACKAGE_BUGREPORT);
+  return out;
+}
+
+
+
+
+
 gal_data_t *
 gal_data_arithmetic(int operator, unsigned char flags, ...)
 {
diff --git a/lib/gnuastro/data.h b/lib/gnuastro/data.h
index 138e28f..579dd2a 100644
--- a/lib/gnuastro/data.h
+++ b/lib/gnuastro/data.h
@@ -352,6 +352,11 @@ char *
 gal_data_operator_string(int operator);
 
 gal_data_t *
+data_arithmetic_convert_to_compiled_type(gal_data_t *in, unsigned char flags);
+
+
+
+gal_data_t *
 gal_data_arithmetic(int operator, unsigned char flags, ...);
 
 



reply via email to

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