arithmetic

Arithmetic capability traits and checked analytic operations for LunaFlow numeric types, with default real-valued instances.

math
arithmetic
elementary-functions
moon add Luna-Flow/arithmetic@0.5.0
Download zip
Author
Version
0.5.0
License
Apache-2.0
Last updated
25 days ago
Downloads
490
README

#Arithmetic

Arithmetic capability traits and checked or contextual numeric boundaries for Luna Flow projects.

#v0.5.0 - Contextual Capability Expansion

This release expands the contextual capability boundary built in 0.3.0 and the certification-failure vocabulary added in 0.4.0. The new traits cover integer embedding, adjacent representable values, context-dependent constants, and context-dependent hyperbolic functions without bundling unrelated numeric requirements.

For earlier release notes and repository history, see CHANGELOG.md.

#Release Notes

  • IntegralContextual embeds a MoonBit Int under an explicit context and returns conversion diagnostics.
  • AdjacentContextual exposes next-plus, next-minus, and next-toward operations while preserving signed-zero and infinity boundaries.
  • ConstantsContextual and HyperbolicContextual define context-faithful outcome surfaces for numeric backends that can report meaningful diagnostics.
  • Proof-backed constant implementations can preserve target-rounding failures through ArithmeticErrorKind::CertificationFailure.

#Package Positioning

  • luna-generic expresses algebraic structure such as Ring, Field, and Num.
  • arithmetic expresses analytic functions, checked operations, contextual outcomes, and enclosure-style relations.
  • The package describes small capabilities rather than declaring a bundled “real number” abstraction.
  • Concrete numeric packages should implement only the traits whose semantics they can support faithfully.

#Capability Layers

#Unchecked Elementary Traits

  • Sqrt, Cbrt, Radical
  • Exponential, Logarithmic, Power
  • Trigonometric, InverseTrigonometric
  • Hyperbolic, InverseHyperbolic
  • Constants

These traits preserve direct backend behavior and return Self.

#Checked Traits

  • SqrtChecked, DivChecked, CompareChecked
  • PowNatChecked, PowIntChecked, ParseChecked

Checked traits return Result[..., ArithmeticError] and use ArithmeticContext where the operation needs an explicit context. ArithmeticError can also carry a CertificationFailureDetail when a proof-backed backend cannot certify a result at the requested target.

#Contextual Outcome Traits

  • AddContextual, SubContextual, MulContextual, DivContextual
  • AbsContextual, SqrtContextual, ExpContextual
  • IntegralContextual, AdjacentContextual
  • ConstantsContextual, HyperbolicContextual
  • NumericFormatContextual

Contextual operations return ArithmeticOutcome[Self] inside Result, keeping the computed value and diagnostic flags together as immutable data.

#Enclosure Relations

  • Contains, Overlaps
  • DefinitelyLt, DefinitelyLe, MaybeEq

These traits model containment and definite or possible relations without pretending enclosure values form a scalar total order.

#Context Contract

  • ArithmeticContext::new clamps precision to at least 1.
  • If both exponent limits are present, e_min must not exceed e_max.
  • The decimal presets use precisions 7, 16, and 34 with their matching exponent ranges and clamping enabled.
  • ArithmeticDiagnostics::combine merges flags with logical OR, so callers can aggregate a sequence of outcomes explicitly.

The built-in Float and Double contextual implementations do not emulate arbitrary decimal precision, directed rounding, exponent clamping, or general IEEE status-flag detection. Contextual division and square root delegate validation to their checked counterparts. Integer embedding reports inexact/rounded when conversion to Float loses information. Adjacent operations use the fixed IEEE binary format and treat selecting the neighboring value as exact. Float and Double intentionally do not implement ConstantsContextual or HyperbolicContextual, because their native functions cannot honor arbitrary contexts or report complete diagnostics.

#Installation

moon add Luna-Flow/arithmetic@0.5.0 moon add Luna-Flow/luna-generic@0.3.1

Use explicit Luna Flow aliases in moon.pkg:

import {
"Luna-Flow/luna-generic" @lf_alg,
"Luna-Flow/arithmetic" @lf_arith,
}

#Quick Start

using @lf_alg { trait Add, trait Mul }
using @lf_arith { trait Sqrt }

fn hypot2[T : Add + Mul + Sqrt](x : T, y : T) -> T {
Sqrt::sqrt(x * x + y * y)
}

