spirix 0.1.0

Two's complement floating-point arithmetic library
Documentation
// Add this to the implementations/powers/circle_circle.rs file

use crate::core::integer::*;
use crate::core::undefined::*;
use crate::{Circle, CircleConstants, Integer, Scalar, ScalarConstants};
use core::ops::*;
use i256::I256;
use num_traits::{AsPrimitive, WrappingAdd, WrappingMul, WrappingNeg, WrappingSub};

#[allow(private_bounds)]
impl<
        F: Integer
            + FullInt
            + Shl<isize, Output = F>
            + Shr<isize, Output = F>
            + Shl<F, Output = F>
            + Shr<F, Output = F>
            + Shl<E, Output = F>
            + Shr<E, Output = F>
            + WrappingNeg
            + WrappingAdd
            + WrappingMul
            + WrappingSub,
        E: Integer
            + FullInt
            + Shl<isize, Output = E>
            + Shr<isize, Output = E>
            + Shl<E, Output = E>
            + Shr<E, Output = E>
            + Shl<F, Output = E>
            + Shr<F, Output = E>
            + WrappingNeg
            + WrappingAdd
            + WrappingMul
            + WrappingSub,
    > Circle<F, E>
where
    Circle<F, E>: CircleConstants,
    Scalar<F, E>: ScalarConstants,
    u8: AsPrimitive<F>,
    u16: AsPrimitive<F>,
    u32: AsPrimitive<F>,
    u64: AsPrimitive<F>,
    u128: AsPrimitive<F>,
    usize: AsPrimitive<F>,
    i8: AsPrimitive<F>,
    i16: AsPrimitive<F>,
    i32: AsPrimitive<F>,
    i64: AsPrimitive<F>,
    i128: AsPrimitive<F>,
    isize: AsPrimitive<F>,
    I256: From<F>,
    u8: AsPrimitive<E>,
    u16: AsPrimitive<E>,
    u32: AsPrimitive<E>,
    u64: AsPrimitive<E>,
    u128: AsPrimitive<E>,
    usize: AsPrimitive<E>,
    i8: AsPrimitive<E>,
    i16: AsPrimitive<E>,
    i32: AsPrimitive<E>,
    i64: AsPrimitive<E>,
    i128: AsPrimitive<E>,
    isize: AsPrimitive<E>,
    I256: From<E>,
{
    pub(crate) fn circle_power_circle(&self, exp: &Self) -> Self {
        // A purely-real exponent is the scalar-exponent op: reroute so all of circle_power_scalar's resolutions (zero base, escaped base thru the multiply chain / rotation, ∞ base) apply uniformly.
        if exp.is_normal() && exp.i().is_zero() {
            return self.circle_power_scalar(&exp.r());
        }
        if !self.is_normal() || !exp.is_normal() {
            if self.is_undefined() {
                return *self;
            }
            if exp.is_undefined() {
                return *exp;
            }
            // z^0 = 1 for any finite z (0^0 = 1 included). The old code fell past this: a zero exponent has real = 0, so the is_positive test below sent 0^0 to ℘.
            if exp.is_zero() {
                return Self::ONE;
            }
            // Zero base, complex exponent w: 0^w = e^(w·ln 0) — magnitude by the sign of Re(w) (Circle components are plain two's complement, so the raw sign test is the right one). Re > 0 → 0, Re < 0 → ∞, Re = 0 (pure imaginary) → oscillates → ℘.
            if self.is_zero() {
                if exp.is_normal() {
                    if exp.real > F::zero() {
                        return Self::ZERO;
                    }
                    if exp.real < F::zero() {
                        return Self::INFINITY;
                    }
                }
                let prefix: F = VANISHED_POWER.prefix.sa();
                return Self {
                    real: prefix,
                    imaginary: prefix,
                    exponent: Self::ambiguous_exponent(),
                };
            }
            // Escaped base with a truly-complex exponent w = a+bi: the result angle contains b·ln|z| with ln|z| unknowable → ℘ regardless of a. (b = 0 was rerouted above.)
            if self.exploded() {
                let prefix: F = TRANSFINITE_POWER.prefix.sa();
                return Self {
                    real: prefix,
                    imaginary: prefix,
                    exponent: Self::ambiguous_exponent(),
                };
            }
            if self.vanished() {
                let prefix: F = VANISHED_POWER.prefix.sa();
                return Self {
                    real: prefix,
                    imaginary: prefix,
                    exponent: Self::ambiguous_exponent(),
                };
            }
            // Infinite base (single point, no angle to lose): magnitude by sign of Re(w).
            if self.is_infinite() && exp.is_normal() {
                if exp.real > F::zero() {
                    return Self::INFINITY;
                }
                if exp.real < F::zero() {
                    return Self::ZERO;
                }
            }
            // Normal (or ∞ with Re(w) = 0) base, non-normal exponent: transfinite exponents (exploded/∞) → ℘^⬆; vanished exponent → ℘^⬇ (was a single ℘^⬇ catch-all that mislabeled the transfinite cases).
            let prefix: F = if exp.vanished() {
                POWER_VANISHED.prefix.sa()
            } else {
                POWER_TRANSFINITE.prefix.sa()
            };
            return Self {
                real: prefix,
                imaginary: prefix,
                exponent: Self::ambiguous_exponent(),
            };
        }

        let ln_z = self.ln();
        let w_ln_z = exp * ln_z;
        w_ln_z.exp()
    }

    /// Computes the logarithm of a complex number with a complex base.
    ///
    /// Implements log_b(z) (logarithm of complex z with complex base b) using: log_b(z) = ln(z) / ln(b)
    ///
    /// # Special Cases:
    /// - Undefined or escaped values return appropriate undefined states
    /// - Exploded or vanished values return appropriate undefined states
    /// - log_b(0) returns ZERO_LOG undefined state
    /// - log_0(z) returns LOG_ZERO undefined state
    ///
    /// # Parameters:
    /// - `self`: The complex number to take the logarithm of
    /// - `base`: The complex base of the logarithm
    ///
    /// # Returns:
    /// - A complex number representing log_b(z)
    pub(crate) fn circle_logarithm_circle(&self, base: &Self) -> Self {
        if !self.is_normal() || !base.is_normal() {
            if self.is_undefined() {
                return *self;
            }
            if base.is_undefined() {
                return *base;
            }
            if self.is_zero() {
                let prefix: F = NEGLIGIBLE_LOG.prefix.sa();
                return Self {
                    real: prefix,
                    imaginary: prefix,
                    exponent: Self::ambiguous_exponent(),
                };
            }

            if base.is_zero() {
                let prefix: F = LOG_NEGLIGIBLE.prefix.sa();
                return Self {
                    real: prefix,
                    imaginary: prefix,
                    exponent: Self::ambiguous_exponent(),
                };
            }
            if self.exploded() {
                let prefix: F = TRANSFINITE_LOG.prefix.sa();
                return Self {
                    real: prefix,
                    imaginary: prefix,
                    exponent: Self::ambiguous_exponent(),
                };
            }
            if self.vanished() {
                let prefix: F = NEGLIGIBLE_LOG.prefix.sa();
                return Self {
                    real: prefix,
                    imaginary: prefix,
                    exponent: Self::ambiguous_exponent(),
                };
            }
            if base.exploded() {
                let prefix: F = LOG_TRANSFINITE.prefix.sa();
                return Self {
                    real: prefix,
                    imaginary: prefix,
                    exponent: Self::ambiguous_exponent(),
                };
            }
            if base.vanished() {
                let prefix: F = LOG_NEGLIGIBLE.prefix.sa();
                return Self {
                    real: prefix,
                    imaginary: prefix,
                    exponent: Self::ambiguous_exponent(),
                };
            }
        }

        let ln_z = self.ln();
        let ln_base = base.ln();

        ln_z / ln_base
    }
}