Initial commit.

This commit is contained in:
hal8174 2024-09-21 22:26:15 +02:00
commit 0e372df756
4 changed files with 343 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

175
Cargo.lock generated Normal file
View file

@ -0,0 +1,175 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "bitexperimentation"
version = "0.1.0"
dependencies = [
"quickcheck",
"quickcheck_macros",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "env_logger"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3"
dependencies = [
"log",
"regex",
]
[[package]]
name = "getrandom"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "libc"
version = "0.2.158"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
[[package]]
name = "log"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "proc-macro2"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quickcheck"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6"
dependencies = [
"env_logger",
"log",
"rand",
]
[[package]]
name = "quickcheck_macros"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b22a693222d716a9587786f37ac3f6b4faedb5b80c23914e7303ff5a1d8016e9"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "quote"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "regex"
version = "1.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"

11
Cargo.toml Normal file
View file

@ -0,0 +1,11 @@
[package]
name = "bitexperimentation"
version = "0.1.0"
edition = "2021"
[dependencies]
[dev-dependencies]
quickcheck = "1"
quickcheck_macros = "1"

156
src/main.rs Normal file
View file

@ -0,0 +1,156 @@
#[allow(non_snake_case)]
fn L(k: u8) -> u64 {
let mut s = 0;
for i in 0..64u8.div_ceil(k) {
s |= 1 << (i * k);
}
s
}
#[allow(non_snake_case)]
fn H(k: u8) -> u64 {
L(k) << (k - 1)
}
fn sideways_addition(x: u64) -> u64 {
let s = x - ((x & 0xAAAAAAAAAAAAAAAA) >> 1);
// 0xA = 0b1010
let s = (s & 0x3333333333333333) + ((s >> 2) & 0x3333333333333333);
// 0x3 = 0b0011
let s = (s + (s >> 4)) & 0x0F0F0F0F0F0F0F0F;
u64::wrapping_mul(s, L(8)) >> 56
}
fn less_equal_k_signed(x: u64, y: u64, k: u8) -> u64 {
let s = (y | H(k)) - (x & !H(k));
let s = s ^ x ^ y;
let s = s | (x & !y);
let s = s & !(!x & y);
s & H(k)
}
fn less_equal_k_unsigned(x: u64, y: u64, k: u8) -> u64 {
let s = (y | H(k)) - (x & !H(k));
let s = s | x ^ y;
let s = s ^ (x & !y);
s & H(k)
}
fn grater_than_0_k_unsigned(x: u64, k: u8) -> u64 {
(((x | H(k)) - L(k)) | x) & H(k)
}
fn select64(x: u64, r: u64) -> u64 {
// Same as in sideways addition
let s = x - ((x & 0xAAAAAAAAAAAAAAAA) >> 1);
// 0xA = 0b1010
let s = (s & 0x3333333333333333) + ((s >> 2) & 0x3333333333333333);
// 0x3 = 0b0011
let s = ((s + (s >> 4)) & 0x0F0F0F0F0F0F0F0F).wrapping_mul(L(8));
// Select byte
// b: byte index << 3
let b =
(less_equal_k_signed(s, r.wrapping_mul(L(8)), 8) >> 7).wrapping_mul(L(8)) >> 53 & (!0x7);
if b == 64 {
return 72;
}
// extract selected byte
let l = r - (((s << 8) >> b) & 0xFF);
// select index in byte
let s = (grater_than_0_k_unsigned((x >> b & 0xFF).wrapping_mul(L(8)) & 0x8040201008040201, 8)
>> 7)
.wrapping_mul(L(8));
b + ((less_equal_k_signed(s, l.wrapping_mul(L(8)), 8) >> 7).wrapping_mul(L(8)) >> 56)
}
fn trivial_select(data: u64, count: u8) -> u8 {
let mut l = 0;
let mut r = 63;
while l < r {
let m = (l + r) / 2;
let shift = 64 - m - 1;
let shifted = data << shift;
let local_count = shifted.count_ones();
// dbg!(l, r, m, shift, local_count, r);
if local_count < count as u32 {
l = m + 1;
} else {
r = m;
}
}
l as u8
}
fn main() {
dbg!(select64(3, 1));
dbg!(trivial_select(3, 3));
}
#[cfg(test)]
mod test {
use quickcheck_macros::quickcheck;
use crate::*;
#[quickcheck]
fn qc_test_sideways_addition(x: u64) -> bool {
x.count_ones() as u64 == sideways_addition(x)
}
#[quickcheck]
fn qc_less_equal_8_signed(x: u64, y: u64) -> bool {
let s = less_equal_k_signed(x, y, 8).to_be_bytes();
s.iter()
.zip(x.to_be_bytes().iter().zip(y.to_be_bytes().iter()))
.all(|(s, (&x, &y))| match s {
0x00 => (x as i8) > (y as i8),
0x80 => (x as i8) <= (y as i8),
_ => false,
})
}
#[quickcheck]
fn qc_less_equal_k_unsigned(x: u64, y: u64) -> bool {
let s = less_equal_k_unsigned(x, y, 8).to_be_bytes();
s.iter()
.zip(x.to_be_bytes().iter().zip(y.to_be_bytes().iter()))
.all(|(s, (&x, &y))| match s {
0x00 => x > y,
0x80 => x <= y,
_ => false,
})
}
#[quickcheck]
fn qc_grater_than_0_k_unsigned(x: u64) -> bool {
let s = grater_than_0_k_unsigned(x, 8).to_be_bytes();
s.iter().zip(x.to_be_bytes().iter()).all(|(a, b)| match a {
0x00 => b == &0,
0x80 => b > &0,
_ => false,
})
}
#[quickcheck]
fn qc_select64(x: u64, r: u8) -> bool {
let r = r.clamp(1, 64);
let s = select64(x, r as u64);
if x.count_ones() <= r as u32 {
s == 72
} else {
trivial_select(x, r + 1) as u64 == s
}
}
}