let context = @lf_arith.ArithmeticContext::decimal64()
let outcome = @lf_arith.DivContextual::div_contextual(10.0, 4.0, context).unwrap()
inspect(outcome.value, content="2.5")
inspect(outcome.diagnostics.inexact, content="false")

#Documentation

#Changelog

Historical release notes live in CHANGELOG.md. This README stays focused on the current package baseline and entry points.

#Development

Useful local commands:

moon fmt moon info moon check --target all moon test

#Release Checklist

  1. Bump moon.mod to the intended release version.
  2. Update README.md, all three localized documentation trees, and CHANGELOG.md.
  3. Run moon fmt --check, moon info, moon build --target all, moon check --target all --frozen, and the default, JavaScript, and native test suites.
  4. Trigger publish-package with the exact moon.mod version. The workflow repeats the checks, publishes to mooncakes, and creates the matching GitHub release.

The workflow publishes the version declared in moon.mod to mooncakes; it does not accept a mismatched release version.

#
AbsContextual

pub(open) trait AbsContextual {
fn abs_contextual(Self, ArithmeticContext) -> Result[ArithmeticOutcome[Self], ArithmeticError]
}

#
AddContextual

pub(open) trait AddContextual {
fn add_contextual(Self, Self, ArithmeticContext) -> Result[ArithmeticOutcome[Self], ArithmeticError]
}

#
AdjacentContextual

pub(open) trait AdjacentContextual {
fn next_plus_contextual(Self, ArithmeticContext) -> Result[ArithmeticOutcome[Self], ArithmeticError]
fn next_minus_contextual(Self, ArithmeticContext) -> Result[ArithmeticOutcome[Self], ArithmeticError]
fn next_toward_contextual(Self, Self, ArithmeticContext) -> Result[ArithmeticOutcome[Self], ArithmeticError]
}

#
Cbrt

pub(open) trait Cbrt {
fn cbrt(Self) -> Self
}

impl Cbrt for Float
impl Cbrt for Double

#
CompareChecked

pub(open) trait CompareChecked {
fn compare_checked(Self, Self) -> Result[Int, ArithmeticError]
}

#
Constants

pub(open) trait Constants {
fn pi() -> Self
fn tau() -> Self
fn e() -> Self
}

impl Constants for Float
impl Constants for Double

#
ConstantsContextual

pub(open) trait ConstantsContextual {
fn pi_contextual(ArithmeticContext) -> Result[ArithmeticOutcome[Self], ArithmeticError]
fn tau_contextual(ArithmeticContext) -> Result[ArithmeticOutcome[Self], ArithmeticError]
fn e_contextual(ArithmeticContext) -> Result[ArithmeticOutcome[Self], ArithmeticError]
}

#
Contains

pub(open) trait Contains {
fn contains(Self, Self) -> Bool
}

#
DefinitelyLe

pub(open) trait DefinitelyLe {
fn definitely_le(Self, Self) -> Bool
}

#
DefinitelyLt

pub(open) trait DefinitelyLt {
fn definitely_lt(Self, Self) -> Bool
}

#
DivChecked

pub(open) trait DivChecked {
fn div_checked(Self, Self, ArithmeticContext) -> Result[Self, ArithmeticError]
}

impl DivChecked for Float

#
DivContextual

pub(open) trait DivContextual {
fn div_contextual(Self, Self, ArithmeticContext) -> Result[ArithmeticOutcome[Self], ArithmeticError]
}

#
ExpContextual

pub(open) trait ExpContextual {
fn exp_contextual(Self, ArithmeticContext) -> Result[ArithmeticOutcome[Self], ArithmeticError]
}

#
Exponential

pub(open) trait Exponential {
fn exp(Self) -> Self
fn exp2(Self) -> Self
}

#
Hyperbolic

pub(open) trait Hyperbolic {
fn sinh(Self) -> Self
fn cosh(Self) -> Self
fn tanh(Self) -> Self
}

impl Hyperbolic for Float

#
HyperbolicContextual

pub(open) trait HyperbolicContextual {
fn sinh_contextual(Self, ArithmeticContext) -> Result[ArithmeticOutcome[Self], ArithmeticError]
fn cosh_contextual(Self, ArithmeticContext) -> Result[ArithmeticOutcome[Self], ArithmeticError]
fn tanh_contextual(Self, ArithmeticContext) -> Result[ArithmeticOutcome[Self], ArithmeticError]
}

#
IntegralContextual

