gnuastro-commits
[Top][All Lists]
Advanced

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

[gnuastro-commits] master 0ad0906 014/125: Bitwise operators available i


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master 0ad0906 014/125: Bitwise operators available in arithmetic operations
Date: Sun, 23 Apr 2017 22:36:27 -0400 (EDT)

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

    Bitwise operators available in arithmetic operations
    
    Mask images in astronomy commonly use bit values where every bit has a
    special meaning. Therefore bitwise operators are important in low-level
    analysis of the data. With this commit, Gnuastro's `gal_data_arithmetic'
    function and thus the Arithmetic program now support bitwise operators on
    integer types.
    
    Some other minor works in this commit:
    
     - Two new blank pixel related functions have been added:
       `gal_data_has_blank' and `gal_data_flag_blank'.
    
     - Three new operators added to `gal_data_arithmetic': "modulo"
       (remainder), "isblank", and "not".
    
     - The message at the end of configure also lets the users know that some
       libraries will take a while to compile.
    
     - Work has also started on unary operators.
    
    This finishes task #13868.
---
 bin/arithmetic/arithmetic.c   |  69 +++--
 configure.ac                  |  11 +-
 doc/gnuastro.texi             |  59 +++-
 lib/Makefile.am               |  11 +-
 lib/data-arithmetic-onlyint.c | 663 ++++++++++++++++++++++++++++++++++++++++++
 lib/data-arithmetic-onlyint.h |  32 ++
 lib/data-arithmetic-unary.c   | 100 +++++++
 lib/data-arithmetic-unary.h   |  31 ++
 lib/data.c                    | 333 ++++++++++++++++++++-
 lib/gnuastro/data.h           |  11 +
 10 files changed, 1270 insertions(+), 50 deletions(-)

diff --git a/bin/arithmetic/arithmetic.c b/bin/arithmetic/arithmetic.c
index 13883f6..ffc94a5 100644
--- a/bin/arithmetic/arithmetic.c
+++ b/bin/arithmetic/arithmetic.c
@@ -91,6 +91,8 @@ reversepolish(struct imgarithparams *p)
         add_operand(p, NULL, d1);
       else
         {
+          /* Order is the same as in the manual. */
+          /* Simple arithmetic operators. */
           if      (!strcmp(token->v, "+" ))
             { op=GAL_DATA_OPERATOR_PLUS;          nop=2;  }
           else if (!strcmp(token->v, "-" ))
@@ -99,7 +101,36 @@ reversepolish(struct imgarithparams *p)
             { op=GAL_DATA_OPERATOR_MULTIPLY;      nop=2;  }
           else if (!strcmp(token->v, "/" ))
             { op=GAL_DATA_OPERATOR_DIVIDE;        nop=2;  }
+          else if (!strcmp(token->v, "%" ))
+            { op=GAL_DATA_OPERATOR_REMAINDER;     nop=2;  }
 
+          /* Mathematical Operators. */
+          else if (!strcmp(token->v, "abs"))
+            { op=GAL_DATA_OPERATOR_ABS;           nop=1;  }
+          else if (!strcmp(token->v, "pow"))
+            { op=GAL_DATA_OPERATOR_POW;           nop=2;  }
+          else if (!strcmp(token->v, "sqrt"))
+            { op=GAL_DATA_OPERATOR_SQRT;          nop=1;  }
+          else if (!strcmp(token->v, "log"))
+            { op=GAL_DATA_OPERATOR_LOG;           nop=1;  }
+          else if (!strcmp(token->v, "log10"))
+            { op=GAL_DATA_OPERATOR_LOG10;         nop=1;  }
+
+          /* Statistical operators. */
+          else if (!strcmp(token->v, "minval"))
+            { op=GAL_DATA_OPERATOR_MINVAL;        nop=1;  }
+          else if (!strcmp(token->v, "maxval"))
+            { op=GAL_DATA_OPERATOR_MAXVAL;        nop=1;  }
+          else if (!strcmp(token->v, "min"))
+            { op=GAL_DATA_OPERATOR_MIN;           nop=-1; }
+          else if (!strcmp(token->v, "max"))
+            { op=GAL_DATA_OPERATOR_MAX;           nop=-1; }
+          else if (!strcmp(token->v, "average"))
+            { op=GAL_DATA_OPERATOR_AVERAGE;       nop=-1; }
+          else if (!strcmp(token->v, "median"))
+            { op=GAL_DATA_OPERATOR_MEDIAN;        nop=-1; }
+
+          /* Conditional operators. */
           else if (!strcmp(token->v, "lt" ))
             { op=GAL_DATA_OPERATOR_LT;            nop=2;  }
           else if (!strcmp(token->v, "le"))
@@ -116,11 +147,6 @@ reversepolish(struct imgarithparams *p)
             { op=GAL_DATA_OPERATOR_AND;           nop=2;  }
           else if (!strcmp(token->v, "or"))
             { op=GAL_DATA_OPERATOR_OR;            nop=2;  }
-          else if (!strcmp(token->v, "bitand"))
-            { op=GAL_DATA_OPERATOR_BITAND;        nop=2;  }
-          else if (!strcmp(token->v, "bitor"))
-            { op=GAL_DATA_OPERATOR_BITOR;         nop=2;  }
-
           else if (!strcmp(token->v, "not"))
             { op=GAL_DATA_OPERATOR_NOT;           nop=1;  }
           else if (!strcmp(token->v, "isblank"))
@@ -128,29 +154,18 @@ reversepolish(struct imgarithparams *p)
           else if (!strcmp(token->v, "where"))
             { op=GAL_DATA_OPERATOR_WHERE;         nop=3;  }
 
-          else if (!strcmp(token->v, "abs"))
-            { op=GAL_DATA_OPERATOR_ABS;           nop=1;  }
-          else if (!strcmp(token->v, "pow"))
-            { op=GAL_DATA_OPERATOR_POW;           nop=2;  }
-          else if (!strcmp(token->v, "sqrt"))
-            { op=GAL_DATA_OPERATOR_SQRT;          nop=1;  }
-          else if (!strcmp(token->v, "log"))
-            { op=GAL_DATA_OPERATOR_LOG;           nop=1;  }
-          else if (!strcmp(token->v, "log10"))
-            { op=GAL_DATA_OPERATOR_LOG10;         nop=1;  }
+          /* Bitwise operators. */
+          else if (!strcmp(token->v, "bitand"))
+            { op=GAL_DATA_OPERATOR_BITAND;        nop=2;  }
+          else if (!strcmp(token->v, "bitor"))
+            { op=GAL_DATA_OPERATOR_BITOR;         nop=2;  }
+          else if (!strcmp(token->v, "bitxor"))
+            { op=GAL_DATA_OPERATOR_BITXOR;        nop=2;  }
+          else if (!strcmp(token->v, "lshift"))
+            { op=GAL_DATA_OPERATOR_BITLSH;        nop=2;  }
+          else if (!strcmp(token->v, "rshift"))
+            { op=GAL_DATA_OPERATOR_BITRSH;        nop=2;  }
 
-          else if (!strcmp(token->v, "minval"))
-            { op=GAL_DATA_OPERATOR_MINVAL;        nop=1;  }
-          else if (!strcmp(token->v, "maxval"))
-            { op=GAL_DATA_OPERATOR_MAXVAL;        nop=1;  }
-          else if (!strcmp(token->v, "min"))
-            { op=GAL_DATA_OPERATOR_MIN;           nop=-1; }
-          else if (!strcmp(token->v, "max"))
-            { op=GAL_DATA_OPERATOR_MAX;           nop=-1; }
-          else if (!strcmp(token->v, "average"))
-            { op=GAL_DATA_OPERATOR_AVERAGE;       nop=-1; }
-          else if (!strcmp(token->v, "median"))
-            { op=GAL_DATA_OPERATOR_MEDIAN;        nop=-1; }
           else
             error(EXIT_FAILURE, 0, "the argument \"%s\" could not be "
                   "interpretted as a FITS file, number, or operator",
diff --git a/configure.ac b/configure.ac
index 0ae190c..d2a13c1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -675,8 +675,8 @@ AC_OUTPUT
 AS_IF([test x$enable_guide_message = xyes],
 [
   AS_ECHO([])
-  
AS_ECHO([===================================================================])
-  
AS_ECHO([===================================================================])
+  
AS_ECHO([====================================================================])
+  
AS_ECHO([====================================================================])
   AS_ECHO(["$PACKAGE_NAME (Gnuastro) $PACKAGE_VERSION is successfully"])
   AS_ECHO(["configured for this machine."])
   AS_ECHO([])
@@ -709,9 +709,10 @@ AS_IF([test x$enable_guide_message = xyes],
   AS_ECHO([])
   AS_ECHO(["    make"])
   AS_ECHO([])
-  AS_ECHO(["(Build faster on N threads with 'make -jN'.)"])
+  AS_ECHO(["(RECOMMENDED: Build faster on N threads with 'make -jN'.)"])
   AS_ECHO(["(Configure with '--disable-guide-message' for no messages.)"])
-  
AS_ECHO([===================================================================])
-  
AS_ECHO([===================================================================])
+  AS_ECHO(["(Please be patient, some libraries take a few minutes to 
compile.)"])
+  
AS_ECHO([====================================================================])
+  
AS_ECHO([====================================================================])
   AS_ECHO([])
 ])
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index 4a6bbb7..b84329c 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -7145,6 +7145,10 @@ the multiplication sign (for example @command{"*"}).
 @item /
 Division, so address@hidden 5 /}'' is equivalent to @mymath{4/5}.
 
address@hidden %
+Remainder, so address@hidden 2 %}'' is equivalent to @mymath{1}. Note that
+the remainder operator only works on integer types.
+
 @item abs
 Absolute value of first operand, so address@hidden abs}'' is
 equivalent to @mymath{|4|}.
@@ -7245,16 +7249,6 @@ Non-Equality: similar to @code{lt} (`less than' 
operator), but returning 1
 when the two popped operands are @emph{not} equal (to double precision
 floating point accuracy).
 
address@hidden Blank pixel
address@hidden isblank
-Test for a blank value (see @ref{Blank pixels}). In essence, this is very
-similar to the conditional operators: the output is either 1 or 0 (see the
-`less than' operator above). The difference is that it only needs one
-operand. Because of the definition of a blank pixel, a blank value is not
-even equal to itself, so you cannot use the equal operator above to select
-blank pixels. See the ``Blank pixels'' box below for more on Blank pixels
-in Arithmetic.
-
 @item and
 Logical AND: returns 1 if both operands have a non-zero value and 0 if both
 are zero. Both operands have to be the same kind: either both images or
@@ -7270,6 +7264,16 @@ Logical NOT: returns 1 when the operand is zero and 0 
when the operand is
 non-zero. The operand can be an image or number, for an image, it is
 applied to each pixel separately.
 
address@hidden Blank pixel
address@hidden isblank
+Test for a blank value (see @ref{Blank pixels}). In essence, this is very
+similar to the conditional operators: the output is either 1 or 0 (see the
+`less than' operator above). The difference is that it only needs one
+operand. Because of the definition of a blank pixel, a blank value is not
+even equal to itself, so you cannot use the equal operator above to select
+blank pixels. See the ``Blank pixels'' box below for more on Blank pixels
+in Arithmetic.
+
 @item where
 Change the input (pixel) value `where' a certain condition holds. The
 conditional operators above can be used to define the condition. Three
@@ -7297,6 +7301,41 @@ internally. For example the case below:
 $ astarithmetic in.fits reference.fits 100 gt new.fits where
 @end example
 
address@hidden bitand
+Bitwise AND operator: only bits with values of 1 will get the value of 1,
+the rest will be set to 0. For example (assuming numbers can be written as
+bit strings on the command-line): @code{00101000 00100010 bitand} will give
address@hidden Note that the bitwise operators only work on integer type
+datasets.
+
address@hidden bitor
+Bitwise inclusive OR operator: The bit will stay 1 if atleast one of the
+two inputs has a 1 value on that bit. For example (assuming numbers can be
+written as bit strings on the command-line): @code{00101000 00100010
+bitand} will give @code{00101010}. Note that the bitwise operators only
+work on integer type datasets.
+
address@hidden bitxor
+Bitwise exclusive OR operator: A bit will be 1 if it differs between the
+two inputs. For example (assuming numbers can be written as bit strings on
+the command-line): @code{00101000 00100010 bitand} will give
address@hidden Note that the bitwise operators only work on integer type
+datasets.
+
address@hidden lshift
+Bitwise left shift operator: shift all the bits of the first operand to the
+left by a number of times given by the second operand. For example
+(assuming numbers can be written as bit strings on the command-line):
address@hidden 2 lshift} will give @code{10100000}. This is equivalent to
+multiplication by 4.  Note that the bitwise operators only work on integer
+type datasets.
+
address@hidden rshift
+Bitwise right shift operator: shift all the bits of the first operand to
+the right by a number of times given by the second operand. For example
+(assuming numbers can be written as bit strings on the command-line):
address@hidden 2 rshift} will give @code{00001010}. Note that the bitwise
+operators only work on integer type datasets.
 
 @end table
 
diff --git a/lib/Makefile.am b/lib/Makefile.am
index d363c0a..09f2c9c 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -41,7 +41,8 @@ libgnuastro_la_LDFLAGS = -version-info $(GAL_LT_VERSION)
 
 # Specify the library .c files
 libgnuastro_la_SOURCES = array.c box.c checkset.c configfiles.c data.c  \
-  data-arithmetic-binary.c data-copy.c fits.c git.c linkedlist.c mesh.c \
+  data-arithmetic-binary.c data-arithmetic-onlyint.c                    \
+  data-arithmetic-unary.c data-copy.c fits.c git.c linkedlist.c mesh.c  \
   mode.c polygon.c qsort.c spatialconvolve.c statistics.c threads.c     \
   timing.c txtarray.c wcs.c
 
@@ -69,10 +70,10 @@ pkginclude_HEADERS = gnuastro/config.h 
$(headersdir)/array.h            \
 # and if they are not explicitly mentioned somewhere in the Makefile, they
 # will not distributed, so we need to explicitly tell Automake to
 # distribute them here.
-EXTRA_DIST = gnuastro.pc.in data-arithmetic.h data-arithmetic-binary.h  \
-  data-copy.h config.h.in checkset.h commonargs.h commonparams.h        \
-  configfiles.h fixedstringmacros.h mode.h neighbors.h timing.h         \
-  $(headersdir)/README
+EXTRA_DIST = gnuastro.pc.in data-arithmetic.h data-arithmetic-binary.h \
+  data-arithmetic-onlyint.h data-arithmetic-unary.h data-copy.h         \
+  config.h.in checkset.h commonargs.h commonparams.h configfiles.h      \
+  fixedstringmacros.h mode.h neighbors.h timing.h $(headersdir)/README
 
 
 
diff --git a/lib/data-arithmetic-onlyint.c b/lib/data-arithmetic-onlyint.c
new file mode 100644
index 0000000..9b247d0
--- /dev/null
+++ b/lib/data-arithmetic-onlyint.c
@@ -0,0 +1,663 @@
+/*********************************************************************
+Arithmetic operations on data structures.
+This is part of GNU Astronomy Utilities (Gnuastro) package.
+
+Original author:
+     Mohammad Akhlaghi <address@hidden>
+Contributing author(s):
+Copyright (C) 2016, Free Software Foundation, Inc.
+
+Gnuastro is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+Gnuastro is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
+**********************************************************************/
+#include <config.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <error.h>
+#include <stdlib.h>
+
+#include <gnuastro/data.h>
+#include <data-arithmetic-onlyint.h>
+
+
+
+/************************************************************************/
+/*************      Possibly set onlyint types to convert    *************/
+/************************************************************************/
+#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;
+#else
+#define ONLYINT_LEFT_RIGHT_DONE_UCHAR(LT, RT, OP)
+#define ONLYINT_LEFT_DONE_UCHAR(LT, OP)
+#define ONLYINT_MULTISWITCH_UCHAR(OP)
+#endif
+
+
+
+
+
+#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);                         \
+    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)
+#endif
+
+
+
+
+
+#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);               \
+    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)
+#endif
+
+
+
+
+
+#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);                        \
+    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)
+#endif
+
+
+
+
+
+#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);                 \
+    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)
+#endif
+
+
+
+
+
+#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);                          \
+    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)
+#endif
+
+
+
+
+
+#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;
+#else
+#define ONLYINT_LEFT_RIGHT_DONE_ULONG(LT, RT, OP)
+#define ONLYINT_LEFT_DONE_ULONG(LT, OP)
+#define ONLYINT_MULTISWITCH_ULONG(OP)
+#endif
+
+
+
+
+
+#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;
+#else
+#define ONLYINT_LEFT_RIGHT_DONE_LONG(LT, RT, OP)
+#define ONLYINT_LEFT_DONE_LONG(LT, OP)
+#define ONLYINT_MULTISWITCH_LONG(OP)
+#endif
+
+
+
+
+
+#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;
+#else
+#define ONLYINT_LEFT_RIGHT_DONE_LONGLONG(LT, RT, OP)
+#define ONLYINT_LEFT_DONE_LONGLONG(LT, OP)
+#define ONLYINT_MULTISWITCH_LONGLONG(OP)
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/************************************************************************/
+/*************       Macros for specifying the type     *****************/
+/************************************************************************/
+
+#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);       \
+  }
+
+
+
+
+
+#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);         \
+    }
+
+
+
+
+
+#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);               \
+    }
+
+
+
+
+
+#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);
+        }
+    }
+
+  /* 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;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/************************************************************************/
+/*************              Top level function          *****************/
+/************************************************************************/
+gal_data_t *
+data_arithmetic_onlyint_binary(int operator, unsigned char flags,
+                               gal_data_t *lo, gal_data_t *ro)
+{
+  /* 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). */
+  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 ONLYINT_INTERNAL, the input datasets "
+          "don't have the same dimension/size");
+
+
+  /* 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);
+
+
+  /* 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 sizes. */
+  minmapsize = ( lo->minmapsize < ro->minmapsize
+                 ? lo->minmapsize : ro->minmapsize );
+  out_size = lo->size > ro->size ? lo->size : ro->size;
+
+
+  /* If we want inplace output, set the output pointer to one input. Note
+     that the output type can be different from both inputs.  */
+  if(flags & GAL_DATA_ARITH_INPLACE)
+    {
+      if     (l->type==otype && out_size==l->size)   o = l;
+      else if(r->type==otype && out_size==r->size)   o = r;
+    }
+
+
+  /* If the output pointer was not set for any reason, allocate it. For
+     `mmapsize', note that since its `size_t', it will always be
+     Positive. The `-1' that is recommended to give when you want the value
+     in RAM is actually the largest possible memory location. So we just
+     have to choose the smaller minmapsize of the two to decide if the
+     output array should be in RAM or not. */
+  if(o==NULL)
+    o = gal_data_alloc(NULL, otype,
+                       l->size>1 ? l->ndim  : r->ndim,
+                       l->size>1 ? l->dsize : r->dsize,
+                       l->size>1 ? l->wcs : r->wcs, 0, minmapsize );
+
+
+  /* Start setting the operator and operands. */
+  switch(operator)
+    {
+    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;
+    default:
+      error(EXIT_FAILURE, 0, "Operator code %d not recognized in "
+            "data_arithmetic_onlyint when preparing for the operation",
+            operator);
+    }
+
+
+  /* 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. */
+  if(flags & GAL_DATA_ARITH_FREE)
+    {
+      if     (o==l)       gal_data_free(r);
+      else if(o==r)       gal_data_free(l);
+      else              { gal_data_free(l); gal_data_free(r); }
+    }
+  else
+    {
+      if(l!=lo)           gal_data_free(l);
+      if(r!=ro)           gal_data_free(r);
+    }
+
+  /* In case otype and final_otype aren't equal, we need to convert the
+     output data structure to the proper type. */
+  if(otype!=final_otype)
+    {
+      tmp_o=gal_data_copy_to_new_type(o, final_otype);
+      gal_data_free(o);
+      o=tmp_o;
+    }
+
+  /* Return */
+  return o;
+}
diff --git a/lib/data-arithmetic-onlyint.h b/lib/data-arithmetic-onlyint.h
new file mode 100644
index 0000000..afe255e
--- /dev/null
+++ b/lib/data-arithmetic-onlyint.h
@@ -0,0 +1,32 @@
+/*********************************************************************
+Arithmetic operations on data structures.
+This is part of GNU Astronomy Utilities (Gnuastro) package.
+
+Original author:
+     Mohammad Akhlaghi <address@hidden>
+Contributing author(s):
+Copyright (C) 2015, Free Software Foundation, Inc.
+
+Gnuastro is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+Gnuastro is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
+**********************************************************************/
+#ifndef __GAL_ARITHMETIC_ONLYINT_H__
+#define __GAL_ARITHMETIC_ONLYINT_H__
+
+
+gal_data_t *
+data_arithmetic_onlyint_binary(int operator, unsigned char flags,
+                               gal_data_t *lo, gal_data_t *ro);
+
+
+#endif
diff --git a/lib/data-arithmetic-unary.c b/lib/data-arithmetic-unary.c
new file mode 100644
index 0000000..2ffbd7e
--- /dev/null
+++ b/lib/data-arithmetic-unary.c
@@ -0,0 +1,100 @@
+/*********************************************************************
+Arithmetic operations on data structures.
+This is part of GNU Astronomy Utilities (Gnuastro) package.
+
+Original author:
+     Mohammad Akhlaghi <address@hidden>
+Contributing author(s):
+Copyright (C) 2016, Free Software Foundation, Inc.
+
+Gnuastro is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+Gnuastro is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
+**********************************************************************/
+#include <config.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <error.h>
+#include <stdlib.h>
+
+#include <gnuastro/data.h>
+
+
+
+
+/* Return an array of value 1 for any zero valued element and zero for any
+   non-zero valued element. */
+#define TYPE_CASE_FOR_NOT(TYPE, IN, IN_FINISH) {                        \
+    case TYPE:                                                          \
+      do *o++ = !*IN; while(++IN<IN_FINISH);                            \
+      break;                                                            \
+  }
+
+gal_data_t *
+data_arithmetic_not(gal_data_t *data)
+{
+  gal_data_t *out;
+
+  /* 'value' will only be read from one of these based on the
+     datatype. Which the caller assigned. If there is any problem, it is
+     their responsability, not this function's.*/
+  void *A=data->array;
+  size_t S=data->size;
+  unsigned char     *uc = A,   *ucf = A+S, *o;
+  char               *c = A,    *cf = A+S;
+  unsigned short    *us = A,   *usf = A+S;
+  short              *s = A,    *sf = A+S;
+  unsigned int      *ui = A,   *uif = A+S;
+  int               *in = A,   *inf = A+S;
+  unsigned long     *ul = A,   *ulf = A+S;
+  long               *l = A,    *lf = A+S;
+  LONGLONG           *L = A,    *Lf = A+S;
+  float              *f = A,    *ff = A+S;
+  double             *d = A,    *df = A+S;
+
+
+  /* Allocate the output array. */
+  out=gal_data_alloc(NULL, GAL_DATA_TYPE_UCHAR, data->ndim, data->dsize,
+                     data->wcs, 0, data->minmapsize);
+  o=out->array;
+
+
+  /* Go over the pixels and set the output values. */
+  switch(data->type)
+    {
+
+    TYPE_CASE_FOR_NOT(GAL_DATA_TYPE_UCHAR,    uc,  ucf)
+    TYPE_CASE_FOR_NOT(GAL_DATA_TYPE_CHAR,     c,   cf)
+    TYPE_CASE_FOR_NOT(GAL_DATA_TYPE_LOGICAL,  c,   cf)
+    TYPE_CASE_FOR_NOT(GAL_DATA_TYPE_USHORT,   us,  usf)
+    TYPE_CASE_FOR_NOT(GAL_DATA_TYPE_SHORT,    s,   sf)
+    TYPE_CASE_FOR_NOT(GAL_DATA_TYPE_UINT,     ui,  uif)
+    TYPE_CASE_FOR_NOT(GAL_DATA_TYPE_INT,      in,  inf)
+    TYPE_CASE_FOR_NOT(GAL_DATA_TYPE_ULONG,    ul,  ulf)
+    TYPE_CASE_FOR_NOT(GAL_DATA_TYPE_LONG,     l,   lf)
+    TYPE_CASE_FOR_NOT(GAL_DATA_TYPE_LONGLONG, L,   Lf)
+    TYPE_CASE_FOR_NOT(GAL_DATA_TYPE_FLOAT,    f,   ff)
+    TYPE_CASE_FOR_NOT(GAL_DATA_TYPE_DOUBLE,   d,   df)
+
+    case GAL_DATA_TYPE_BIT:
+      error(EXIT_FAILURE, 0, "Currently Gnuastro doesn't support bit "
+            "datatype, please get in touch with us to implement it.");
+
+    default:
+      error(EXIT_FAILURE, 0, "type value (%d) not recognized "
+            "in `data_arithmetic_not'", data->type);
+    }
+
+  /* Return */
+  return out;
+}
diff --git a/lib/data-arithmetic-unary.h b/lib/data-arithmetic-unary.h
new file mode 100644
index 0000000..50954f0
--- /dev/null
+++ b/lib/data-arithmetic-unary.h
@@ -0,0 +1,31 @@
+/*********************************************************************
+Arithmetic operations on data structures.
+This is part of GNU Astronomy Utilities (Gnuastro) package.
+
+Original author:
+     Mohammad Akhlaghi <address@hidden>
+Contributing author(s):
+Copyright (C) 2015, Free Software Foundation, Inc.
+
+Gnuastro is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+Gnuastro is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
+**********************************************************************/
+#ifndef __GAL_ARITHMETIC_UNARY_H__
+#define __GAL_ARITHMETIC_UNARY_H__
+
+
+gal_data_t *
+data_arithmetic_not(gal_data_t *data);
+
+
+#endif
diff --git a/lib/data.c b/lib/data.c
index 0b21222..86bf0d1 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -38,7 +38,9 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 #include <checkset.h>
 #include <data-copy.h>
