gnuastro-commits
[Top][All Lists]
Advanced

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

[gnuastro-commits] master 6a291cd: Library type.h: integers can be read


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master 6a291cd: Library type.h: integers can be read as floats when ending in . or .0
Date: Mon, 25 May 2020 18:34:09 -0400 (EDT)

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

    Library type.h: integers can be read as floats when ending in . or .0
    
    For numerical analysis, it is common practice to simply put a '.' or '.0'
    after them to tell the programs to parse them as floating point (for
    example when dividing 2 by 3). However, until now, the
    'gal_type_string_to_number' function would parse numbers ending in '.' or
    '.0' as integers. The only way to force it to parse them as floating point
    was to put a 'f' suffix.
    
    So with this commit, the 'gal_type_string_to_number' function (which is in
    charge of parsing strings to numbers) will interpret any number that has a
    '.' inside of it as a floating point. Note that it has already been parsed
    as a number by the C library, so there is no problem in the '.' having
    another meaning.
    
    While correcting the documentation, I noticed that we also force a
    floating-point type on the 'pow' (to-power) operator of Arithmetic. But
    that is again non-intuitive, so a step was added to internally convert the
    values to floating point (when they are integers), and free them before
    coming out.
    
    This task was suggested by Carlos Allende Prieto.
---
 NEWS                         | 16 ++++++++++++++++
 THANKS                       |  1 +
 doc/announce-acknowledge.txt |  1 +
 doc/gnuastro.texi            | 32 +++++++++++++++-----------------
 lib/arithmetic.c             | 43 ++++++++++++++++++++++++++++++-------------
 lib/type.c                   |  8 +++++++-
 6 files changed, 70 insertions(+), 31 deletions(-)

diff --git a/NEWS b/NEWS
index fb7d08d..efca08b 100644
--- a/NEWS
+++ b/NEWS
@@ -7,10 +7,26 @@ See the end of the file for license conditions.
 
 ** New features
 
+  Arithmetic:
+   - To force integers to floats, you can also put a '.' or '.0' after
+     them. Until now, it was only possibly by putting an 'f' after
+     them. Hence while '5' will be read as an integer, '5.', '5.0' or '5f'
+     will be read as floating point. This also applies to column arithmetic
+     in Table.
+
 ** Removed features
 
 ** Changed features
 
+  Arithmetic:
+   - The 'pow' operator can also accept integer inputs. This also applies
+     to column arithmetic in Table.
+
+  Library:
+   - gal_type_string_to_number: Numbers ending in '.' or '.0' will be
+     parsed as floating point. Until now, it would only parse numbers as
+     floating point if they had non-zero decimals.
+
 ** Bugs fixed
   bug #58434: MakeCatalog crash when ordering is required and no usable pixels
 
diff --git a/THANKS b/THANKS
index 28e0700..707d693 100644
--- a/THANKS
+++ b/THANKS
@@ -20,6 +20,7 @@ support in Gnuastro. The list is ordered alphabetically (by 
family name).
 
     Valentina Abril-melgarejo            address@hidden
     Marjan Akbari                        address@hidden
+    Carlos Allende Prieto                address@hidden
     Hamed Altafi                         address@hidden
     Roland Bacon                         address@hidden
     Roberto Baena Gallé                  address@hidden
diff --git a/doc/announce-acknowledge.txt b/doc/announce-acknowledge.txt
index e160424..010cc61 100644
--- a/doc/announce-acknowledge.txt
+++ b/doc/announce-acknowledge.txt
@@ -1,5 +1,6 @@
 Alphabetically ordered list to acknowledge in the next release.
 
+Carlos Allende Prieto
 Raúl Infante Sainz
 Zahra Sharbaf
 Ole Streicher
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index 0f05717..f7aa34c 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -10150,9 +10150,7 @@ Note that the modulo operator only works on integer 
types.
 Absolute value of first operand, so ``@command{4 abs}'' is equivalent to 
@mymath{|4|}.
 
 @item pow
-First operand to the power of the second, so ``@command{4.3 5f pow}'' is 
equivalent to @mymath{4.3^{5}}.
-Currently @code{pow} will only work on single or double precision floating 
point numbers or images.
-To be sure that a number is read as a floating point (even if it doesn't have 
any non-zero decimals) put an @code{f} after it.
+First operand to the power of the second, so ``@command{4.3 5 pow}'' is 
equivalent to @mymath{4.3^{5}}.
 
 @item sqrt
 The square root of the first operand, so ``@command{5 sqrt}'' is equivalent to 
@mymath{\sqrt{5}}.
@@ -10743,7 +10741,8 @@ $ astarithmetic image.fits image.fits - 
--out=skysub.fits           \
                 --hdu=1 --hdu=4
 
 ## Add two images, then divide them by 2 (2 is read as floating point):
