pub const fn vdc_i(k: usize, base: usize, scale: u32) -> usize {
let mut res = 0;
let mut factor = base.pow(scale);
let mut k = k;
while k != 0 {
let remainder = k % base;
factor /= base;
k /= base;
res += remainder * factor;
}
res
}
#[derive(Debug)]
pub struct VdCorput {
count: usize,
base: usize,
scale: u32,
}
impl VdCorput {
pub const fn new(base: usize, scale: u32) -> Self {
VdCorput {
count: 0,
base,
scale,
}
}
pub fn pop(&mut self) -> usize {
self.count += 1;
vdc_i(self.count, self.base, self.scale)
}
pub fn reseed(&mut self, seed: usize) {
self.count = seed;
}
}
#[derive(Debug)]
pub struct Halton {
vdc0: VdCorput,
vdc1: VdCorput,
}
impl Halton {
pub fn new(base: &[usize], scale: &[u32]) -> Self {
Halton {
vdc0: VdCorput::new(base[0], scale[0]),
vdc1: VdCorput::new(base[1], scale[1]),
}
}
pub fn pop(&mut self) -> [usize; 2] {
[self.vdc0.pop(), self.vdc1.pop()]
}
#[allow(dead_code)]
pub fn reseed(&mut self, seed: usize) {
self.vdc0.reseed(seed);
self.vdc1.reseed(seed);
}
}
macro_rules! div_mod_3_iter {
($input:expr) => {{
let q = $input >> 2; let r = $input & 0x03; (q, q + r) }};
}
pub fn div_mod_3_u8(n: u8) -> (u8, u8) {
let (q1, rem1) = div_mod_3_iter!(n); let (q2, rem2) = div_mod_3_iter!(rem1); let (q3, rem3) = div_mod_3_iter!(rem2); let (q4, rem4) = div_mod_3_iter!(rem3);
let quotient_sum = q1 + q2 + q3 + q4;
if rem4 == 0x03 {
(quotient_sum + 1, 0x00) } else {
(quotient_sum, rem4) }
}
pub fn div_mod_3_u16(n: u16) -> (u16, u16) {
let (q1, rem1) = div_mod_3_iter!(n); let (q2, rem2) = div_mod_3_iter!(rem1); let (q3, rem3) = div_mod_3_iter!(rem2); let (q4, rem4) = div_mod_3_iter!(rem3); let (q5, rem5) = div_mod_3_iter!(rem4); let (q6, rem6) = div_mod_3_iter!(rem5); let (q7, rem7) = div_mod_3_iter!(rem6); let (q8, rem8) = div_mod_3_iter!(rem7);
let quotient_sum = q1 + q2 + q3 + q4 + q5 + q6 + q7 + q8;
if rem8 == 0x03 {
(quotient_sum + 1, 0x00) } else {
(quotient_sum, rem8) }
}
macro_rules! div_mod_7_iter {
($input:expr) => {{
let q = $input >> 3; let r = $input & 0x07; (q, q + r) }};
}
pub fn div_mod_7_u8(n: u8) -> (u8, u8) {
let (q1, rem1) = div_mod_7_iter!(n); let (q2, rem2) = div_mod_7_iter!(rem1); let (q3, rem3) = div_mod_7_iter!(rem2);
let quotient_sum = q1 + q2 + q3;
if rem3 == 0x07 {
(quotient_sum + 1, 0x000) } else {
(quotient_sum, rem3) }
}
pub fn div_mod_7_u16(n: u16) -> (u16, u16) {
let (q1, rem1) = div_mod_7_iter!(n); let (q2, rem2) = div_mod_7_iter!(rem1); let (q3, rem3) = div_mod_7_iter!(rem2); let (q4, rem4) = div_mod_7_iter!(rem3); let (q5, rem5) = div_mod_7_iter!(rem4);
let quotient_sum = q1 + q2 + q3 + q4 + q5;
if rem5 == 0x07 {
(quotient_sum + 1, 0x000) } else {
(quotient_sum, rem5) }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vdc() {
let base = 2;
let scale = 10;
let k = 10;
let res = vdc_i(k, base, scale);
assert_eq!(res, 320);
assert_eq!(vdc_i(1, 2, 10), 512);
assert_eq!(vdc_i(2, 2, 10), 256);
assert_eq!(vdc_i(3, 2, 10), 768);
}
#[test]
fn test_vdcorput() {
let mut vgen = VdCorput::new(2, 10);
vgen.reseed(0);
assert_eq!(vgen.pop(), 512);
assert_eq!(vgen.pop(), 256);
assert_eq!(vgen.pop(), 768);
let mut vgen2 = VdCorput::new(3, 7);
vgen2.reseed(0);
assert_eq!(vgen2.pop(), 729);
assert_eq!(vgen2.pop(), 1458);
assert_eq!(vgen2.pop(), 243);
}
#[test]
fn test_halton() {
let mut hgen = Halton::new(&[2, 3], &[11, 7]);
hgen.reseed(0);
let result = hgen.pop();
assert_eq!(result, [1024, 729]);
let result = hgen.pop();
assert_eq!(result, [512, 1458]);
}
#[test]
fn test_div_mod_3_u8() {
let (q, r) = div_mod_3_u8(10);
assert_eq!(q, 3);
assert_eq!(r, 1);
let (q, r) = div_mod_3_u8(12);
assert_eq!(q, 4);
assert_eq!(r, 0);
}
#[test]
fn test_div_mod_3_u16() {
let (q, r) = div_mod_3_u16(10000);
assert_eq!(q, 3333);
assert_eq!(r, 1);
let (q, r) = div_mod_3_u16(10002);
assert_eq!(q, 3334);
assert_eq!(r, 0);
}
#[test]
fn test_div_mod_7_u8() {
let (q, r) = div_mod_7_u8(10);
assert_eq!(q, 1);
assert_eq!(r, 3);
let (q, r) = div_mod_7_u8(14);
assert_eq!(q, 2);
assert_eq!(r, 0);
}
#[test]
fn test_div_mod_7_u16() {
let (q, r) = div_mod_7_u16(10000);
assert_eq!(q, 1428);
assert_eq!(r, 4);
let (q, r) = div_mod_7_u16(14000);
assert_eq!(q, 2000);
assert_eq!(r, 0);
}
}