[blivet:master 3/3] Add a method that determines whether a number is an exact power of 2.

David Lehman dlehman at redhat.com
Fri Oct 31 20:01:58 UTC 2014


On 10/31/2014 10:31 AM, mulhern wrote:
> Taking the log to determine whether a number is an exact power of 2 does
> not always work, because log computes w/ floats, somehow. It usually works,
> because base 2 works well w/ binary floating point representation.
>
> Decimal does not actually have a log function. You can use change of base
> to get log base 2, but you do not get an exact result.
>
> Use method in is_valid_pool_chunk_size().
>
> Signed-off-by: mulhern <amulhern at redhat.com>
> ---
>   blivet/devicelibs/lvm.py |  3 +--
>   blivet/util.py           | 28 ++++++++++++++++++++++++++++
>   tests/util_test.py       | 22 ++++++++++++++++++++++
>   3 files changed, 51 insertions(+), 2 deletions(-)
>   create mode 100644 tests/util_test.py
>
> diff --git a/blivet/devicelibs/lvm.py b/blivet/devicelibs/lvm.py
> index cf21902..958b974 100644
> --- a/blivet/devicelibs/lvm.py
> +++ b/blivet/devicelibs/lvm.py
> @@ -20,7 +20,6 @@
>   # Author(s): Dave Lehman <dlehman at redhat.com>
>   #
>
> -import math
>   from decimal import Decimal
>   from collections import namedtuple
>
> @@ -212,7 +211,7 @@ def is_valid_thin_pool_chunk_size(size, discard=False):
>           return False
>
>       if discard:
> -        return (math.log(size, 2) % 1.0 == 0)
> +        return util.power_of_two(int(size))
>       else:
>           return (size % LVM_THINP_MIN_CHUNK_SIZE == Size(0))
>
> diff --git a/blivet/util.py b/blivet/util.py
> index a69b694..e045a32 100644
> --- a/blivet/util.py
> +++ b/blivet/util.py
> @@ -524,3 +524,31 @@ def variable_copy(obj, memo, omit=None, shallow=None, duplicate=None):
>   def get_current_entropy():
>       with open("/proc/sys/kernel/random/entropy_avail", "r") as fobj:
>           return int(fobj.readline())
> +
> +def power_of_two(value):
> +    """ Checks whether value is a power of 2 greater than 1.
> +
> +        :param any value: a value
> +        :returns: True if the value is a power of 2
> +        :rtype: bool
> +    """
> +    try:
> +        int_value = int(value)
> +    except (ValueError, TypeError):
> +        return False
> +
> +    if int_value != value:
> +        return False
> +
> +    value = int_value
> +
> +    if value < 2:
> +        return False
> +
> +    (q, r) = (value, 0)
> +    while q != 0:
> +        if r != 0:
> +            return False
> +        (q, r) = q.__divmod__(2)

Why not divmod(q, 2)?

> +
> +    return True
> diff --git a/tests/util_test.py b/tests/util_test.py
> new file mode 100644
> index 0000000..13b8d06
> --- /dev/null
> +++ b/tests/util_test.py
> @@ -0,0 +1,22 @@
> +#!/usr/bin/python
> +
> +import unittest
> +from decimal import Decimal
> +
> +from blivet import util
> +
> +class MiscTest(unittest.TestCase):
> +
> +    longMessage = True
> +
> +    def test_power_of_two(self):
> +        self.assertFalse(util.power_of_two(None))
> +        self.assertFalse(util.power_of_two("not a number"))
> +        self.assertFalse(util.power_of_two(Decimal(2.2)))
> +        self.assertFalse(util.power_of_two(-1))
> +        self.assertFalse(util.power_of_two(0))
> +        self.assertFalse(util.power_of_two(1))
> +        for i in range(1, 60, 5):
> +            self.assertTrue(util.power_of_two(2 ** i), msg=i)
> +            self.assertFalse(util.power_of_two(2 ** i + 1), msg=i)
> +            self.assertFalse(util.power_of_two(2 ** i - 1), msg=i)
>



More information about the anaconda-patches mailing list