[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