Skip to content

RuiNelson/SwiftEngineeringNumberFormatter

Repository files navigation

SwiftEngineeringNumberFormatter

Swift 6.0+ Platform Swift Package Manager License

A powerful and flexible Swift library for formatting numbers using engineering notation with SI metric prefixes. Supports all multiples of 3 SI metric prefixes from quecto (10⁻³⁰) to quetta (10³⁰).

Features

  • Complete SI Prefix Support: All 20 standard metric prefixes
  • High Precision: Full Decimal type support for exact arithmetic
  • Thread Safe: Sendable conformance for concurrent environments
  • Locale Aware: Respects decimal separators and number formatting rules
  • Highly Configurable: Fraction digits, spacing, micro symbol options
  • Swift 6 Ready: Uses modern Swift Testing framework
  • Zero Dependencies: Lightweight with no external dependencies

Supported Prefixes

Prefix Symbol Factor Example
quetta Q 10³⁰ 1Q = 1,000,000,000,000,000,000,000,000,000,000
ronna R 10²⁷ 1R = 1,000,000,000,000,000,000,000,000,000
yotta Y 10²⁴ 1Y = 1,000,000,000,000,000,000,000,000
zetta Z 10²¹ 1Z = 1,000,000,000,000,000,000,000
exa E 10¹⁸ 1E = 1,000,000,000,000,000,000
peta P 10¹⁵ 1P = 1,000,000,000,000,000
tera T 10¹² 1T = 1,000,000,000,000
giga G 10⁹ 1G = 1,000,000,000
mega M 10⁶ 1M = 1,000,000
kilo k 10³ 1k = 1,000
10⁰ 1 = 1
milli m 10⁻³ 1m = 0.001
micro µ/u 10⁻⁶ = 0.000001
nano n 10⁻⁹ 1n = 0.000000001
pico p 10⁻¹² 1p = 0.000000000001
femto f 10⁻¹⁵ 1f = 0.000000000000001
atto a 10⁻¹⁸ 1a = 0.000000000000000001
zepto z 10⁻²¹ 1z = 0.000000000000000000001
yocto y 10⁻²⁴ 1y = 0.000000000000000000000001
ronto r 10⁻²⁷ 1r = 0.000000000000000000000000001
quecto q 10⁻³⁰ 1q = 0.000000000000000000000000000001

Quick Start

Basic Usage with Extensions

The simplest way to get started is using the convenience extensions:

import SwiftEngineeringNumberFormatter

// Double conversions
let value = Double(engineeringNotation: "2.2k")  // Optional(2200.0)
let formatted = (1500.0).engineering              // "1.5k"

// Decimal conversions (high precision)
let decimal = Decimal(engineeringNotation: "333n") // Optional(0.000000333)
let precision = decimal!.engineering                // "333n"

Formatter Instance

For more control, create a formatter instance:

let formatter = EngineeringNumberFormatter()

// Double formatting
let result1 = formatter.string(1_000_000.0)        // "1M"
let parsed1 = formatter.double("2.5G")             // Optional(2500000000.0)

// Decimal formatting (recommended for precision)
let result2 = formatter.string(decimal: Decimal(-1_000_000))  // "-1M"
let parsed2 = formatter.decimal("10p")             // Optional(0.00000000001)

Advanced Configuration

Customize the formatter to match your requirements:

let formatter = EngineeringNumberFormatter(
    minimumFractionDigits: 1,     // Always show at least 1 decimal place
    maximumFractionDigits: 3,     // Limit to 3 decimal places
    locale: Locale(identifier: "de_DE"),  // German locale (comma separator)
    useGreekMu: false,            // Use 'u' instead of 'µ' for micro
    addSpace: true               // Add space between number and prefix
)

let result = formatter.string(2.222222e-6)  // "2,222 u" (German formatting)

Precision Matters

When working with high-precision calculations, use Decimal to avoid floating-point arithmetic issues:

let formatter = EngineeringNumberFormatter()

// Double precision limitations
let doubleSum = formatter.double("0.2")! + formatter.double("100m")!
// doubleSum != 0.3 (floating point precision issues)

// Decimal precision advantage
let decimalSum = formatter.decimal("0.2")! + formatter.decimal("100m")!
// decimalSum == 0.3 (exact decimal arithmetic)

// High precision example
let highPrecision = formatter.decimal("1M")! + formatter.decimal("1f")!
// Exactly: 1000000.000000000000001

Error Handling

The library gracefully handles invalid inputs:

let formatter = EngineeringNumberFormatter()

// These return nil for invalid inputs
formatter.double("")           // nil
formatter.double("invalid")    // nil  
formatter.double("1.2.3k")     // nil
formatter.decimal("µ")         // nil

Installation

Swift Package Manager

Add to your Package.swift:

dependencies: [
    .package(url: "https://github.com/RuiCarneiro/SwiftEngineeringNumberFormatter", from: "3.0.0")
]

Add to your target dependencies:

.target(
    name: "YourTarget",
    dependencies: ["SwiftEngineeringNumberFormatter"]
)

Xcode

  1. File → Add Package Dependencies
  2. Enter: https://github.com/RuiCarneiro/SwiftEngineeringNumberFormatter
  3. Select version and add to your target

Requirements

  • Swift 6.0+
  • iOS 13.0+ / macOS 10.15+ / watchOS 6.0+ / tvOS 13.0+
  • Linux (Swift Package Manager)

Thread Safety

EngineeringNumberFormatter is marked as Sendable and is safe to use across multiple threads concurrently.

Performance

The library is optimized for performance with:

  • Efficient string parsing algorithms
  • Minimal memory allocations
  • Built-in caching for number formatters
  • Comprehensive test suite including performance benchmarks

Testing

The project uses Swift Testing framework (Swift 6.0+):

swift test                    # Run all tests
swift build                   # Build the package

Documentation

Generate documentation using Swift-DocC:

swift package generate-documentation

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

Licensed under the Apache License, Version 2.0. See LICENSE for details.

Copyright

© 2024 Rui Nelson


About

Number formatter using the engineering notation for Swift

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages