popham.c revision 1.1.1.2 1 1.1 mrg /* mpn_popcount, mpn_hamdist -- mpn bit population count/hamming distance.
2 1.1 mrg
3 1.1.1.2 mrg Copyright 1994, 1996, 2000, 2001, 2002, 2005, 2011, 2012 Free Software
4 1.1.1.2 mrg Foundation, Inc.
5 1.1 mrg
6 1.1 mrg This file is part of the GNU MP Library.
7 1.1 mrg
8 1.1 mrg The GNU MP Library is free software; you can redistribute it and/or modify
9 1.1 mrg it under the terms of the GNU Lesser General Public License as published by
10 1.1 mrg the Free Software Foundation; either version 3 of the License, or (at your
11 1.1 mrg option) any later version.
12 1.1 mrg
13 1.1 mrg The GNU MP Library is distributed in the hope that it will be useful, but
14 1.1 mrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 1.1 mrg or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16 1.1 mrg License for more details.
17 1.1 mrg
18 1.1 mrg You should have received a copy of the GNU Lesser General Public License
19 1.1 mrg along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
20 1.1 mrg
21 1.1 mrg #include "gmp.h"
22 1.1 mrg #include "gmp-impl.h"
23 1.1 mrg
24 1.1 mrg #if OPERATION_popcount
25 1.1 mrg #define FNAME mpn_popcount
26 1.1 mrg #define POPHAM(u,v) u
27 1.1 mrg #endif
28 1.1 mrg
29 1.1 mrg #if OPERATION_hamdist
30 1.1 mrg #define FNAME mpn_hamdist
31 1.1 mrg #define POPHAM(u,v) u ^ v
32 1.1 mrg #endif
33 1.1 mrg
34 1.1 mrg mp_bitcnt_t
35 1.1 mrg FNAME (mp_srcptr up,
36 1.1 mrg #if OPERATION_hamdist
37 1.1 mrg mp_srcptr vp,
38 1.1 mrg #endif
39 1.1.1.2 mrg mp_size_t n) __GMP_NOTHROW
40 1.1 mrg {
41 1.1 mrg mp_bitcnt_t result = 0;
42 1.1 mrg mp_limb_t p0, p1, p2, p3, x, p01, p23;
43 1.1 mrg mp_size_t i;
44 1.1 mrg
45 1.1 mrg ASSERT (n >= 1); /* Actually, this code handles any n, but some
46 1.1 mrg assembly implementations do not. */
47 1.1 mrg
48 1.1 mrg for (i = n >> 2; i != 0; i--)
49 1.1 mrg {
50 1.1 mrg p0 = POPHAM (up[0], vp[0]);
51 1.1 mrg p0 -= (p0 >> 1) & MP_LIMB_T_MAX/3; /* 2 0-2 */
52 1.1 mrg p0 = ((p0 >> 2) & MP_LIMB_T_MAX/5) + (p0 & MP_LIMB_T_MAX/5); /* 4 0-4 */
53 1.1 mrg
54 1.1 mrg p1 = POPHAM (up[1], vp[1]);
55 1.1 mrg p1 -= (p1 >> 1) & MP_LIMB_T_MAX/3; /* 2 0-2 */
56 1.1 mrg p1 = ((p1 >> 2) & MP_LIMB_T_MAX/5) + (p1 & MP_LIMB_T_MAX/5); /* 4 0-4 */
57 1.1 mrg
58 1.1 mrg p01 = p0 + p1; /* 8 0-8 */
59 1.1 mrg p01 = ((p01 >> 4) & MP_LIMB_T_MAX/17) + (p01 & MP_LIMB_T_MAX/17); /* 8 0-16 */
60 1.1 mrg
61 1.1 mrg p2 = POPHAM (up[2], vp[2]);
62 1.1 mrg p2 -= (p2 >> 1) & MP_LIMB_T_MAX/3; /* 2 0-2 */
63 1.1 mrg p2 = ((p2 >> 2) & MP_LIMB_T_MAX/5) + (p2 & MP_LIMB_T_MAX/5); /* 4 0-4 */
64 1.1 mrg
65 1.1 mrg p3 = POPHAM (up[3], vp[3]);
66 1.1 mrg p3 -= (p3 >> 1) & MP_LIMB_T_MAX/3; /* 2 0-2 */
67 1.1 mrg p3 = ((p3 >> 2) & MP_LIMB_T_MAX/5) + (p3 & MP_LIMB_T_MAX/5); /* 4 0-4 */
68 1.1 mrg
69 1.1 mrg p23 = p2 + p3; /* 8 0-8 */
70 1.1 mrg p23 = ((p23 >> 4) & MP_LIMB_T_MAX/17) + (p23 & MP_LIMB_T_MAX/17); /* 8 0-16 */
71 1.1 mrg
72 1.1 mrg x = p01 + p23; /* 8 0-32 */
73 1.1 mrg x = (x >> 8) + x; /* 8 0-64 */
74 1.1 mrg x = (x >> 16) + x; /* 8 0-128 */
75 1.1 mrg #if GMP_LIMB_BITS > 32
76 1.1 mrg x = ((x >> 32) & 0xff) + (x & 0xff); /* 8 0-256 */
77 1.1 mrg result += x;
78 1.1 mrg #else
79 1.1 mrg result += x & 0xff;
80 1.1 mrg #endif
81 1.1 mrg up += 4;
82 1.1 mrg #if OPERATION_hamdist
83 1.1 mrg vp += 4;
84 1.1 mrg #endif
85 1.1 mrg }
86 1.1 mrg
87 1.1 mrg n &= 3;
88 1.1 mrg if (n != 0)
89 1.1 mrg {
90 1.1 mrg x = 0;
91 1.1 mrg do
92 1.1 mrg {
93 1.1 mrg p0 = POPHAM (up[0], vp[0]);
94 1.1 mrg p0 -= (p0 >> 1) & MP_LIMB_T_MAX/3; /* 2 0-2 */
95 1.1 mrg p0 = ((p0 >> 2) & MP_LIMB_T_MAX/5) + (p0 & MP_LIMB_T_MAX/5); /* 4 0-4 */
96 1.1 mrg p0 = ((p0 >> 4) + p0) & MP_LIMB_T_MAX/17; /* 8 0-8 */
97 1.1 mrg
98 1.1 mrg x += p0;
99 1.1 mrg up += 1;
100 1.1 mrg #if OPERATION_hamdist
101 1.1 mrg vp += 1;
102 1.1 mrg #endif
103 1.1 mrg }
104 1.1 mrg while (--n);
105 1.1 mrg
106 1.1 mrg x = (x >> 8) + x;
107 1.1 mrg x = (x >> 16) + x;
108 1.1 mrg #if GMP_LIMB_BITS > 32
109 1.1 mrg x = (x >> 32) + x;
110 1.1 mrg #endif
111 1.1 mrg result += x & 0xff;
112 1.1 mrg }
113 1.1 mrg
114 1.1 mrg return result;
115 1.1 mrg }
116