1 
2 /* ----------------------------------------------------------------------
3  * Project:      CMSIS DSP Library
4  * Title:        arm_canberra_distance_f16.c
5  * Description:  Canberra distance between two vectors
6  *
7  * $Date:        23 April 2021
8  * $Revision:    V1.9.0
9  *
10  * Target Processor: Cortex-M and Cortex-A cores
11  * -------------------------------------------------------------------- */
12 /*
13  * Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved.
14  *
15  * SPDX-License-Identifier: Apache-2.0
16  *
17  * Licensed under the Apache License, Version 2.0 (the License); you may
18  * not use this file except in compliance with the License.
19  * You may obtain a copy of the License at
20  *
21  * www.apache.org/licenses/LICENSE-2.0
22  *
23  * Unless required by applicable law or agreed to in writing, software
24  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
25  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26  * See the License for the specific language governing permissions and
27  * limitations under the License.
28  */
29 
30 #include "dsp/distance_functions_f16.h"
31 
32 #if defined(ARM_FLOAT16_SUPPORTED)
33 
34 #include <limits.h>
35 #include <math.h>
36 
37 /**
38   @ingroup FloatDist
39  */
40 
41 /**
42   @defgroup Canberra Canberra distance
43 
44   Canberra distance
45  */
46 
47 
48 /**
49   @addtogroup Canberra
50   @{
51  */
52 
53 
54 /**
55  * @brief        Canberra distance between two vectors
56  *
57  * This function may divide by zero when samples pA[i] and pB[i] are both zero.
58  * The result of the computation will be correct. So the division per zero may be
59  * ignored.
60  *
61  * @param[in]    pA         First vector
62  * @param[in]    pB         Second vector
63  * @param[in]    blockSize  vector length
64  * @return distance
65  *
66  */
67 
68 #if defined(ARM_MATH_MVE_FLOAT16) && !defined(ARM_MATH_AUTOVECTORIZE)
69 
70 #include "arm_helium_utils.h"
71 #include "arm_vec_math_f16.h"
72 
arm_canberra_distance_f16(const float16_t * pA,const float16_t * pB,uint32_t blockSize)73 float16_t arm_canberra_distance_f16(const float16_t *pA,const float16_t *pB, uint32_t blockSize)
74 {
75     _Float16       accum = 0.0f16;
76     uint32_t         blkCnt;
77     f16x8_t         a, b, c, accumV;
78 
79     accumV = vdupq_n_f16(0.0f);
80 
81     blkCnt = blockSize >> 3;
82     while (blkCnt > 0) {
83         a = vld1q(pA);
84         b = vld1q(pB);
85 
86         c = vabdq(a, b);
87 
88         a = vabsq(a);
89         b = vabsq(b);
90         a = vaddq(a, b);
91 
92         /*
93          * May divide by zero when a and b have both the same lane at zero.
94          */
95         a = vrecip_hiprec_f16(a);
96 
97         /*
98          * Force result of a division by 0 to 0. It the behavior of the
99          * sklearn canberra function.
100          */
101         a = vdupq_m_n_f16(a, 0.0f, vcmpeqq(a, 0.0f));
102         c = vmulq(c, a);
103         accumV = vaddq(accumV, c);
104 
105         pA += 8;
106         pB += 8;
107         blkCnt--;
108     }
109 
110     blkCnt = blockSize & 7;
111     if (blkCnt > 0U) {
112         mve_pred16_t    p0 = vctp16q(blkCnt);
113 
114         a = vldrhq_z_f16(pA, p0);
115         b = vldrhq_z_f16(pB, p0);
116 
117         c = vabdq(a, b);
118 
119         a = vabsq(a);
120         b = vabsq(b);
121         a = vaddq(a, b);
122 
123         /*
124          * May divide by zero when a and b have both the same lane at zero.
125          */
126         a = vrecip_hiprec_f16(a);
127 
128         /*
129          * Force result of a division by 0 to 0. It the behavior of the
130          * sklearn canberra function.
131          */
132         a = vdupq_m_n_f16(a, 0.0f, vcmpeqq(a, 0.0f));
133         c = vmulq(c, a);
134         accumV = vaddq_m(accumV, accumV, c, p0);
135     }
136 
137     accum = vecAddAcrossF16Mve(accumV);
138 
139     return (accum);
140 }
141 
142 
143 #else
arm_canberra_distance_f16(const float16_t * pA,const float16_t * pB,uint32_t blockSize)144 float16_t arm_canberra_distance_f16(const float16_t *pA,const float16_t *pB, uint32_t blockSize)
145 {
146    _Float16 accum=0.0f, tmpA, tmpB,diff,sum;
147 
148    while(blockSize > 0)
149    {
150       tmpA = *pA++;
151       tmpB = *pB++;
152 
153       diff = fabsf(tmpA - tmpB);
154       sum = fabsf(tmpA) + fabsf(tmpB);
155       if ((tmpA != 0.0f16) || (tmpB != 0.0f16))
156       {
157          accum += (diff / sum);
158       }
159       blockSize --;
160    }
161    return(accum);
162 }
163 #endif /* defined(ARM_MATH_MVEF) && !defined(ARM_MATH_AUTOVECTORIZE) */
164 
165 
166 /**
167  * @} end of Canberra group
168  */
169 
170 #endif /* #if defined(ARM_FLOAT16_SUPPORTED) */
171 
172