Commit 0da76a94 authored by Eric Blake's avatar Eric Blake

count-leading-zeros: new module

I needed gcc's clz to determine the most significant bit of a
number (useful for things like truncating to a power of 2),
and was surprised it is not a standardized function (the
opposite direction of finding the least significant bit is
given by ffs).  This borrows heavily from the design of the
count-one-bits module.

* modules/count-leading-zeros: New module.
* m4/count-leading-zeros.m4: New file.
* lib/count-leading-zeros.h: Likewise.
* modules/count-leading-zeros-tests: New test.
* tests/test-count-leading-zeros.c: New file.
* MODULES.html.sh (Integer arithmetic functions): Document it.
Signed-off-by: 's avatarEric Blake <eblake@redhat.com>
parent a451aa0d
2012-08-10 Eric Blake <eblake@redhat.com>
count-leading-zeros: new module
* modules/count-leading-zeros: New module.
* m4/count-leading-zeros.m4: New file.
* lib/count-leading-zeros.h: Likewise.
* modules/count-leading-zeros-tests: New test.
* tests/test-count-leading-zeros.c: New file.
* MODULES.html.sh (Integer arithmetic functions): Document it.
2012-08-07 Simon Josefsson <simon@josefsson.org>
Jim Meyering <meyering@redhat.com>
......@@ -1755,6 +1755,7 @@ func_all_modules ()
func_echo "$element"
func_begin_table
func_module count-leading-zeros
func_module count-one-bits
func_module ffs
func_module ffsl
......
/* count-leading-zeros.h -- counts the number of leading 0 bits in a word.
Copyright (C) 2012 Free Software Foundation, Inc.
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */
/* Written by Eric Blake. */
#ifndef COUNT_LEADING_ZEROS_H
# define COUNT_LEADING_ZEROS_H 1
#include <limits.h>
#include <stdlib.h>
#include "verify.h"
/* Expand the code which computes the number of leading zeros of the local
variable 'x' of type TYPE (an unsigned integer type) and returns it
from the current function. */
#if 0 && __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
# define COUNT_LEADING_ZEROS(BUILTIN, TYPE) \
return x ? BUILTIN (x) : CHAR_BIT * sizeof x;
#else
# define COUNT_LEADING_ZEROS(BUILTIN, TYPE) \
/* This condition is written so as to avoid shifting by more than \
31 bits at once, and also avoids a random HP-UX cc bug. */ \
verify (((TYPE) -1 >> 31 >> 31 >> 2) == 0); /* TYPE has at most 64 bits */ \
int count = 0; \
if (1 < (TYPE) -1 >> 31) { /* TYPE has more than 32 bits? */ \
count = count_leading_zeros_32 (x >> 31 >> 1); \
if (count < 32) \
return count; \
} \
return count + count_leading_zeros_32 (x);
/* Compute and return the number of leading zeros in the least
significant 32 bits of X. */
static inline int
count_leading_zeros_32 (unsigned int x)
{
int count = 0;
if (x & 0xffff0000U)
x >>= 16;
else
count += 16;
if (x & 0xff00)
x >>= 8;
else
count += 8;
if (x & 0xf0)
x >>= 4;
else
count += 4;
if (x & 0xc)
x >>= 2;
else
count += 2;
if (x & 2)
x >>= 1;
else
count++;
if (!(x & 1))
count++;
return count;
}
#endif
/* Compute and return the number of leading zeros in X. */
static inline int
count_leading_zeros (unsigned int x)
{
COUNT_LEADING_ZEROS (__builtin_clz, unsigned int);
}
/* Compute and return the number of leading zeros in X. */
static inline int
count_leading_zeros_l (unsigned long int x)
{
COUNT_LEADING_ZEROS (__builtin_clzl, unsigned long int);
}
#if HAVE_UNSIGNED_LONG_LONG_INT
/* Compute and return the number of leading zeros in X. */
static inline int
count_leading_zeros_ll (unsigned long long int x)
{
COUNT_LEADING_ZEROS (__builtin_clzll, unsigned long long int);
}
#endif
#endif /* COUNT_LEADING_ZEROS_H */
# count-leading-zeros.m4 serial 1
dnl Copyright (C) 2012 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
AC_DEFUN([gl_COUNT_LEADING_ZEROS],
[
dnl We don't need (and can't compile) count_leading_zeros_ll
dnl unless the type 'unsigned long long int' exists.
AC_REQUIRE([AC_TYPE_UNSIGNED_LONG_LONG_INT])
dnl Prerequisites of lib/count-leading-zeros.h.
AC_REQUIRE([AC_C_INLINE])
])
Description:
Counts the number of leading 0-bits in a word.
Files:
lib/count-leading-zeros.h
m4/count-leading-zeros.m4
Depends-on:
verify
configure.ac:
gl_COUNT_LEADING_ZEROS
Makefile.am:
Include:
"count-leading-zeros.h"
License:
LGPLv2+
Maintainer:
Eric Blake
Files:
tests/test-count-leading-zeros.c
tests/macros.h
Depends-on:
configure.ac:
Makefile.am:
TESTS += test-count-leading-zeros
check_PROGRAMS += test-count-leading-zeros
/*
* Copyright (C) 2012 Free Software Foundation, Inc.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */
/* Written by Eric Blake. */
#include <config.h>
#include "count-leading-zeros.h"
#include <limits.h>
#include <stdio.h>
#include "macros.h"
#define UINT_BIT (sizeof (unsigned int) * CHAR_BIT)
#define ULONG_BIT (sizeof (unsigned long int) * CHAR_BIT)
#define ULLONG_BIT (sizeof (unsigned long long int) * CHAR_BIT)
#ifndef ULLONG_MAX
# define HALF (1ULL << (sizeof (unsigned long long int) * CHAR_BIT - 1))
# define ULLONG_MAX (HALF - 1 + HALF)
#endif
int
main (int argc, char *argv[])
{
int i, j;
#define TEST_COUNT_LEADING_ZEROS(FUNC, TYPE, BITS, MAX, ONE) \
ASSERT (FUNC (0) == BITS); \
for (i = 0; i < BITS; i++) \
{ \
ASSERT (FUNC (ONE << i) == BITS - i - 1); \
for (j = 0; j < i; j++) \
ASSERT (FUNC ((ONE << i) | (ONE << j)) == BITS - i - 1);\
} \
for (i = 0; i < 1000; i++) \
{ \
TYPE value = rand () ^ (rand () << 31 << 1); \
int count = 0; \
for (j = 0; j < BITS; j++) \
if (value & (ONE << j)) \
count = BITS - j - 1; \
ASSERT (count == FUNC (value)); \
} \
ASSERT (FUNC (MAX) == 0);
TEST_COUNT_LEADING_ZEROS (count_leading_zeros, unsigned int,
UINT_BIT, UINT_MAX, 1U);
TEST_COUNT_LEADING_ZEROS (count_leading_zeros_l, unsigned long int,
ULONG_BIT, ULONG_MAX, 1UL);
#ifdef HAVE_UNSIGNED_LONG_LONG_INT
TEST_COUNT_LEADING_ZEROS (count_leading_zeros_ll, unsigned long long int,
ULLONG_BIT, ULLONG_MAX, 1ULL);
#endif
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment