rustymath_core/recipe/
integer.rs1use super::{Binary, Cmp, Integer, Ops, Overflowing, Unary};
3use crate::buffer::FloatWidth;
4
5pub struct IntegerOps<T> { pub variant: crate::domain::Variant, item: std::marker::PhantomData<T> }
6impl<T> IntegerOps<T> {
7 #[inline(always)]
8 pub fn new(variant: crate::domain::Variant) -> Self { Self { variant, item: std::marker::PhantomData } }
9}
10impl<T: Overflowing> IntegerOps<T> {
11 #[inline(always)]
12 pub fn result(&self, value: i64) -> T {
13 if self.variant.fails_on_overflow() && matches!(self.variant.dtype, crate::buffer::DType::Integer(w) if !w.holds(value)) {
14 (crate::error::Kind::Overflow.reporter())();
15 }
16 T::low(value)
17 }
18}
19impl<T: Overflowing> Ops<f64> for IntegerOps<T> {
20 type V = T;
21 type B = bool;
22 type I = u64;
23 type W = f64;
24 #[inline(always)]
25 fn width(&self) -> FloatWidth { FloatWidth::F64 }
26 #[inline(always)]
27 fn fused(&self) -> bool { false }
28 #[inline(always)]
29 fn integral(&self) -> bool { true }
30 #[inline(always)]
31 fn widen(&self, x: T) -> f64 { Into::<i64>::into(x) as f64 }
32 #[inline(always)]
33 fn wide_number(&self, x: f64) -> f64 { x }
34 #[inline(always)]
35 fn wide_multiply_add(&self, x: f64, y: f64, z: f64) -> f64 { x * y + z }
36 #[inline(always)]
37 fn narrow(&self, x: f64) -> T { T::low(x as i64) }
38 u64_integers!(8 * std::mem::size_of::<T>() as u32);
39 #[inline(always)]
40 fn to_integer(&self, x: T) -> u64 { Into::<i64>::into(x) as u64 }
41 #[inline(always)]
42 fn from_integer(&self, x: u64) -> T { self.from_bits(x) }
43 #[inline(always)]
44 fn to_bits(&self, x: T) -> u64 { Into::<i64>::into(x) as u64 }
45 #[inline(always)]
46 fn from_bits(&self, x: u64) -> T { T::low(if self.variant.dtype == crate::buffer::DType::Boolean { (x & 1) as i64 } else { x as i64 }) }
47 #[inline(always)]
48 fn number(&self, x: f64) -> T { T::low(x as i64) }
49 #[inline(always)]
50 fn unary(&self, op: Unary, x: T) -> T {
51 match op {
52 Unary::Negate => T::low(0).minus(x).0, Unary::Magnitude => x.magnitude().0, Unary::Floor => x,
53 Unary::Sqrt => { let x = Into::<i64>::into(x); T::low(if x >= 0 { x.isqrt() } else { 0 }) } Unary::Not => T::low(1).minus(x).0,
54 _ => unreachable!("non-integer instruction in an integer formula")
55 }
56 }
57 #[inline(always)]
58 fn binary(&self, op: Binary, x: T, y: T) -> T {
59 match op {
60 Binary::Add => x.plus(y).0,
61 Binary::Subtract => x.minus(y).0,
62 Binary::Multiply => x.times(y).0,
63 Binary::Divide => {
65 let (x, y): (i64, i64) = (x.into(), y.into());
66 if y != 0 { T::low(x.wrapping_div(y)) }
67 else if self.variant.fails_on_overflow() {
68 self.result(if x == 0 { 0 } else if x > 0 { i64::MAX } else { i64::MIN })
69 } else { T::limit(x) }
70 }
71 Binary::Larger => x.max(y),
72 Binary::Smaller => x.min(y),
73 Binary::BitAnd => T::low(Into::<i64>::into(x) & Into::<i64>::into(y)),
74 _ => unreachable!("non-integer instruction in an integer formula"),
75 }
76 }
77 #[inline(always)]
78 fn overflow(&self, op: Binary, x: T, y: T) -> bool {
79 !match op {
80 Binary::Add => x.plus(y).1,
81 Binary::Subtract => x.minus(y).1,
82 Binary::Multiply => x.times(y).1,
83 Binary::Divide => {
85 let (x, y): (i64, i64) = (x.into(), y.into());
86 x.checked_div(y).map_or(y == 0, |q| Into::<i64>::into(T::low(q)) == q)
87 }
88 _ => true,
89 }
90 }
91 plain_logic!(T);
92 #[inline(always)]
93 fn multiply_add(&self, x: T, y: T, z: T) -> T { self.binary(Binary::Add, self.binary(Binary::Multiply, x, y), z) }
94}