-$ astarithmetic image1.fits image2.fits + 2f / --out=average.fits
+## Note that without the '.0', the '2' will be read/used as an integer.
+$ astarithmetic image1.fits image2.fits + 2.0 / --out=average.fits
 
 ## Use Arithmetic's average operator:
 $ astarithmetic image1.fits image2.fits average --out=average.fits
@@ -10841,7 +10840,8 @@ But when Arithmetic is called with 
@option{--dontdelete}, it will appended the d
 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/pixel.
 Numbers on the command-line will be read into the smallest type (see 
@ref{Numeric 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), @command{2500} 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 
@command{5f} will be added to the stack as @code{float} (see @ref{Reverse 
polish notation}).
+To force a number to be read as float, put a @code{.} after it (possibly 
followed by a zero for easier readability), or add an @code{f} after it.
+Hence while @command{5} will be read as an integer, @command{5.}, 
@command{5.0} or @command{5f} 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 numeric multiple data types (see @ref{Numeric data types}).
 For example in ``@command{a.fits b.fits +}'', the image types can be 
@code{long} and @code{float}.
@@ -18979,15 +18979,16 @@ if( gal_type_from_string(&out, string, 
GAL_TYPE_FLOAT32) )
 @end deftypefun
 
 @deftypefun {void *} gal_type_string_to_number (char @code{*string}, uint8_t 
@code{*type})
-Read @code{string} into smallest type that can host the number, the
-allocated space for the number will be returned and the type of the number
-will be put into the memory that @code{type} points to. If @code{string}
-couldn't be read as a number, this function will return @code{NULL}.
+Read @code{string} into smallest type that can host the number, the allocated 
space for the number will be returned and the type of the number will be put 
into the memory that @code{type} points to.
+If @code{string} couldn't be read as a number, this function will return 
@code{NULL}.
 
-For the ranges acceptable by each type see @ref{Numeric data types}. For
-integers it is clear, for floating point types, this function will count
-the number of significant digits and determine if the given string is
-single or double precision as described in that section.
+This function calls the C library's @code{strtod} function to read 
@code{string} as a double-precision floating point number.
+When successful, it will check the value to put it in the smallest numerical 
data type that can handle it.
+However, if @code{string} is successfully parsed as a number @emph{and} there 
is @code{.} in @code{string}, it will force the number into floating point 
types.
+For example @code{"5"} is read as an integer, while @code{"5."} or 
@code{"5.0"}, or @code{"5.00"} will be read as a floating point 
(single-precision).
+
+For the ranges acceptable by each type see @ref{Numeric data types}.
+For integers, the range is clear, but for floating point types, this function 
will count the number of significant digits and determine if the given string 
is single or double precision as described in that section.
 @end deftypefun
 
 @node Pointers, Library blank values, Library data types, Gnuastro library
@@ -22467,10 +22468,7 @@ The output type is a single integer.
 @end deffn
 
 @deffn Macro GAL_ARITHMETIC_OP_POW
-Binary operator to-power operator. When @code{gal_arithmetic} is called
-with any of these operators, it will expect two operands: raising the first
-by the second. This operator only accepts floating point inputs and the
-output is also floating point.
+Binary operator to-power operator. When @code{gal_arithmetic} is called with 
any of these operators, it will expect two operands: raising the first by the 
second (returning a floating point, inputs can be integers).
 @end deffn
 
 @deffn  Macro GAL_ARITHMETIC_OP_BITAND
diff --git a/lib/arithmetic.c b/lib/arithmetic.c
index 8a4c8c6..744b7b1 100644
--- a/lib/arithmetic.c
+++ b/lib/arithmetic.c
@@ -79,7 +79,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 /* Some functions are only for a floating point operand, so if the input
    isn't floating point, inform the user to change the type explicitly,
    doing it implicitly/internally puts too much responsability on the
-   program. */
+   program.
 static void
 arithmetic_check_float_input(gal_data_t *in, int operator, char *numstr)
 {
@@ -101,7 +101,7 @@ arithmetic_check_float_input(gal_data_t *in, int operator, 
char *numstr)
             numstr, gal_type_name(in->type, 1));
     }
 }
-
+*/
 
 
 
@@ -1682,24 +1682,26 @@ arithmetic_binary(int operator, int flags, gal_data_t 
*l, gal_data_t *r)
 
 
 static gal_data_t *