+#include <data-arithmetic-unary.h>
 #include <data-arithmetic-binary.h>
+#include <data-arithmetic-onlyint.h>
 
 
 
@@ -861,6 +863,307 @@ gal_data_blank_to_value(gal_data_t *data, void *value)
 
 
 
+/* Return 1 if the dataset has a blank value and zero if it doesn't. */
+int
+gal_data_has_blank(gal_data_t *data)
+{
+  /* 'value' will only be read from one of these based on the
+     datatype. Which the caller assigned. If there is any problem, it is
+     their responsability, not this function's.*/
+  void *A=data->array;
+  size_t S=data->size;
+  unsigned char     *uc = A,   *ucf = A+S;
+  char               *c = A,    *cf = A+S;
+  char            **str = A, **strf = A+S;
+  unsigned short    *us = A,   *usf = A+S;
+  short              *s = A,    *sf = A+S;
+  unsigned int      *ui = A,   *uif = A+S;
+  int               *in = A,   *inf = A+S;
+  unsigned long     *ul = A,   *ulf = A+S;
+  long               *l = A,    *lf = A+S;
+  LONGLONG           *L = A,    *Lf = A+S;
+  float              *f = A,    *ff = A+S;
+  double             *d = A,    *df = A+S;
+  gsl_complex_float *cx = A,   *cxf = A+S;
+  gsl_complex      *dcx = A,  *dcxf = A+S;
+
+
+  /* Go over the pixels and check: */
+  switch(data->type)
+    {
+    case GAL_DATA_TYPE_BIT:
+      error(EXIT_FAILURE, 0, "Currently Gnuastro doesn't support bit "
+            "datatype, please get in touch with us to implement it.");
+
+    case GAL_DATA_TYPE_UCHAR:
+      do if(*uc==GAL_DATA_BLANK_UCHAR) return 1; while(uc<ucf);
+      break;
+
+
+    case GAL_DATA_TYPE_CHAR: case GAL_DATA_TYPE_LOGICAL:
+      do if(*c++==GAL_DATA_BLANK_CHAR) return 1; while(c<cf);
+      break;
+
+
+    case GAL_DATA_TYPE_STRING:
+      do if(*str++==GAL_DATA_BLANK_STRING) return 1; while(str<strf);
+      break;
+
+
+    case GAL_DATA_TYPE_USHORT:
+      do if(*us++==GAL_DATA_BLANK_USHORT) return 1; while(us<usf);
+      break;
+
+
+    case GAL_DATA_TYPE_SHORT:
+      do if(*s++==GAL_DATA_BLANK_SHORT) return 1; while(s<sf);
+      break;
+
+
+    case GAL_DATA_TYPE_UINT:
+      do if(*ui++==GAL_DATA_BLANK_UINT) return 1; while(ui<uif);
+      break;
+
+
+    case GAL_DATA_TYPE_INT:
+      do if(*in++==GAL_DATA_BLANK_INT) return 1; while(in<inf);
+      break;
+
+
+    case GAL_DATA_TYPE_ULONG:
+      do if(*ul++==GAL_DATA_BLANK_ULONG) return 1; while(ul<ulf);
+      break;
+
+
+    case GAL_DATA_TYPE_LONG:
+      do if(*l++==GAL_DATA_BLANK_LONG) return 1; while(l<lf);
+      break;
+
+
+    case GAL_DATA_TYPE_LONGLONG:
+      do if(*L++==GAL_DATA_BLANK_LONGLONG) return 1; while(L<Lf);
+      break;
+
+
+      /* Note that a NaN value is not equal to another NaN value, so we
+         can't use the easy check for cases were the blank value is
+         NaN. Also note that `isnan' is actually a macro, so it works for
+         both float and double types.*/
+    case GAL_DATA_TYPE_FLOAT:
+      if(isnan(GAL_DATA_BLANK_FLOAT))
+        do if(isnan(*f++)) return 1; while(f<ff);
+      else
+        do if(*f++==GAL_DATA_BLANK_FLOAT) return 1; while(f<ff);
+      break;
+
+
+    case GAL_DATA_TYPE_DOUBLE:
+      if(isnan(GAL_DATA_BLANK_DOUBLE))
+        do if(isnan(*d++)) return 1; while(d<df);
+      else
+        do if(*d++==GAL_DATA_BLANK_FLOAT) return 1; while(d<df);
+      break;
+
+
+    case GAL_DATA_TYPE_COMPLEX:
+      if(isnan(GAL_DATA_BLANK_FLOAT))
+          do
+            if(isnan(GSL_COMPLEX_P_REAL(cx))
+               && isnan(GSL_COMPLEX_P_IMAG(cx)) )
+              return 1;
+          while(++cx<cxf);
+      else
+        do
+          if( GSL_COMPLEX_P_REAL(cx) == GAL_DATA_BLANK_FLOAT
+              && GSL_COMPLEX_P_IMAG(cx) == GAL_DATA_BLANK_FLOAT)
+            return 1;
+        while(++cx<cxf);
+      break;
+
+
+    case GAL_DATA_TYPE_DCOMPLEX:
+      if(isnan(GAL_DATA_BLANK_DOUBLE))
+          do
+            if(isnan(GSL_COMPLEX_P_REAL(dcx))
+               && isnan(GSL_COMPLEX_P_IMAG(dcx)) )
+              return 1;
+          while(++dcx<dcxf);
+      else
+        do
+          if( GSL_COMPLEX_P_REAL(dcx) == GAL_DATA_BLANK_FLOAT
+              && GSL_COMPLEX_P_IMAG(dcx) == GAL_DATA_BLANK_FLOAT)
+            return 1;
+        while(++dcx<dcxf);
+      break;
+
+
+    default:
+      error(EXIT_FAILURE, 0, "a bug! type value (%d) not recognized "
+            "in `gal_data_blank_to_value'", data->type);
+    }
+
+  /* If there was a blank value, then the function would have returned with
+     a value of 1. So if it reaches here, then we can be sure that there
+     was no blank values, hence, return 0. */
+  return 0;
+}
+
+
+
+
+
+/* Output a data-set of the the same size as the input, but with an
+   unsigned character type that has a value of 1 for data that are blank
+   and 0 for those that aren't. */
+gal_data_t *
+gal_data_flag_blank(gal_data_t *data)
+{
+  gal_data_t *out;
+
+  /* 'value' will only be read from one of these based on the
+     datatype. Which the caller assigned. If there is any problem, it is
+     their responsability, not this function's.*/
+  void *A=data->array;
+  size_t S=data->size;
+  unsigned char     *uc = A,   *ucf = A+S, *o;
+  char               *c = A,    *cf = A+S;
+  char            **str = A, **strf = A+S;
+  unsigned short    *us = A,   *usf = A+S;
+  short              *s = A,    *sf = A+S;
+  unsigned int      *ui = A,   *uif = A+S;
+  int               *in = A,   *inf = A+S;
+  unsigned long     *ul = A,   *ulf = A+S;
+  long               *l = A,    *lf = A+S;
+  LONGLONG           *L = A,    *Lf = A+S;
+  float              *f = A,    *ff = A+S;
+  double             *d = A,    *df = A+S;
+  gsl_complex_float *cx = A,   *cxf = A+S;
+  gsl_complex      *dcx = A,  *dcxf = A+S;
+
+
+  /* Allocate the output array. */
+  out=gal_data_alloc(NULL, GAL_DATA_TYPE_UCHAR, data->ndim, data->dsize,
+                     data->wcs, 0, data->minmapsize);
+  o=out->array;
+
+
+  /* Go over the pixels and set the output values. */
+  switch(data->type)
+    {
+    case GAL_DATA_TYPE_BIT:
+      error(EXIT_FAILURE, 0, "Currently Gnuastro doesn't support bit "
+            "datatype, please get in touch with us to implement it.");
+
+    case GAL_DATA_TYPE_UCHAR:
+      do *o++ = *uc==GAL_DATA_BLANK_UCHAR; while(++uc<ucf);
+      break;
+
+
+    case GAL_DATA_TYPE_CHAR: case GAL_DATA_TYPE_LOGICAL:
+      do *o++ = *c==GAL_DATA_BLANK_CHAR; while(++c<cf);
+      break;
+
+
+    case GAL_DATA_TYPE_STRING:
+      do *o++ = *str==GAL_DATA_BLANK_STRING; while(++str<strf);
+      break;
+
+
+    case GAL_DATA_TYPE_USHORT:
+      do *o++ = *us==GAL_DATA_BLANK_USHORT; while(++us<usf);
+      break;
+
+
+    case GAL_DATA_TYPE_SHORT:
+      do *o++ = *s==GAL_DATA_BLANK_SHORT; while(++s<sf);
+      break;
+
+
+    case GAL_DATA_TYPE_UINT:
+      do *o++ = *ui==GAL_DATA_BLANK_UINT; while(++ui<uif);
+      break;
+
+
+    case GAL_DATA_TYPE_INT:
+      do *o++ = *in==GAL_DATA_BLANK_INT; while(++in<inf);
+      break;
+
+
+    case GAL_DATA_TYPE_ULONG:
+      do *o++ = *ul==GAL_DATA_BLANK_ULONG; while(++ul<ulf);
+      break;
+
+
+    case GAL_DATA_TYPE_LONG:
+      do *o++ = *l==GAL_DATA_BLANK_LONG; while(++l<lf);
+      break;
+
+
+    case GAL_DATA_TYPE_LONGLONG:
+      do *o++ = *L==GAL_DATA_BLANK_LONGLONG; while(++L<Lf);
+      break;
+
+
+      /* Note that a NaN value is not equal to another NaN value, so we
+         can't use the easy check for cases were the blank value is
+         NaN. Also note that `isnan' is actually a macro, so it works for
+         both float and double types.*/
+    case GAL_DATA_TYPE_FLOAT:
+      if(isnan(GAL_DATA_BLANK_FLOAT))
+        do *o++ = isnan(*f); while(++f<ff);
+      else
+        do *o++ = *f==GAL_DATA_BLANK_FLOAT; while(++f<ff);
+      break;
+
+
+    case GAL_DATA_TYPE_DOUBLE:
+      if(isnan(GAL_DATA_BLANK_DOUBLE))
+        do *o++ = isnan(*d); while(++d<df);
+      else
+        do *o++ = *d==GAL_DATA_BLANK_DOUBLE; while(++d<df);
+      break;
+
+
+    case GAL_DATA_TYPE_COMPLEX:
+      if(isnan(GAL_DATA_BLANK_FLOAT))
+          do
+            *o++ = ( isnan(GSL_COMPLEX_P_REAL(cx))
+                     && isnan(GSL_COMPLEX_P_IMAG(cx)) );
+          while(++cx<cxf);
+      else
+        do
+          *o++ = ( GSL_COMPLEX_P_REAL(cx) == GAL_DATA_BLANK_FLOAT
+                   && GSL_COMPLEX_P_IMAG(cx) == GAL_DATA_BLANK_FLOAT );
+        while(++cx<cxf);
+      break;
+
+
+    case GAL_DATA_TYPE_DCOMPLEX:
+      if(isnan(GAL_DATA_BLANK_DOUBLE))
+          do
+            *o++ = ( isnan(GSL_COMPLEX_P_REAL(dcx))
+                     && isnan(GSL_COMPLEX_P_IMAG(dcx)) );
+          while(++dcx<dcxf);
+      else
+        do
+          *o++ = ( GSL_COMPLEX_P_REAL(dcx) == GAL_DATA_BLANK_FLOAT
+                   && GSL_COMPLEX_P_IMAG(dcx) == GAL_DATA_BLANK_FLOAT );
+        while(++dcx<dcxf);
+      break;
+
+
+    default:
+      error(EXIT_FAILURE, 0, "type value (%d) not recognized "
+            "in `gal_data_flag_blank'", data->type);
+    }
+
+  /* Return */
+  return out;
+}
+
+
+
+
 
 
 
