LCOV - code coverage report
Current view: top level - src - dist.c (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 52 52 100.0 %
Date: 2020-12-14 08:13:14 Functions: 3 3 100.0 %

          Line data    Source code
       1             : #include "dist.h"
       2             : #include <tgmath.h>
       3             : #include "mathext.h"
       4             : #define swap(T, x, y) \
       5             :   {                   \
       6             :     T tmp = (x);      \
       7             :     x = (y);          \
       8             :     y = tmp;          \
       9             :   }
      10             : 
      11             : #define map1(i) (i) - 1
      12             : #define x(i) x[ map1(i) ]
      13             : #define y(i) y[ map1(i) ]
      14             : 
      15             : // Computes either the Euclidean distance between two N-dimensional
      16             : // vectors X and Y or the Euclidean norm of one such vector X.
      17             : //
      18             : // Call the routine
      19             : // either
      20             : //    with KVEC = 2 and two vectors X and Y of dimension N stored
      21             : //    with storage-increments INCX and INCY, respectively.
      22             : // or
      23             : //    with KVEC = 1 and one vector X of dimension N stored
      24             : //    with storage-increment INCX. In this case the second array
      25             : //    is not referenced and can be a dummy array or simply the
      26             : //    array X again.
      27             : //
      28             : // If N .LE. 0 then zero is returned, if N .GE. 1 then the
      29             : // storage increments cannot be zero.
      30             : //
      31             : // This code is inspired by the LAPACK function DNRM2 written by
      32             : // Sven Hammarling.
      33             : //
      34             : // Variables in the calling sequence
      35             : // ---------------------------------
      36             : //    N     I    IN   Dimension of the vectors X and Y
      37             : //    X     D    IN   The first vector of dimension N
      38             : //    INCX  I    IN   Storage increment of X
      39             : //    Y     D    IN   The second vector of dimension N
      40             : //    INYY  D    IN   Storage increment of Y
      41             : //    KVEC  I    IN   Number of vectors
      42             : //                    KVEC = ANY INTEGER OTHER THAN 2
      43             : //                              Only one vector, namely X, is given,
      44             : //                              the Euclidean norm of X is computed
      45             : //                              and the Y array is not referenced
      46             : //                              This is the default
      47             : //                    KVEC = 2  Two vectors X and Y  are given,
      48             : //                              the Euclidean distance between
      49             : //                              X and Y is computed
      50             : //
      51          19 : double ddist2(int n, double *x, int incx, double *y, int incy, int kvec)
      52             : {
      53          19 :   const double zer = 0.0;
      54          19 :   int ix = 1, iy = 1;
      55          19 :   double diff = 0.0, dx = 0.0, dy = 0.0;
      56          19 :   double scale = 0.0, sum = 0.0;
      57             : 
      58          19 :   if (kvec != 2) kvec = 1;
      59             : 
      60             :   // Define the inner product to be zero whenever the dimension is not positive
      61             :   // or a storage incrementor (incx/incy) is zero
      62          19 :   if (n <= 0) return zer;
      63          16 :   if (kvec == 1 && incx == 0) return zer;
      64          15 :   if (kvec == 2 && incx == 0 && incy == 0) return zer;
      65             : 
      66             :   // Initialize incrementors
      67             : 
      68          14 :   ix = 1;
      69          14 :   if (incx < 0) ix = (-n + 1) * incx + 1;
      70          14 :   iy = 1;
      71          14 :   if (incy < 0) iy = (-n + 1) * incy + 1;
      72             : 
      73          14 :   sum = zer;
      74          14 :   scale = zer;
      75         145 :   for (int j = 1; j <= n; j++)
      76             :   {
      77         131 :     dx = x(ix);
      78         131 :     ix += incx;
      79         131 :     if (kvec == 1)  // One vector case
      80             :     {
      81          72 :       diff = dx;
      82             :     }
      83             :     else  // Two vector case
      84             :     {
      85          59 :       dy = y(iy);
      86          59 :       iy += incy;
      87          59 :       diff = dx - dy;
      88             :     }
      89             : 
      90             :     // Scaled squares (less than or equal to one) of the nonzero terms.
      91         131 :     add_next_element_squared(diff, &sum, &scale);
      92             :   }
      93          14 :   return scale * sqrt(sum);
      94             : }
      95             : 
      96             : // Computes the Euclidean norm of X.
      97             : //
      98             : // If N .LE. 0 then zero is returned, if N .GE. 1 then the
      99             : // storage increments cannot be zero.
     100             : //
     101             : // This code is inspired by the LAPACK function DNRM2 written by
     102             : // Sven Hammarling.
     103             : //
     104             : // Variables in the calling sequence
     105             : // ---------------------------------
     106             : //    N     I    IN   Dimension of the vector X
     107             : //    X     D    IN   Vector of dimension N
     108             : //    INCX  I    IN   Storage spacing between elements of X
     109             : //
     110         236 : double dnrm2(int n, double *x, int incx)
     111             : {
     112         236 :   const double zer = 0.0;
     113         236 :   int ix = 1;
     114         236 :   double dx = 0.0;
     115         236 :   double scale = 0.0, sum = 0.0;
     116             : 
     117             :   // Define the norm2 to be zero whenever the dimension is not positive
     118             :   // or a storage incrementor is zero
     119         236 :   if (n < 1 || incx == 0) return zer;
     120             : 
     121             :   // Initialize incrementors
     122         232 :   if (incx < 0) ix = (-n + 1) * incx + 1;
     123             : 
     124        1308 :   for (int j = 1; j <= n; j++)
     125             :   {
     126        1076 :     dx = x(ix);
     127        1076 :     ix += incx;
     128             :     // Scaled squares (less than or equal to one) of the nonzero terms.
     129        1076 :     add_next_element_squared(dx, &sum, &scale);
     130             :   }
     131         232 :   return scale * sqrt(sum);
     132             : }
     133             : 
     134        1207 : void add_next_element_squared(double xi, double *sum, double *scale)
     135             : {
     136        1207 :   double bar = *scale;
     137        1207 :   double ssq = *sum;
     138        1207 :   const double zer = 0.0, one = 1.0;
     139        1207 :   double tmp = 0.0, absxi = 0.0;
     140             : 
     141             :   // If xi==0, then the remaining statements do not permit a division by zero
     142             :   // because bar >= 0 implies that bar < 0 is always false.
     143             :   // However a quick return prohibits a wasted multiplication and sum.
     144        1207 :   if (xi == zer) return;
     145             : 
     146        1046 :   absxi = fabs(xi);
     147        1046 :   if (bar < absxi)
     148             :   {
     149         594 :     tmp = bar / absxi;
     150         594 :     ssq = one + ssq * tmp * tmp;
     151         594 :     bar = absxi;
     152             :   }
     153             :   else
     154             :   {
     155         452 :     tmp = absxi / bar;
     156         452 :     ssq += tmp * tmp;
     157             :   }
     158             : 
     159        1046 :   *scale = bar;
     160        1046 :   *sum = ssq;
     161             : }

Generated by: LCOV version 1.14