Skip to main content

scratch_test_value/arithmetic/
division.rs

1use crate::{
2    QuirkSink, SNumber, SValue,
3    quirks::{SNumberToFloatQ, SValueToNumberQ},
4};
5
6impl SValue {
7    /// See [`SNumber::q_div_numbers`]
8    pub fn q_div_numbers<Q>(&self, other: &SValue, sink: &mut Q) -> SValue
9    where
10        Q: QuirkSink<SValueToNumberQ> + QuirkSink<SNumberToFloatQ>,
11    {
12        self.q_as_number(sink)
13            .q_div_numbers(&other.q_as_number(sink), sink)
14            .svalue()
15    }
16}
17
18impl SNumber {
19    /// Integers are automatically divided as floats (if the remainder != 0) but I think this
20    /// shouldn't be considered a quirk as some people would actually like it (?)
21    ///
22    /// The division rules are not necessarily identical to IEEE 754.
23    ///
24    /// - n·m / m → n (integer division without remainder)
25    ///
26    /// If both numbers are finite integers and the division would have a remainder
27    /// of 0 the numbers are divided as integers.
28    /// Otherwise, the below table applys. p and q are arbitraty finite floats.
29    ///
30    /// (line / column is shown in cell)
31    ///
32    /// | `/`   |    | `NaN` | `+∞`  | `-∞`  |  +q  | -q   | `+0`  | `-0`  |
33    /// | ----- | -- | ----- | ----- | ----- | ---- | ---- | ----- | ----- |
34    /// |       |    |       |       |       |      |      |       |       |
35    /// | `NaN` |    | `NaN` | `+0`  | `-0`  | `+0` | `-0` | `NaN` | `NaN` |
36    /// | `+∞`  |    | `+∞`  | `NaN` | `NaN` | `+∞` | `-∞` | `+∞`  | `-∞`  |
37    /// | `-∞`  |    | `-∞`  | `NaN` | `NaN` | `-∞` | `+∞` | `-∞`  | `+∞`  |
38    /// |  +p   |    | `+∞`  | `+0`  | `-0`  |  p/q | -p/q | `+∞`  | `-∞`  |
39    /// |  -p   |    | `-∞`  | `-0`  | `+0`  | -p/q |  p/q | `-∞`  | `+∞`  |
40    /// | `+0`  |    | `NaN` | `+0`  | `-0`  | `+0` | `-0` | `NaN` | `NaN` |
41    /// | `-0`  |    | `NaN` | `-0`  | `+0`  | `-0` | `+0` | `NaN` | `NaN` |
42    pub fn q_div_numbers<Q>(&self, other: &SNumber, sink: &mut Q) -> SNumber
43    where
44        Q: QuirkSink<SNumberToFloatQ>,
45    {
46        if let (SNumber::Int(a), SNumber::Int(b)) = (self, other)
47            && a.checked_rem(*b) == Some(0)
48            && let Some(res) = a.checked_div(*b)
49        {
50            return SNumber::Int(res);
51        }
52
53        let a = self.q_as_float(sink);
54        let b = other.q_as_float(sink);
55
56        if a.is_nan() && b.is_nan() {
57            return SNumber::NAN;
58        }
59
60        if (a == 0.0 || a == -0.0) && b.is_nan() {
61            return Self::NAN;
62        }
63        if a.is_nan() && (b == 0.0 || b == -0.0) {
64            return Self::NAN;
65        }
66
67        if b.is_nan() {
68            return if a.is_sign_positive() {
69                SNumber::INFINITY
70            } else {
71                SNumber::NEG_INFINITY
72            };
73        }
74        if a.is_nan() && b.is_infinite() {
75            return SNumber::Float(if b.is_sign_positive() { 0.0 } else { -0.0 });
76        }
77        if a.is_nan() && b.is_finite() {
78            return SNumber::Float(if b.is_sign_positive() { 0.0 } else { -0.0 });
79        }
80
81        SNumber::Float(a / b)
82    }
83}