@@ -1150,11 +1453,12 @@ gal_data_arithmetic(int operator, unsigned char flags, 
...)
   /* Depending on the operator do the job: */
   switch(operator)
     {
-    /* If we have an ordinary (not bitwise) binary operator: */
+    /* Binary operators with any data type. */
     case GAL_DATA_OPERATOR_PLUS:
     case GAL_DATA_OPERATOR_MINUS:
     case GAL_DATA_OPERATOR_MULTIPLY:
     case GAL_DATA_OPERATOR_DIVIDE:
+    case GAL_DATA_OPERATOR_MODULO:
     case GAL_DATA_OPERATOR_LT:
     case GAL_DATA_OPERATOR_LE:
     case GAL_DATA_OPERATOR_GT:
@@ -1163,12 +1467,36 @@ gal_data_arithmetic(int operator, unsigned char flags, 
...)
     case GAL_DATA_OPERATOR_NE:
     case GAL_DATA_OPERATOR_AND:
     case GAL_DATA_OPERATOR_OR:
-      /* Prepare original data structures from the input arguments. */
       d1 = va_arg(va, gal_data_t *);
       d2 = va_arg(va, gal_data_t *);
       out=data_arithmetic_binary(operator, flags, d1, d2);
       break;
 
+    case GAL_DATA_OPERATOR_NOT:
+      d1 = va_arg(va, gal_data_t *);
+      out=data_arithmetic_not(d1);
+      break;
+
+    /* Binary operators that only work on integer types. */
+    case GAL_DATA_OPERATOR_BITAND:
+    case GAL_DATA_OPERATOR_BITOR:
+    case GAL_DATA_OPERATOR_BITXOR:
+    case GAL_DATA_OPERATOR_BITLSH:
+    case GAL_DATA_OPERATOR_BITRSH:
+      d1 = va_arg(va, gal_data_t *);
+      d2 = va_arg(va, gal_data_t *);
+      out=data_arithmetic_onlyint_binary(operator, flags, d1, d2);
+      break;
+
+    /* Ones component (bitwise) operator.*/
+
+    case GAL_DATA_OPERATOR_ISBLANK:
+      d1 = va_arg(va, gal_data_t *);
+      out = gal_data_flag_blank(d1);
+      if(flags & GAL_DATA_ARITH_FREE)
+        gal_data_free(d1);
+
+
 
 #if 0
   else if(!strcmp(operator, "abs"))       takeabs(p);
@@ -1183,7 +1511,6 @@ gal_data_arithmetic(int operator, unsigned char flags, 
...)
           || !strcmp(operator, "average")
           || !strcmp(operator, "median")) alloppixs(p, operator);
   else if(!strcmp(operator, "not"))       notfunc(p);
