Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • Kazan-team/algebraics
1 result
Show changes
Commits on Source (2)
......@@ -11,6 +11,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
* add changes here
## [0.3.0]
### Changed
* Updated dependency versions
## [0.2.0]
### Changed
......
......@@ -2,7 +2,7 @@
# See Notices.txt for copyright information
[package]
name = "algebraics"
version = "0.2.0"
version = "0.3.0"
authors = ["Jacob Lifshay <programmerjake@gmail.com>"]
edition = "2018"
license = "LGPL-2.1-or-later"
......@@ -22,15 +22,15 @@ name = "algebraics"
crate-type = ["rlib", "cdylib"]
[dependencies]
num-traits = "0.2"
num-bigint = "0.2"
num-integer = "0.1"
num-rational = "0.2"
rand = "0.5"
rand_pcg = "0.1.1"
num-traits = "0.2.14"
num-bigint = "0.4.3"
num-integer = "0.1.44"
num-rational = "0.4.0"
rand = "0.8.5"
rand_pcg = "0.3.1"
lazy_static = "1.4"
[dependencies.pyo3]
version = "0.9.0"
version = "0.16"
optional = true
features = ["num-bigint"]
......@@ -86,7 +86,7 @@ Using algebraics in your own Rust project:
```toml
[dependencies.algebraics]
version = "0.2"
version = "0.3"
```
Developing algebraics:
......
# SPDX-License-Identifier: LGPL-2.1-or-later
# See Notices.txt for copyright information
[build-system]
requires = ["maturin"]
requires = ["maturin>=0.11,<0.12"]
build-backend = "maturin"
[tool.maturin]
......
......@@ -181,7 +181,7 @@ where
mod tests {
use super::*;
use num_bigint::BigInt;
use num_traits::{One, Pow};
use num_traits::One;
#[test]
fn test_gram_schmidt() {
......@@ -281,16 +281,6 @@ mod tests {
assert!(output == expected);
}
// workaround for https://github.com/rust-num/num-bigint/issues/106
fn pow<'a, T>(base: &'a Ratio<BigInt>, exponent: &'a T) -> Ratio<BigInt>
where
&'a BigInt: Pow<&'a T, Output = BigInt>,
{
let numer = base.numer().pow(exponent);
let denom = base.denom().pow(exponent);
Ratio::new(numer, denom)
}
#[test]
fn test_lll_reduce() {
let ints = |v: &[i64]| -> Vec<BigInt> { v.iter().copied().map(BigInt::from).collect() };
......@@ -324,7 +314,7 @@ mod tests {
assert!(output == expected);
// find the minimal polynomial of sin(pi / 7)
let multiplier = BigInt::from(1) << 48;
let multiplier = BigInt::one() << 48i32;
// approximation to 1024 fractional bits
let sin_pi_7_approximation: Ratio<BigInt> =
"97498727392503287796421964844598099607650972550809391824625445149289352\
......@@ -348,7 +338,8 @@ mod tests {
BigInt::zero()
}
} else {
-pow(&sin_pi_7_approximation, &x)
-(&sin_pi_7_approximation)
.pow(x as i32)
.mul(&multiplier)
.round()
.to_integer()
......
......@@ -20,8 +20,9 @@ pub use algebraic_numbers::RealAlgebraicNumber;
macro_rules! doctest {
($x:expr) => {
#[allow(unused_doc_comments)]
#[doc = $x]
extern {}
extern "C" {}
};
}
......
......@@ -3,148 +3,83 @@
#![cfg(feature = "python")]
use crate::{algebraic_numbers::RealAlgebraicNumber, traits::ExactDivAssign};
use crate::{algebraic_numbers::RealAlgebraicNumber, traits::ExactDiv};
use num_bigint::BigInt;
use num_traits::{Signed, Zero};
use pyo3::{
basic::CompareOp,
exceptions::{TypeError, ValueError, ZeroDivisionError},
exceptions::{PyTypeError, PyValueError, PyZeroDivisionError},
prelude::*,
types::PyAny,
PyNativeType, PyNumberProtocol, PyObjectProtocol,
};
use std::{
ops::{Deref, DerefMut},
sync::Arc,
};
impl FromPyObject<'_> for RealAlgebraicNumber {
fn extract(value: &PyAny) -> PyResult<Self> {
Ok(RealAlgebraicNumberWrapper::extract(value)?.into())
}
}
impl<'a> FromPyObject<'a> for &'a RealAlgebraicNumber {
fn extract(value: &'a PyAny) -> PyResult<Self> {
let wrapper: RealAlgebraicNumberWrapper = value.extract()?;
Ok(&value.py().register_any(wrapper))
}
}
impl IntoPy<PyObject> for RealAlgebraicNumber {
fn into_py(self, py: Python) -> PyObject {
RealAlgebraicNumberWrapper::from(self).into_py(py)
}
}
impl IntoPy<PyObject> for &'_ RealAlgebraicNumber {
fn into_py(self, py: Python) -> PyObject {
RealAlgebraicNumberWrapper::from(self).into_py(py)
}
}
impl ToPyObject for RealAlgebraicNumber {
fn to_object(&self, py: Python) -> PyObject {
self.into_py(py)
}
}
#[derive(Clone)]
struct RealAlgebraicNumberWrapper(Arc<RealAlgebraicNumber>);
struct SharedNumber(Arc<RealAlgebraicNumber>);
impl Deref for RealAlgebraicNumberWrapper {
impl Deref for SharedNumber {
type Target = Arc<RealAlgebraicNumber>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for RealAlgebraicNumberWrapper {
impl DerefMut for SharedNumber {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl FromPyObject<'_> for RealAlgebraicNumberWrapper {
fn extract(value: &PyAny) -> PyResult<Self> {
if let Ok(value) = value.extract::<PyRef<RealAlgebraicNumberPy2>>() {
return Ok(value.value.clone());
}
let value = value.extract::<BigInt>()?;
Ok(RealAlgebraicNumber::from(value).into())
}
}
impl From<Arc<RealAlgebraicNumber>> for RealAlgebraicNumberWrapper {
fn from(v: Arc<RealAlgebraicNumber>) -> Self {
RealAlgebraicNumberWrapper(v)
}
}
impl From<RealAlgebraicNumber> for RealAlgebraicNumberWrapper {
impl From<RealAlgebraicNumber> for SharedNumber {
fn from(v: RealAlgebraicNumber) -> Self {
RealAlgebraicNumberWrapper(v.into())
SharedNumber(v.into())
}
}
impl From<&'_ RealAlgebraicNumber> for RealAlgebraicNumberWrapper {
fn from(v: &RealAlgebraicNumber) -> Self {
RealAlgebraicNumber::clone(v).into()
}
}
impl Into<Arc<RealAlgebraicNumber>> for RealAlgebraicNumberWrapper {
fn into(self) -> Arc<RealAlgebraicNumber> {
self.0
}
}
impl From<RealAlgebraicNumberWrapper> for RealAlgebraicNumber {
fn from(v: RealAlgebraicNumberWrapper) -> Self {
match Arc::try_unwrap(v.0) {
Ok(v) => v,
Err(v) => (*v).clone(),
}
}
}
impl IntoPy<PyObject> for RealAlgebraicNumberWrapper {
impl IntoPy<PyObject> for SharedNumber {
fn into_py(self, py: Python) -> PyObject {
RealAlgebraicNumberPy2 { value: self }.into_py(py)
}
}
impl IntoPy<PyObject> for &'_ RealAlgebraicNumberWrapper {
fn into_py(self, py: Python) -> PyObject {
RealAlgebraicNumberWrapper::clone(self).into_py(py)
impl FromPyObject<'_> for SharedNumber {
fn extract(value: &PyAny) -> PyResult<Self> {
if let Ok(value) = value.extract::<PyRef<RealAlgebraicNumberPy2>>() {
return Ok(value.value.clone());
}
let value = value.extract::<BigInt>()?;
Ok(RealAlgebraicNumber::from(value).into())
}
}
impl ToPyObject for RealAlgebraicNumberWrapper {
fn to_object(&self, py: Python) -> PyObject {
self.into_py(py)
}
#[pyclass(name = "RealAlgebraicNumber", module = "algebraics")]
struct RealAlgebraicNumberPy2 {
value: SharedNumber,
}
#[pyclass(name=RealAlgebraicNumber, module="algebraics")]
struct RealAlgebraicNumberPy2 {
value: RealAlgebraicNumberWrapper,
impl From<&'_ PyCell<RealAlgebraicNumberPy2>> for SharedNumber {
fn from(v: &PyCell<RealAlgebraicNumberPy2>) -> Self {
v.borrow().value.clone()
}
}
#[pymethods(PyObjectProtocol, PyNumberProtocol)]
#[pymethods]
impl RealAlgebraicNumberPy2 {
#[new]
fn pynew(value: Option<RealAlgebraicNumberWrapper>) -> Self {
fn pynew(value: Option<SharedNumber>) -> Self {
let value = value.unwrap_or_else(|| RealAlgebraicNumber::zero().into());
RealAlgebraicNumberPy2 { value }
}
fn __trunc__(&self, py: Python<'_>) -> BigInt {
fn __trunc__(&self, py: Python) -> BigInt {
py.allow_threads(|| self.value.to_integer_trunc())
}
fn __floor__(&self, py: Python<'_>) -> BigInt {
fn __floor__(&self, py: Python) -> BigInt {
py.allow_threads(|| self.value.to_integer_floor())
}
fn __ceil__(&self, py: Python<'_>) -> BigInt {
fn __ceil__(&self, py: Python) -> BigInt {
py.allow_threads(|| self.value.to_integer_ceil())
}
fn to_integer(&self) -> Option<BigInt> {
......@@ -167,30 +102,26 @@ impl RealAlgebraicNumberPy2 {
fn is_integer(&self) -> bool {
self.value.is_integer()
}
fn recip(&self, py: Python<'_>) -> PyResult<RealAlgebraicNumberWrapper> {
fn recip(&self, py: Python) -> PyResult<SharedNumber> {
py.allow_threads(|| Some(self.value.checked_recip()?.into()))
.ok_or_else(get_div_by_zero_error)
}
/// returns `floor(log2(self))`
fn floor_log2(&self, py: Python<'_>) -> PyResult<i64> {
fn floor_log2(&self, py: Python) -> PyResult<i64> {
py.allow_threads(|| self.value.checked_floor_log2())
.ok_or_else(get_floor_ceil_log2_error)
}
/// returns `ceil(log2(self))`
fn ceil_log2(&self, py: Python<'_>) -> PyResult<i64> {
fn ceil_log2(&self, py: Python) -> PyResult<i64> {
py.allow_threads(|| self.value.checked_ceil_log2())
.ok_or_else(get_floor_ceil_log2_error)
}
}
#[pyproto]
impl PyObjectProtocol for RealAlgebraicNumberPy2 {
// Basic object methods
fn __repr__(&self) -> PyResult<String> {
Ok(format!("<{:?}>", *self.value))
}
fn __richcmp__(&self, other: &PyAny, op: CompareOp) -> PyResult<bool> {
let py = other.py();
let other = other.extract::<RealAlgebraicNumberWrapper>()?;
fn __richcmp__(&self, py: Python, other: SharedNumber, op: CompareOp) -> PyResult<bool> {
Ok(py.allow_threads(|| match op {
CompareOp::Lt => *self.value < *other,
CompareOp::Le => *self.value <= *other,
......@@ -200,123 +131,123 @@ impl PyObjectProtocol for RealAlgebraicNumberPy2 {
CompareOp::Ge => *self.value >= *other,
}))
}
}
fn get_div_by_zero_error() -> PyErr {
ZeroDivisionError::py_err("can't divide RealAlgebraicNumber by zero")
}
fn get_floor_ceil_log2_error() -> PyErr {
ValueError::py_err("can't extract base-2 logarithm of zero or negative RealAlgebraicNumber")
}
fn try_arithmetic_helper<
E: Send,
F: Send + FnOnce(&mut RealAlgebraicNumber, &RealAlgebraicNumber) -> Result<(), E>,
MapErr: FnOnce(E) -> PyErr,
>(
lhs: &PyAny,
rhs: RealAlgebraicNumberWrapper,
f: F,
map_err: MapErr,
) -> PyResult<RealAlgebraicNumberWrapper> {
let py = lhs.py();
let mut lhs: RealAlgebraicNumberWrapper = lhs.extract()?;
py.allow_threads(|| {
f(Arc::make_mut(&mut lhs), &**rhs)?;
Ok(lhs)
})
.map_err(map_err)
}
fn arithmetic_helper<F: Send + FnOnce(&mut RealAlgebraicNumber, &RealAlgebraicNumber)>(
lhs: &PyAny,
rhs: RealAlgebraicNumberWrapper,
f: F,
) -> PyResult<RealAlgebraicNumberWrapper> {
enum Uninhabited {}
try_arithmetic_helper(
lhs,
rhs,
|lhs, rhs| {
f(lhs, rhs);
Ok(())
},
|v: Uninhabited| match v {},
)
}
#[pyproto]
impl PyNumberProtocol for RealAlgebraicNumberPy2 {
fn __add__(
lhs: &PyAny,
rhs: RealAlgebraicNumberWrapper,
) -> PyResult<RealAlgebraicNumberWrapper> {
arithmetic_helper(lhs, rhs, |lhs, rhs| *lhs += rhs)
}
fn __sub__(
lhs: &PyAny,
rhs: RealAlgebraicNumberWrapper,
) -> PyResult<RealAlgebraicNumberWrapper> {
arithmetic_helper(lhs, rhs, |lhs, rhs| *lhs -= rhs)
}
fn __mul__(
lhs: &PyAny,
rhs: RealAlgebraicNumberWrapper,
) -> PyResult<RealAlgebraicNumberWrapper> {
arithmetic_helper(lhs, rhs, |lhs, rhs| *lhs *= rhs)
}
fn __truediv__(
lhs: &PyAny,
rhs: RealAlgebraicNumberWrapper,
) -> PyResult<RealAlgebraicNumberWrapper> {
// Numeric methods
fn __add__(lhs: SharedNumber, py: Python, rhs: SharedNumber) -> PyResult<SharedNumber> {
arithmetic_helper(py, lhs, rhs, |lhs, rhs| lhs + rhs)
}
fn __radd__(rhs: SharedNumber, py: Python, lhs: SharedNumber) -> PyResult<SharedNumber> {
Self::__add__(lhs, py, rhs)
}
fn __sub__(lhs: SharedNumber, py: Python, rhs: SharedNumber) -> PyResult<SharedNumber> {
arithmetic_helper(py, lhs, rhs, |lhs, rhs| lhs - rhs)
}
fn __rsub__(rhs: SharedNumber, py: Python, lhs: SharedNumber) -> PyResult<SharedNumber> {
Self::__sub__(lhs, py, rhs)
}
fn __mul__(lhs: SharedNumber, py: Python, rhs: SharedNumber) -> PyResult<SharedNumber> {
arithmetic_helper(py, lhs, rhs, |lhs, rhs| lhs * rhs)
}
fn __rmul__(rhs: SharedNumber, py: Python, lhs: SharedNumber) -> PyResult<SharedNumber> {
Self::__mul__(lhs, py, rhs)
}
fn __truediv__(lhs: SharedNumber, py: Python, rhs: SharedNumber) -> PyResult<SharedNumber> {
try_arithmetic_helper(
py,
lhs,
rhs,
|lhs, rhs| lhs.checked_exact_div_assign(rhs),
|()| get_div_by_zero_error(),
|lhs, rhs| lhs.checked_exact_div(rhs).ok_or(()),
|_| get_div_by_zero_error(),
)
}
fn __rtruediv__(rhs: SharedNumber, py: Python, lhs: SharedNumber) -> PyResult<SharedNumber> {
Self::__truediv__(lhs, py, rhs)
}
fn __pow__(
lhs: &PyAny,
rhs: RealAlgebraicNumberWrapper,
lhs: SharedNumber,
py: Python,
rhs: SharedNumber,
modulus: &PyAny,
) -> PyResult<RealAlgebraicNumberWrapper> {
) -> PyResult<SharedNumber> {
if !modulus.is_none() {
return Err(TypeError::py_err(
return Err(PyTypeError::new_err(
"3 argument pow() not allowed for RealAlgebraicNumber",
));
}
try_arithmetic_helper(
py,
lhs,
rhs,
|lhs, rhs| {
if let Some(rhs) = rhs.to_rational() {
*lhs = lhs
.checked_pow(rhs)
.ok_or("pow() failed for RealAlgebraicNumber")?;
Ok(())
lhs.checked_pow(rhs)
.ok_or("pow() failed for RealAlgebraicNumber")
} else {
Err("exponent must be rational for RealAlgebraicNumber")
}
},
ValueError::py_err,
PyValueError::new_err,
)
}
fn __rpow__(
rhs: SharedNumber,
py: Python,
lhs: SharedNumber,
modulus: &PyAny,
) -> PyResult<SharedNumber> {
Self::__pow__(lhs, py, rhs, modulus)
}
// Unary arithmetic
fn __neg__(&self) -> PyResult<RealAlgebraicNumberWrapper> {
Ok(Python::acquire_gil()
.python()
.allow_threads(|| (-&**self.value).into()))
fn __neg__(&self, py: Python) -> PyResult<SharedNumber> {
Ok(py.allow_threads(|| (-&**self.value).into()))
}
fn __abs__(&self) -> PyResult<RealAlgebraicNumberWrapper> {
Ok(Python::acquire_gil()
.python()
.allow_threads(|| self.value.abs().into()))
fn __abs__(&self, py: Python) -> PyResult<SharedNumber> {
Ok(py.allow_threads(|| self.value.abs().into()))
}
}
fn get_div_by_zero_error() -> PyErr {
PyZeroDivisionError::new_err("can't divide RealAlgebraicNumber by zero")
}
fn get_floor_ceil_log2_error() -> PyErr {
PyValueError::new_err("can't extract base-2 logarithm of zero or negative RealAlgebraicNumber")
}
fn try_arithmetic_helper<
E: Send,
F: Send + FnOnce(&RealAlgebraicNumber, &RealAlgebraicNumber) -> Result<RealAlgebraicNumber, E>,
MapErr: FnOnce(E) -> PyErr,
>(
py: Python,
lhs: SharedNumber,
rhs: SharedNumber,
f: F,
map_err: MapErr,
) -> PyResult<SharedNumber> {
py.allow_threads(|| Ok(f(&lhs, &rhs)?.into()))
.map_err(map_err)
}
fn arithmetic_helper<
F: Send + FnOnce(&RealAlgebraicNumber, &RealAlgebraicNumber) -> RealAlgebraicNumber,
>(
py: Python,
lhs: SharedNumber,
rhs: SharedNumber,
f: F,
) -> PyResult<SharedNumber> {
enum Uninhabited {}
try_arithmetic_helper(
py,
lhs,
rhs,
|lhs, rhs| Ok(f(lhs, rhs)),
|v: Uninhabited| match v {},
)
}
#[pymodule]
fn algebraics(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<RealAlgebraicNumberPy2>()?;
......@@ -332,22 +263,12 @@ mod tests {
#![allow(dead_code)]
#[pyfunction]
fn identity_ref_result(v: &RealAlgebraicNumber) -> PyResult<&RealAlgebraicNumber> {
Ok(v)
}
#[pyfunction]
fn identity_result(v: RealAlgebraicNumber) -> PyResult<RealAlgebraicNumber> {
fn identity_result(v: SharedNumber) -> PyResult<SharedNumber> {
Ok(v)
}
#[pyfunction]
fn identity_ref(v: &RealAlgebraicNumber) -> &RealAlgebraicNumber {
v
}
#[pyfunction]
fn identity(v: RealAlgebraicNumber) -> RealAlgebraicNumber {
fn identity(v: SharedNumber) -> SharedNumber {
v
}
}
......
......@@ -575,14 +575,14 @@ impl PartialOrd<BigRational> for RealQuadraticNumber {
if let Some(lhs) = self.to_ratio() {
lhs < *rhs
} else if self.quadratic_term().is_negative() {
if self.linear_term() * rhs.denom() < 2 * abs_quadratic_term * rhs.numer() {
if self.linear_term() * rhs.denom() < 2i32 * abs_quadratic_term * rhs.numer() {
true
} else {
self.constant_term() * rhs.denom() * rhs.denom()
> -rhs.numer()
* (self.quadratic_term() * rhs.numer() + self.linear_term() * rhs.denom())
}
} else if self.linear_term() * rhs.denom() > -2 * abs_quadratic_term * rhs.numer() {
} else if self.linear_term() * rhs.denom() > -2i32 * abs_quadratic_term * rhs.numer() {
self.constant_term() * rhs.denom() * rhs.denom()
> -rhs.numer()
* (self.quadratic_term() * rhs.numer() + self.linear_term() * rhs.denom())
......@@ -954,7 +954,7 @@ mod tests {
println!("{}: {}", Polynomial::from(poly.clone()), f);
let rqn = RealQuadraticNumber::new(poly).unwrap();
let num = rqn.to_f64().unwrap();
assert!((num - f).abs() < 1e-10, format!("{} != {}", num, f));
assert!((num - f).abs() < 1e-10, "{} != {}", num, f);
}
}
#[test]
......@@ -969,7 +969,7 @@ mod tests {
let rqn = RealQuadraticNumber::new(poly).unwrap();
let num = (-rqn).to_f64().unwrap();
let f = -f;
assert!((num - f).abs() < 1e-10, format!("{} != {}", num, f));
assert!((num - f).abs() < 1e-10, "{} != {}", num, f);
}
}
#[test]
......
......@@ -6,6 +6,7 @@ use num_integer::Integer;
use num_rational::Ratio;
use num_traits::{CheckedDiv, CheckedMul, CheckedRem, NumAssign, One, Signed, ToPrimitive, Zero};
use std::{
convert::TryInto,
fmt,
ops::{Add, Div, DivAssign, Mul},
};
......@@ -401,7 +402,7 @@ impl CeilLog2 for BigUint {
if self.is_zero() {
None
} else {
Some((self - 1u32).bits())
Some((self - 1u32).bits().try_into().unwrap())
}
}
}
......@@ -411,7 +412,7 @@ impl FloorLog2 for BigUint {
if self.is_zero() {
None
} else {
Some(self.bits() - 1)
Some((self.bits() - 1).try_into().unwrap())
}
}
}
......@@ -445,7 +446,7 @@ impl TrailingZeros for BigUint {
impl CeilLog2 for BigInt {
fn ceil_log2(&self) -> Option<usize> {
if self.is_positive() {
Some((self - 1u32).bits())
Some((self - 1u32).bits().try_into().unwrap())
} else {
None
}
......@@ -455,7 +456,7 @@ impl CeilLog2 for BigInt {
impl FloorLog2 for BigInt {
fn floor_log2(&self) -> Option<usize> {
if self.is_positive() {
Some(self.bits() - 1)
Some((self.bits() - 1).try_into().unwrap())
} else {
None
}
......@@ -769,7 +770,7 @@ mod tests {
#[test]
fn test_trailing_zeros() {
let one = BigUint::one();
for i in 0..=256 {
for i in 0..=256u64 {
for j in 0..=i {
let v = (&one << dbg!(i)) | (&one << dbg!(j));
assert_eq!(v.trailing_zeros(), Some(j));
......@@ -781,12 +782,12 @@ mod tests {
fn test_ceil_log2() {
assert_eq!(BigUint::zero().ceil_log2(), None);
assert_eq!(BigInt::zero().ceil_log2(), None);
assert_eq!(0.ceil_log2(), None);
assert_eq!(0i32.ceil_log2(), None);
let one = BigUint::one();
assert_eq!(one.ceil_log2(), Some(0));
assert_eq!(BigInt::one().ceil_log2(), Some(0));
assert_eq!(1.ceil_log2(), Some(0));
for i in 0..=256 {
assert_eq!(1i32.ceil_log2(), Some(0));
for i in 0..=256usize {
for j in 0..=i {
let v = (&one << dbg!(i)) + (&one << dbg!(j));
assert_eq!(v.ceil_log2(), Some(i + 1));
......@@ -804,12 +805,12 @@ mod tests {
fn test_floor_log2() {
assert_eq!(BigUint::zero().floor_log2(), None);
assert_eq!(BigInt::zero().floor_log2(), None);
assert_eq!(0.floor_log2(), None);
assert_eq!(0i32.floor_log2(), None);
let one = BigUint::one();
assert_eq!(one.floor_log2(), Some(0));
assert_eq!(BigInt::one().floor_log2(), Some(0));
assert_eq!(1.floor_log2(), Some(0));
for i in 0..=256 {
assert_eq!(1i32.floor_log2(), Some(0));
for i in 0..=256usize {
for j in 0..=i {
let v = (&one << dbg!(i)) | (&one << dbg!(j));
assert_eq!(v.floor_log2(), Some(i));
......