pub(open) trait IntegralContextual {
fn from_int_contextual(Int, ArithmeticContext) -> Result[ArithmeticOutcome[Self], ArithmeticError]
}

#
InverseHyperbolic

pub(open) trait InverseHyperbolic {
fn asinh(Self) -> Self
fn acosh(Self) -> Self
fn atanh(Self) -> Self
}

#
InverseTrigonometric

pub(open) trait InverseTrigonometric {
fn asin(Self) -> Self
fn acos(Self) -> Self
fn atan(Self) -> Self
fn atan2(Self, Self) -> Self
}

#
Logarithmic

pub(open) trait Logarithmic {
fn ln(Self) -> Self
fn log2(Self) -> Self
fn log10(Self) -> Self
}

#
MaybeEq

pub(open) trait MaybeEq {
fn maybe_eq(Self, Self) -> Bool
}

#
MulContextual

pub(open) trait MulContextual {
fn mul_contextual(Self, Self, ArithmeticContext) -> Result[ArithmeticOutcome[Self], ArithmeticError]
}

#
NumericFormatContextual

pub(open) trait NumericFormatContextual {
fn zero_contextual(ArithmeticContext) -> Self
fn one_contextual(ArithmeticContext) -> Self
fn epsilon_contextual(ArithmeticContext) -> Self
fn min_normal_contextual(ArithmeticContext) -> Self
fn max_finite_contextual(ArithmeticContext) -> Self
fn classify_contextual(Self) -> FpClass
}

#
Overlaps

pub(open) trait Overlaps {
fn overlaps(Self, Self) -> Bool
}

#
ParseChecked

pub(open) trait ParseChecked {
fn parse_checked(String, ArithmeticContext) -> Result[Self, ArithmeticError]
}

#
PowIntChecked

pub(open) trait PowIntChecked {
fn pow_int_checked(Self, Int, ArithmeticContext) -> Result[Self, ArithmeticError]
}

#
PowNatChecked

pub(open) trait PowNatChecked {
fn pow_nat_checked(Self, UInt, ArithmeticContext) -> Result[Self, ArithmeticError]
}

#
Power

pub(open) trait Power {
fn pow(Self, Self) -> Self
}

impl Power for Int
impl Power for Int16
impl Power for Int64
impl Power for UInt
impl Power for UInt16
impl Power for UInt64
impl Power for Float
impl Power for Double

#
Radical

pub(open) trait Radical : Sqrt + Cbrt {
}

impl Radical for Float
impl Radical for Double

#
Sqrt

pub(open) trait Sqrt {
fn sqrt(Self) -> Self
}

impl Sqrt for Float
impl Sqrt for Double

#
SqrtChecked

pub(open) trait SqrtChecked {
fn sqrt_checked(Self, ArithmeticContext) -> Result[Self, ArithmeticError]
}

#
SqrtContextual

pub(open) trait SqrtContextual {
fn sqrt_contextual(Self, ArithmeticContext) -> Result[ArithmeticOutcome[Self], ArithmeticError]
}

#
SubContextual

pub(open) trait SubContextual {
fn sub_contextual(Self, Self, ArithmeticContext) -> Result[ArithmeticOutcome[Self], ArithmeticError]
}

#
Trigonometric

pub(open) trait Trigonometric {
fn sin(Self) -> Self
fn cos(Self) -> Self
fn tan(Self) -> Self
}

#
ArithmeticContext

pub struct ArithmeticContext {
precision : Int
rounding : RoundingMode
e_min : Int?
e_max : Int?
clamp : Bool
} derive(Eq)

#
ArithmeticContext::decimal128

#
ArithmeticContext::decimal32

#
ArithmeticContext::decimal64

#
ArithmeticContext::new

fn ArithmeticContext::new(precision : Int, rounding? : RoundingMode, e_min? : Int, e_max? : Int, clamp? : Bool) -> ArithmeticContext

#
ArithmeticDiagnostics

pub struct ArithmeticDiagnostics {
inexact : Bool
rounded : Bool
overflow : Bool
underflow : Bool
subnormal : Bool
clamped : Bool
} derive(Eq,
Debug
)

#
ArithmeticDiagnostics::combine

#
ArithmeticDiagnostics::empty

#
ArithmeticDiagnostics::new

fn ArithmeticDiagnostics::new(inexact? : Bool, rounded? : Bool, overflow? : Bool, underflow? : Bool, subnormal? : Bool, clamped? : Bool) -> ArithmeticDiagnostics

