A sophisticated runtime number system for building interpreters, dynamic languages, and computer algebra systems that need automatic type promotion and exact arithmetic with optimal performance.
DAL (Dynamic Arithmetic Logic) provides automatic number type promotion and runtime arithmetic operations that adapt to the precision requirements of your calculations. It seamlessly handles operations between different number types and automatically promotes to higher precision when needed.
- ๐ Automatic Type Promotion: Operations automatically promote to higher precision types when needed
- ๐ฏ Exact Arithmetic: Maintains mathematical precision through rational and arbitrary precision types
- โก Performance Optimized: Uses the most efficient representation for each value
- ๐ Cross-Platform: Works on JVM, JavaScript, and Native platforms
- ๐ง Runtime Flexible: Perfect for interpreters, calculators, and dynamic languages
- ๐ Mathematical Types: Supports complex numbers, quaternions, and arbitrary precision
DAL manages a sophisticated type hierarchy with automatic promotion:
Int โโโ Long โโโ BigInt โโโ Double โโโ BigDecimal
โ โ โ โ
โ โ โ โ
โโโโ Rational โโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโ ComplexRational โโโ ComplexBigDecimal
โ โ
โ โโโโ ComplexDouble
โ
โโโโ QuaternionRational โโโ QuaternionBigDecimal
โ
โโโโ QuaternionDouble
1 + 2 // โ 3 (Int)
1 + 2.5 // โ 3.5 (Double)
1 / 3 // โ 1/3 (Rational) - Exact!
1.5 + 2/3 // โ 2.1666... (Double)
BigInt("999") * BigInt("999") // โ BigInt (as needed)
import io.github.edadma.dal._
// Use PrecisionDAL for exact arithmetic
val result1 = PrecisionDAL.compute("+", 1, 2) // 3 (Int)
val result2 = PrecisionDAL.compute("/", 1, 3) // 1/3 (Rational)
val result3 = PrecisionDAL.compute("+", result2, result2) // 2/3 (Rational)
// Automatic promotion on overflow
val big1 = PrecisionDAL.compute("*", Long.MaxValue, 2) // โ BigInt
val exact = PrecisionDAL.compute("/", 22, 7) // โ 22/7 (Rational)
// Boolean operations
val comparison = PrecisionDAL.relate("=", Rational(1,2), 0.5) // true
val ordering = PrecisionDAL.relate("<", 1, 2) // true
import io.github.edadma.dal._
class Calculator {
def evaluate(left: Any, operator: String, right: Any): Number = {
val leftNum = convertToNumber(left)
val rightNum = convertToNumber(right)
// DAL handles all type conversions and promotions automatically
PrecisionDAL.compute(Symbol(operator), leftNum, rightNum)
}
def convertToNumber(value: Any): Number = value match {
case i: Int => i
case d: Double => d
case s: String if s.contains('/') => Rational(s) // "1/3" โ Rational
case s: String => BigDecimal(s) // High precision
case n: Number => n
}
}
val calc = Calculator()
calc.evaluate("1/3", "+", "1/6") // โ 1/2 (Rational)
calc.evaluate(Long.MaxValue, "*", 2) // โ BigInt (auto-promotion)
calc.evaluate("0.1", "+", "0.2") // โ 0.3 (BigDecimal, exact)
DAL provides different implementations optimized for different use cases:
Fast arithmetic with lossy division
- Division of integers returns integers or doubles
- Optimized for performance
- Good for numerical computing
BasicDAL.compute("/", 1, 3) // โ 0.333... (Double)
BasicDAL.compute("+", 1, 2) // โ 3 (Int)
Exact arithmetic with rational numbers
- Division of integers creates exact rational numbers
- Maintains mathematical precision
- Perfect for computer algebra systems
PrecisionDAL.compute("/", 1, 3) // โ 1/3 (Rational) - Exact!
PrecisionDAL.compute("^", Rational(2,3), 2) // โ 4/9 (Rational)
Complex number support with exact arithmetic
- Includes complex numbers in the type hierarchy
- Exact complex rational arithmetic
- For mathematical and scientific computing
ComplexDAL.compute("+", ComplexDouble(1,2), ComplexDouble(3,4)) // โ 4+6i
ComplexDAL.compute("*", Rational(1,2), ComplexRational(1,1,2,1)) // Mixed types work!
Full quaternion support
- 4D number system for 3D rotations
- Includes all complex number capabilities
- For graphics, robotics, and advanced mathematics
QuaternionDAL.compute("*", QuaternionDouble.i, QuaternionDouble.j) // โ k
QuaternionDAL.compute("+", QuaternionRational(1,0,0,0), QuaternionInt(0,1,0,0))
import io.github.edadma.numbers.BigDecimalMath
// Use custom precision context
implicit val customPrecision = new BigDecimalMath(50) // 50 decimal places
val result = PrecisionDAL.compute("/", BigDecimal("1"), BigDecimal("3"))
// โ 0.33333333333333333333333333333333333333333333333333 (50 digits)
import io.github.edadma.dal.PrecisionNumberIsFractional._
// Works with Scala collections automatically
val numbers = List(1, Rational(1,2), BigDecimal("0.25"))
val sum = numbers.sum // โ 1.75 (BigDecimal)
val rationals = List(Rational(1,2), Rational(1,3), Rational(1,6))
val total = rationals.sum // โ 1 (Rational) - Exact!
// Automatic promotion prevents overflow
val big = PrecisionDAL.compute("*", Int.MaxValue, Int.MaxValue) // โ BigInt
// Division by zero is handled gracefully
try {
PrecisionDAL.compute("/", 1, 0)
} catch {
case e: RuntimeException => println("Division by zero!")
}
// Complex operations maintain precision
val complex = PrecisionDAL.compute("/", ComplexRational(1,1,1,1), ComplexRational(2,1,0,0))
// โ Exact complex rational result
Type | Relative Speed | Memory Usage | Use Case |
---|---|---|---|
Int |
1x (baseline) | 4 bytes | Small integers |
Long |
1x | 8 bytes | Large integers |
Double |
1x | 8 bytes | Approximate decimals |
BigInt |
10-50x slower | 24+ bytes | Arbitrary integers |
Rational |
20-100x slower | 48+ bytes | Exact fractions |
BigDecimal |
50-200x slower | 40+ bytes | Arbitrary precision |
DAL automatically chooses the most efficient type:
// Stays in fast types when possible
PrecisionDAL.compute("+", 1, 2) // โ Int (fastest)
PrecisionDAL.compute("*", 1000, 1000) // โ Int (fits)
PrecisionDAL.compute("*", 100000, 100000) // โ Long (promoted)
PrecisionDAL.compute("*", Long.MaxValue, 2) // โ BigInt (necessary)
// Uses exact types for exact operations
PrecisionDAL.compute("/", 1, 3) // โ Rational (exact)
PrecisionDAL.compute("+", Rational(1,3), Rational(1,6)) // โ Rational(1,2)
import io.github.edadma.dal._
object Calculator extends App {
val operators = Set("+", "-", "*", "/", "^", "=", "<", ">")
def evaluateExpression(input: String): String = {
val tokens = input.split("\\s+")
if (tokens.length != 3) return "Error: Expected 'number operator number'"
val left = parseNumber(tokens(0))
val op = tokens(1)
val right = parseNumber(tokens(2))
if (operators.contains(op)) {
if (Set("=", "<", ">").contains(op)) {
PrecisionDAL.relate(Symbol(op), left, right).toString
} else {
PrecisionDAL.compute(Symbol(op), left, right).toString
}
} else {
"Error: Unknown operator"
}
}
def parseNumber(s: String): Number = {
if (s.contains('/')) Rational(s)
else if (s.contains('.')) BigDecimal(s)
else if (s.length > 9) BigInt(s)
else s.toInt
}
// REPL loop
println("DAL Calculator - Enter expressions like '1/3 + 1/6'")
var continue = true
while (continue) {
print("> ")
val input = scala.io.StdIn.readLine()
if (input == "quit") {
continue = false
} else {
println(evaluateExpression(input))
}
}
}
// Example session:
// > 1/3 + 1/6
// 1/2
// > 1000000000000 * 1000000000000
// 1000000000000000000000000
// > 1 / 3
// 1/3
// > 0.1 + 0.2
// 0.3
import io.github.edadma.dal._
trait Value
case class NumberValue(n: Number) extends Value
case class BooleanValue(b: Boolean) extends Value
class Interpreter {
def evaluateBinaryOp(left: Value, op: String, right: Value): Value = {
(left, right) match {
case (NumberValue(l), NumberValue(r)) =>
if (Set("=", "!=", "<", ">", "<=", ">=").contains(op)) {
BooleanValue(PrecisionDAL.relate(Symbol(op), l, r))
} else {
NumberValue(PrecisionDAL.compute(Symbol(op), l, r))
}
case _ => throw new RuntimeException("Type error")
}
}
// Automatic type promotion in action
def demo(): Unit = {
val a = NumberValue(1)
val b = NumberValue(Rational(1, 3))
val sum = evaluateBinaryOp(a, "+", b) // โ NumberValue(Rational(4,3))
val product = evaluateBinaryOp(a, "*", b) // โ NumberValue(Rational(1,3))
val comparison = evaluateBinaryOp(a, ">", b) // โ BooleanValue(true)
}
}
// Arithmetic operations
def compute(op: Symbol, left: Number, right: Number): Number
def compute(op: String, left: Number, right: Number): Number
// Comparison operations
def relate(op: Symbol, left: Number, right: Number): Boolean
def relate(op: String, left: Number, right: Number): Boolean
// Unary operations
def negate(n: Number): Number
Arithmetic: +
, -
, *
, /
, //
(float division), ^
(power), mod
, \
(integer division)
Comparison: =
, !=
, <
, >
, <=
, >=
Bitwise (integer types): and
, or
, xor
Special: div
(divisibility test), compare
(three-way comparison)
def toBigInt(a: Number): BigInt
def toRational(a: Number): Rational
def toBigDecimal(a: Number): BigDecimal
def numberType(n: Number): Type
def maybeDemote(n: Number): (Type, Number) // Optimize representation
def sqrtFunction(n: Any): Number // Square root with complex results
def absFunction(n: Any): Number // Absolute value
def floorFunction(n: Any): Number // Floor function
def ceilFunction(n: Any): Number // Ceiling function
def expFunction(n: Any): Number // Exponential
def lnFunction(n: Any): Number // Natural logarithm
def sinFunction(n: Any): Number // Sine
def cosFunction(n: Any): Number // Cosine
def tanFunction(n: Any): Number // Tangent
// ... and more trigonometric functions
DAL is built on the numbers library which provides:
Rational
: Exact rational arithmetic with BigInt numerator/denominatorComplexRational
,ComplexDouble
,ComplexBigDecimal
: Complex number typesQuaternionRational
,QuaternionDouble
,QuaternionBigDecimal
: Quaternion typesBigDecimalMath
: High-precision mathematical functions
libraryDependencies += "io.github.edadma" %%% "dal" % "0.1.10"
git clone https://github.com/edadma/dal.git
cd dal
sbt compile
sbt test
sbt "project dalJVM" compile
sbt "project dalJS" compile
sbt "project dalNative" compile
- ๐ง Programming Language Interpreters: Automatic type promotion for dynamic languages
- ๐งฎ Computer Algebra Systems: Exact symbolic computation with rationals
- ๐ฏ Calculators: High-precision arithmetic with automatic precision selection
- ๐ฌ Scientific Computing: Complex and quaternion arithmetic with exact rationals
- ๐ฐ Financial Systems: Exact decimal arithmetic without floating-point errors
- ๐ Data Analysis: Mixed-precision calculations with automatic optimization
// Scheme/Lisp interpreter numeric tower
def evaluateNumber(expr: Any): Number = expr match {
case i: Int => i
case s: String if s.contains('/') => Rational(s)
case s: String => BigDecimal(s)
}
// Computer algebra system
def simplify(expr: Expr): Expr = expr match {
case Add(Number(a), Number(b)) => Number(PrecisionDAL.compute("+", a, b))
case Multiply(Number(a), Number(b)) => Number(PrecisionDAL.compute("*", a, b))
// ... symbolic rules
}
// Financial calculations
def calculateCompoundInterest(principal: String, rate: String, time: Int): BigDecimal = {
val p = BigDecimal(principal)
val r = Rational(rate) // e.g., "5/100" for 5%
val amount = PrecisionDAL.compute("*", p, PrecisionDAL.compute("^",
PrecisionDAL.compute("+", 1, r), time))
amount.asInstanceOf[BigDecimal] // Exact result
}
- Choose the Right DAL: Use
BasicDAL
for speed,PrecisionDAL
for exactness - Input Type Matters: Start with the most efficient type (
Int
vsBigDecimal
) - Batch Operations: Multiple operations on same types are faster
- Avoid Unnecessary Precision: Don't use
BigDecimal
whenDouble
suffices
We welcome contributions! The DAL library is designed to be:
- Extensible: Easy to add new number types and operations
- Testable: Comprehensive test coverage for all type combinations
- Portable: Works across JVM, JavaScript, and Native platforms
This project is licensed under the ISC License - see the LICENSE file for details.