-arithmetic_binary_function_flt(int operator, int flags, gal_data_t *l,
-                               gal_data_t *r)
+arithmetic_binary_function_flt(int operator, int flags, gal_data_t *il,
+                               gal_data_t *ir)
 {
   int final_otype;
-  gal_data_t *o=NULL;
   size_t out_size, minmapsize;
-  int quietmmap=l->quietmmap && r->quietmmap;
-
+  gal_data_t *l, *r, *o=NULL;
+  int quietmmap=il->quietmmap && ir->quietmmap;
 
   /* Simple sanity check on the input sizes */
-  if( !( (flags & GAL_ARITHMETIC_NUMOK) && (l->size==1 || r->size==1))
-      && gal_dimension_is_different(l, r) )
+  if( !( (flags & GAL_ARITHMETIC_NUMOK) && (il->size==1 || ir->size==1))
+      && gal_dimension_is_different(il, ir) )
     error(EXIT_FAILURE, 0, "%s: the input datasets don't have the same "
           "dimension/size", __func__);
 
-  /* Check for the types of the left and right operands. */
-  arithmetic_check_float_input(l, operator, "first");
-  arithmetic_check_float_input(r, operator, "second");
+  /* Convert the values to double precision floating point if they are
+     integer. */
+  l = ( (il->type==GAL_TYPE_FLOAT32 || il->type==GAL_TYPE_FLOAT64)
+         ? il : gal_data_copy_to_new_type(il, GAL_TYPE_FLOAT64) );
+  r = ( (ir->type==GAL_TYPE_FLOAT32 || ir->type==GAL_TYPE_FLOAT64)
+         ? ir : gal_data_copy_to_new_type(ir, GAL_TYPE_FLOAT64) );
 
   /* Set the output type. */
   final_otype = gal_type_out(l->type, r->type);
@@ -1736,7 +1738,7 @@ arithmetic_binary_function_flt(int operator, int flags, 
gal_data_t *l,
   /* Start setting the operator and operands. */
   switch(operator)
     {
-    case GAL_ARITHMETIC_OP_POW:  BINFUNC_F_OPERATOR_SET( pow  ); break;
+    case GAL_ARITHMETIC_OP_POW:  BINFUNC_F_OPERATOR_SET( pow ); break;
     default:
       error(EXIT_FAILURE, 0, "%s: operator code %d not recognized",
             __func__, operator);
@@ -1753,9 +1755,24 @@ arithmetic_binary_function_flt(int operator, int flags, 
gal_data_t *l,
      were allocated. */
   if(flags & GAL_ARITHMETIC_FREE)
     {
+      /* Clean the main used (temporarily allocated) datasets. */
       if     (o==l)       gal_data_free(r);
       else if(o==r)       gal_data_free(l);
       else              { gal_data_free(l); gal_data_free(r); }
+
+      /* Clean the raw inputs, if they weren't equal to the datasets. */
+      if     (o==il) { if(ir!=r) gal_data_free(ir); }
+      else if(o==ir) { if(il!=l) gal_data_free(il); }
+      else           { if(il!=l) gal_data_free(il);
+                       if(ir!=r) gal_data_free(ir); }
+    }
+  else
+    {
+      /* Input datasets should be kept, but we don't want the temporary
+         datasets, so if they were allocated (they don't equal the input
+         pointers, free them). */
+      if (l!=il) gal_data_free(l);
+      if (r!=ir) gal_data_free(r);
     }
 
   /* Return */
diff --git a/lib/type.c b/lib/type.c
index 2e9c6d4..3ade3d4 100644
--- a/lib/type.c
+++ b/lib/type.c
@@ -562,8 +562,8 @@ gal_type_string_to_number(char *string, uint8_t *type)
 {
   void *ptr, *out;
   int fnz=-1, lnz=0;     /* 'F'irst (or 'L'ast) 'N'on-'Z'ero. */
-  char *tailptr, *cp;
   uint8_t forcedfloat=0;
+  char *c, *tailptr, *cp;
 
   /* Define initial spaces to keep the value. */
   uint8_t   u8;   int8_t   i8;      uint16_t u16;   int16_t i16;
@@ -575,6 +575,12 @@ gal_type_string_to_number(char *string, uint8_t *type)
   if(*tailptr=='f') { if(tailptr[1]=='\0') forcedfloat=1; else return NULL; }
   else if (*tailptr!='\0')  return NULL;
 
+  /* The number has been parsed successfully as a number. But if it
+     contains a '.', then it must a "forced" float also. This won't be a
+     problem in scenarios like '.2', but people may use '2.' or '2.0' to
+     force a float and this loop is necessary in such cases. */
+  for(c=string; *c!='\0'; ++c) if(*c=='.') { forcedfloat=1; break; }
+
   /* See if the number is actually an integer: */
   if( forcedfloat==0 && ceil(d) == d )
     {



reply via email to

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