-  else if(!strcmp(operator, "isblank"))   opisblank(p);
   else if(!strcmp(operator, "where"))     where(p);
 #endif
 
diff --git a/lib/gnuastro/data.h b/lib/gnuastro/data.h
index 3298f9f..b8c0a61 100644
--- a/lib/gnuastro/data.h
+++ b/lib/gnuastro/data.h
@@ -136,6 +136,7 @@ enum gal_data_operators
   GAL_DATA_OPERATOR_MINUS,     /*   -    */
   GAL_DATA_OPERATOR_MULTIPLY,  /*   *    */
   GAL_DATA_OPERATOR_DIVIDE,    /*   /    */
+  GAL_DATA_OPERATOR_MODULO,    /*   %    */
 
   GAL_DATA_OPERATOR_LT,        /*   <    */
   GAL_DATA_OPERATOR_LE,        /*   <=   */
@@ -148,6 +149,10 @@ enum gal_data_operators
 
   GAL_DATA_OPERATOR_BITAND,    /*   &    */
   GAL_DATA_OPERATOR_BITOR,     /*   |    */
+  GAL_DATA_OPERATOR_BITXOR,    /*   ^    */
+  GAL_DATA_OPERATOR_BITLSH,    /*   <<   */
+  GAL_DATA_OPERATOR_BITRSH,    /*   >>   */
+  GAL_DATA_OPERATOR_BITOCM,    /*   ~    */
 
   GAL_DATA_OPERATOR_NOT,       /*   !    */
   GAL_DATA_OPERATOR_ISBLANK,   /* Similar to isnan() for floats. */
@@ -246,6 +251,12 @@ gal_data_apply_mask(gal_data_t *in, gal_data_t *mask);
 void
 gal_data_blank_to_value(gal_data_t *data, void *value);
 
+int
+gal_data_has_blank(gal_data_t *data);
+
+gal_data_t *
+gal_data_flag_blank(gal_data_t *data);
+
 
 
 



reply via email to

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