Skip to content

[Refactor] Migrate away from DecimalMath embedded dependency #588

@Nucs

Description

@Nucs

Overview

NumSharp currently embeds a copy of DecimalMath in src/NumSharp.Core/Utilities/DecimalEx.cs (~1000 lines). This provides transcendental math functions for decimal that .NET doesn't offer natively (Sqrt, Pow, Exp, Log, Sin, Cos, Tan, ATan2, etc.).

Problem

The embedded DecimalMath code cannot be optimized for our IL kernel generation pipeline:

  1. No inlining control - DecimalMath methods use their own [MethodImpl(OptimizeAndInline)] but this doesn't integrate with our ILKernelGenerator emit strategy
  2. Reflection overhead - ILKernelGenerator currently uses MethodInfo references to call DecimalMath methods, preventing true inlining
  3. Namespace pollution - The DecimalMath namespace is external; having our own implementation in NumSharp namespace is cleaner

Current Usage (4 call sites, 3 functions)

Location Function Purpose
Default.Reduction.Std.cs:277 Sqrt std for decimal arrays
Default.ATan2.cs:140 ATan2 atan2 for decimal scalars
ILKernelGenerator.cs:1060 Pow IL emit for decimal power
ILKernelGenerator.cs:1115 ATan2 IL emit for decimal atan2

Why .NET Doesn't Provide These

decimal is designed for financial calculations where exact representation matters. Transcendental functions (sqrt, sin, exp) produce irrational numbers that cannot be exactly represented - .NET's position is "use double for scientific math."

However, NumSharp supports all 12 dtypes including decimal, so we need these operations.

Proposed Solution

Implement NumSharp.Utilities.DecimalMath as an internal static class with:

  • Sqrt(decimal) - Babylonian method (current impl is fine)
  • Pow(decimal, decimal) - Exponentiation by squaring + exp/log for fractional
  • ATan2(decimal, decimal) - Quadrant-aware arctangent
  • Exp(decimal) - Taylor series
  • Log(decimal) - Natural logarithm
  • Constants: Pi, E, Ln10, Ln2

Benefits

  1. Kernel integration - Methods can use [MethodImpl(MethodImplOptions.AggressiveInlining)] and be directly emitted by ILKernelGenerator
  2. No external dependency - Fully self-contained
  3. Optimizable - We control the implementation and can tune for our use cases
  4. Cleaner namespace - NumSharp.Utilities.DecimalMath instead of external DecimalMath.DecimalEx

Implementation Notes

  • Start with the existing DecimalEx algorithms (MIT licensed, properly attributed)
  • Move to NumSharp.Utilities namespace
  • Mark as internal static class
  • Apply [MethodImpl(MethodImplOptions.AggressiveInlining)] where beneficial
  • Update ILKernelGenerator to reference the new internal methods
  • Remove the embedded DecimalMath copy

Non-Goals

  • Supporting all DecimalEx functions (we only need ~6)
  • Changing decimal behavior or precision
  • Adding new decimal operations beyond what's currently used

Related

  • ILKernelGenerator kernel emit pipeline
  • Decimal dtype support across all operations

Metadata

Metadata

Assignees

No one assigned

    Labels

    architectureCross-cutting structural changes affecting multiple componentscoreInternal engine: Shape, Storage, TensorEngine, iterators

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions