Struct nekolib::math::ConstDiv2

source ·
pub struct ConstDiv2 { /* private fields */ }
Expand description

定数除算。

除算命令は重いので、加減算や乗算で置き換えることを考える。 同じ値で何度も除算する際には、あらかじめ置き換える値を先に求めておくことで高速化できる。

Barrett reduction に基づく。$a\lt n^2$ に対して、$\lfloor a/n\rfloor$ と $a\bmod n$ を求めることができる。ちゃんと考察すれば、この制約は除ける。 実際、コンパイラは同様の最適化を行う。

example::div2:
        mov     rax, rdi
        shr     rax
        ret
example::div3:
        mov     rax, rdi
        movabs  rcx, -6148914691236517205
        mul     rcx
        mov     rax, rdx
        shr     rax
        ret
example::div63:
        movabs  rcx, 292805461487453201
        mov     rax, rdi
        mul     rcx
        sub     rdi, rdx
        shr     rdi
        lea     rax, [rdi + rdx]
        shr     rax, 5
        ret

example::div64:
        mov     rax, rdi
        shr     rax, 6
        ret

example::div65:
        mov     rax, rdi
        movabs  rcx, 1135184250689818561
        mul     rcx
        mov     rax, rdx
        shr     rax, 2
        ret
fn div63(rdi: u64) -> u64 {
    let rdx = ((rdi as u128 * 0x410410410410411_u128) >> 64) as u64;
    (((rdi - rdx) >> 1) + rdx) >> 5
}

fn div64(rdi: u64) -> u64 { rdi >> 6 }

fn div65(rdi: u64) -> u64 {
    ((rdi as u128 * 0xFC0FC0FC0FC0FC1_u128) >> 66) as u64
}

for i in 0..=100000 {
    assert_eq!(div63(i), i / 63);
    assert_eq!(div64(i), i / 64);
    assert_eq!(div65(i), i / 65);
}

$$ \begin{aligned} \lfloor n/63\rfloor &= (((n-m)\gg 1) + m)\gg 5\text{, where } m=(n\cdot\lceil 2^{64}/63\rceil)\gg 64 \\ \lfloor n/64\rfloor &= n\gg 6 \\ \lfloor n/65\rfloor &= (n\cdot\lceil 2^{66}/65\rceil)\gg 66 \end{aligned} $$

剰余算については、$n\bmod d = n-\lfloor n/d\rfloor\cdot d$ に基づく。 $d$ を掛ける際には定数乗算の最適化(加減算とシフトを用いるなど)を行っていそう。

Naming

除数の 2 乗未満の入力を仮定することから 2 をつけている。

References

Implementations§

source§

impl ConstDiv2

source

pub fn new(n: u64) -> Self

source

pub fn quot(&self, z: u64) -> u64

source

pub fn rem(&self, z: u64) -> u64

Trait Implementations§

source§

impl Clone for ConstDiv2

source§

fn clone(&self) -> ConstDiv2

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for ConstDiv2

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl PartialEq<ConstDiv2> for ConstDiv2

source§

fn eq(&self, other: &ConstDiv2) -> bool

This method tests for self and other values to be equal, and is used by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
source§

impl Copy for ConstDiv2

source§

impl Eq for ConstDiv2

source§

impl StructuralEq for ConstDiv2

source§

impl StructuralPartialEq for ConstDiv2

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> ToOwned for Twhere T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for Twhere V: MultiLane<T>,

§

fn vzip(self) -> V