#
ArithmeticError

pub struct ArithmeticError {
kind : ArithmeticErrorKind
message : String
} derive(Eq)

#
ArithmeticError::certification_failure

fn ArithmeticError::certification_failure(detail : CertificationFailureDetail) -> ArithmeticError

#
ArithmeticError::certification_failure_detail

fn ArithmeticError::certification_failure_detail(self : ArithmeticError) -> CertificationFailureDetail?

#
ArithmeticError::division_by_zero

fn ArithmeticError::division_by_zero(message : String) -> ArithmeticError

#
ArithmeticError::domain_error

fn ArithmeticError::domain_error(message : String) -> ArithmeticError

#
ArithmeticError::format_error

fn ArithmeticError::format_error(message : String) -> ArithmeticError

#
ArithmeticError::is_certification_failure

fn ArithmeticError::is_certification_failure(self : ArithmeticError) -> Bool

#
ArithmeticError::is_division_by_zero

fn ArithmeticError::is_division_by_zero(self : ArithmeticError) -> Bool

#
ArithmeticError::is_domain_error

fn ArithmeticError::is_domain_error(self : ArithmeticError) -> Bool

#
ArithmeticError::is_format_error

fn ArithmeticError::is_format_error(self : ArithmeticError) -> Bool

#
ArithmeticError::is_parse_error

fn ArithmeticError::is_parse_error(self : ArithmeticError) -> Bool

#
ArithmeticError::is_unordered_comparison

fn ArithmeticError::is_unordered_comparison(self : ArithmeticError) -> Bool

#
ArithmeticError::is_unsupported

fn ArithmeticError::is_unsupported(self : ArithmeticError) -> Bool

#
ArithmeticError::parse_error

fn ArithmeticError::parse_error(message : String) -> ArithmeticError

#
ArithmeticError::unordered_comparison

fn ArithmeticError::unordered_comparison(message : String) -> ArithmeticError

#
ArithmeticError::unsupported

fn ArithmeticError::unsupported(message : String) -> ArithmeticError

#
ArithmeticErrorKind

pub enum ArithmeticErrorKind {
DivisionByZero
ParseError
DomainError
FormatError
UnsupportedOperation
UnorderedComparison
CertificationFailure(CertificationFailureDetail)
} derive(Eq)

#
ArithmeticOutcome

pub struct ArithmeticOutcome[T] {
value : T
diagnostics : ArithmeticDiagnostics
} derive(Eq,
Debug
)

#
ArithmeticOutcome::exact

fn[T] ArithmeticOutcome::exact(value : T) -> ArithmeticOutcome[T]

#
ArithmeticOutcome::with_diagnostics

fn[T] ArithmeticOutcome::with_diagnostics(value : T, diagnostics : ArithmeticDiagnostics) -> ArithmeticOutcome[T]

#
CertificationFailureDetail

pub struct CertificationFailureDetail {
operation : String
stage : CertificationStage
reason : CertificationFailureReason
target_precision : Int
work_precision : Int
refinements : Int
} derive(Eq)

#
CertificationFailureDetail::new

fn CertificationFailureDetail::new(operation : String, stage : CertificationStage, reason : CertificationFailureReason, target_precision : Int, work_precision : Int, refinements : Int) -> CertificationFailureDetail

#
CertificationFailureDetail::operation

#
CertificationFailureDetail::reason

#
CertificationFailureDetail::refinements

#
CertificationFailureDetail::stage

#
CertificationFailureDetail::target_precision

fn CertificationFailureDetail::target_precision(self : CertificationFailureDetail) -> Int

#
CertificationFailureDetail::work_precision

fn CertificationFailureDetail::work_precision(self : CertificationFailureDetail) -> Int

#
CertificationFailureReason

pub(all) enum CertificationFailureReason {
RangeNotCertified
SeriesDidNotConverge
InvalidEnclosure
ResourceLimit
RefinementBudgetExhausted
} derive(Eq)

#
CertificationStage

pub(all) enum CertificationStage {
RangeReduction
SeriesEvaluation
EnclosurePropagation
TargetRounding
} derive(Eq)

#
FpClass

pub(all) enum FpClass {
Finite
Infinity
NaN
} derive(Eq,
Debug
)

#
RoundingMode

pub(all) enum RoundingMode {
ToNearestEven
TowardZero
TowardPositive
TowardNegative
AwayFromZero
} derive(Eq)