Skip to content

Instantly share code, notes, and snippets.

@bsneed
Created November 8, 2015 17:58
Show Gist options
  • Save bsneed/a7fee70c0406f203b6bb to your computer and use it in GitHub Desktop.
Save bsneed/a7fee70c0406f203b6bb to your computer and use it in GitHub Desktop.
Treat y0 NSDecimalNumber's like first class peeps instead of red-headed-step-children, in Swift.
//
// Decimal.swift
// Decimal
//
// Created by Brandon Sneed on 11/7/15.
// Copyright © 2015 theholygrail.io. All rights reserved.
//
import Foundation
public struct Decimal {
public let value: NSDecimalNumber
/// Create an instance initialized to zero.
public init() {
value = NSDecimalNumber.zero()
}
/// Create an instance initialized to `value`.
public init(_ value: NSDecimalNumber) {
self.value = value
}
public init(_ value: NSNumber) {
self.value = NSDecimalNumber(decimal: value.decimalValue)
}
public init(_ value: Float) {
self.value = NSDecimalNumber(float: value)
}
public init(_ value: Double) {
self.value = NSDecimalNumber(double: value)
}
public init(_ value: String) {
self.value = NSDecimalNumber(string: value)
}
}
extension Decimal: CustomStringConvertible {
/// A textual representation of `self`.
public var description: String {
return String(reflecting: value)
}
}
extension Decimal: CustomDebugStringConvertible {
/// A textual representation of `self`.
public var debugDescription: String {
return String(reflecting: value)
}
}
extension Decimal /*: FloatingPointType*/ { // It complains about _BitsType missing, no idea wtf that is.
/// The positive infinity.
public static var infinity: Decimal {
return Decimal(Double.infinity)
}
/// A quiet NaN.
public static var NaN: Decimal {
return Decimal(NSDecimalNumber.notANumber())
}
/// A quiet NaN.
public static var quietNaN: Decimal {
return NaN
}
/// `true` iff `self` is negative.
public var isSignMinus: Bool {
return (value as Double).isSignMinus
}
/// `true` iff `self` is normal (not zero, subnormal, infinity, or
/// NaN).
public var isNormal: Bool {
return (value as Double).isNormal
}
/// `true` iff `self` is zero, subnormal, or normal (not infinity
/// or NaN).
public var isFinite: Bool {
return (value as Double).isFinite
}
/// `true` iff `self` is +0.0 or -0.0.
public var isZero: Bool {
return (value as Double).isZero
}
/// `true` iff `self` is subnormal.
public var isSubnormal: Bool {
return (value as Double).isSubnormal
}
/// `true` iff `self` is infinity.
public var isInfinite: Bool {
return (value as Double).isInfinite
}
/// `true` iff `self` is NaN.
public var isNaN: Bool {
return (value as Double).isNaN
}
/// `true` iff `self` is a signaling NaN.
public var isSignaling: Bool {
return (value as Double).isSignaling
}
}
extension Decimal: Comparable, Equatable {
}
// MARK: Equatable
public func ==(lhs: Decimal, rhs: Decimal) -> Bool {
return lhs.value.compare(rhs.value) == .OrderedSame
}
// MARK: Comparable
public func <(lhs: Decimal, rhs: Decimal) -> Bool {
return lhs.value.compare(rhs.value) == .OrderedAscending
}
public func <=(lhs: Decimal, rhs: Decimal) -> Bool {
let result = lhs.value.compare(rhs.value)
if result == .OrderedAscending {
return true
} else if result == .OrderedSame {
return true
}
return false
}
public func >=(lhs: Decimal, rhs: Decimal) -> Bool {
let result = lhs.value.compare(rhs.value)
if result == .OrderedDescending {
return true
} else if result == .OrderedSame {
return true
}
return false
}
public func >(lhs: Decimal, rhs: Decimal) -> Bool {
return lhs.value.compare(rhs.value) == .OrderedDescending
}
extension Decimal: Hashable {
/// The hash value.
///
/// **Axiom:** `x == y` implies `x.hashValue == y.hashValue`.
///
/// - Note: The hash value is not guaranteed to be stable across
/// different invocations of the same program. Do not persist the
/// hash value across program runs.
public var hashValue: Int {
return value.hash
}
}
extension Decimal: IntegerLiteralConvertible {
public init(integerLiteral value: IntegerLiteralType) {
self.value = NSDecimalNumber(integer: value)
}
}
extension Decimal: AbsoluteValuable {
/// Returns the absolute value of `x`.
@warn_unused_result
public static func abs(x: Decimal) -> Decimal {
if x.value.compare(NSDecimalNumber.zero()) == .OrderedAscending {
// number is neg, multiply by -1
let negOne = NSDecimalNumber(mantissa: 1, exponent: 0, isNegative: true)
return Decimal(x.value.decimalNumberByMultiplyingBy(negOne, withBehavior: nil))
} else {
return x
}
}
}
extension Decimal {
public init(_ v: UInt8) {
value = NSDecimalNumber(unsignedChar: v)
}
public init(_ v: Int8) {
value = NSDecimalNumber(char: v)
}
public init(_ v: UInt16) {
value = NSDecimalNumber(unsignedShort: v)
}
public init(_ v: Int16) {
value = NSDecimalNumber(short: v)
}
public init(_ v: UInt32) {
value = NSDecimalNumber(unsignedInt: v)
}
public init(_ v: Int32) {
value = NSDecimalNumber(int: v)
}
public init(_ v: UInt64) {
value = NSDecimalNumber(unsignedLongLong: v)
}
public init(_ v: Int64) {
value = NSDecimalNumber(longLong: v)
}
public init(_ v: UInt) {
value = NSDecimalNumber(unsignedInteger: v)
}
public init(_ v: Int) {
value = NSDecimalNumber(integer: v)
}
}
// MARK: Addition operators
public func +(lhs: Decimal, rhs: Decimal) -> Decimal {
return Decimal(lhs.value.decimalNumberByAdding(rhs.value))
}
public prefix func ++(lhs: Decimal) -> Decimal {
return Decimal(lhs.value.decimalNumberByAdding(NSDecimalNumber.one()))
}
public postfix func ++(inout lhs: Decimal) -> Decimal {
lhs = Decimal(lhs.value.decimalNumberByAdding(NSDecimalNumber.one()))
return lhs
}
public func +=(inout lhs: Decimal, rhs: Decimal) -> Decimal {
lhs = Decimal(lhs.value.decimalNumberBySubtracting(rhs.value))
return lhs
}
public func +=(inout lhs: Decimal, rhs: Int) -> Decimal {
lhs = Decimal(lhs.value.decimalNumberByAdding(NSDecimalNumber(integer: rhs)))
return lhs
}
public func +=(inout lhs: Decimal, rhs: Double) -> Decimal {
lhs = Decimal(lhs.value.decimalNumberByAdding(NSDecimalNumber(double: rhs)))
return lhs
}
// MARK: Subtraction operators
public prefix func -(x: Decimal) -> Decimal {
return Decimal(x.value.decimalNumberByMultiplyingBy(NSDecimalNumber(integer: -1)))
}
public func -(lhs: Decimal, rhs: Decimal) -> Decimal {
return Decimal(lhs.value.decimalNumberBySubtracting(rhs.value))
}
public prefix func --(lhs: Decimal) -> Decimal {
return Decimal(lhs.value.decimalNumberBySubtracting(NSDecimalNumber.one()))
}
public postfix func --(inout lhs: Decimal) -> Decimal {
lhs = Decimal(lhs.value.decimalNumberBySubtracting(NSDecimalNumber.one()))
return lhs
}
public func -=(inout lhs: Decimal, rhs: Decimal) -> Decimal {
lhs = Decimal(lhs.value.decimalNumberBySubtracting(rhs.value))
return lhs
}
public func -=(inout lhs: Decimal, rhs: Int) -> Decimal {
lhs = Decimal(lhs.value.decimalNumberBySubtracting(NSDecimalNumber(integer: rhs)))
return lhs
}
public func -=(inout lhs: Decimal, rhs: Double) -> Decimal {
lhs = Decimal(lhs.value.decimalNumberBySubtracting(NSDecimalNumber(double: rhs)))
return lhs
}
// MARK: Multiplication operators
public func *(inout lhs: Decimal, rhs: Decimal) -> Decimal {
return Decimal(lhs.value.decimalNumberByMultiplyingBy(rhs.value))
}
public func *=(inout lhs: Decimal, rhs: Decimal) -> Decimal {
lhs = Decimal(lhs.value.decimalNumberByMultiplyingBy(rhs.value))
return lhs
}
public func *=(inout lhs: Decimal, rhs: Int) -> Decimal {
lhs = Decimal(lhs.value.decimalNumberByMultiplyingBy(NSDecimalNumber(integer: rhs)))
return lhs
}
public func *=(inout lhs: Decimal, rhs: Double) -> Decimal {
lhs = Decimal(lhs.value.decimalNumberByMultiplyingBy(NSDecimalNumber(double: rhs)))
return lhs
}
// MARK: Division operators
public func /(lhs: Decimal, rhs: Decimal) -> Decimal {
return Decimal(lhs.value.decimalNumberByDividingBy(rhs.value))
}
public func /=(inout lhs: Decimal, rhs: Decimal) -> Decimal {
lhs = Decimal(lhs.value.decimalNumberByDividingBy(rhs.value))
return lhs
}
public func /=(inout lhs: Decimal, rhs: Int) -> Decimal {
lhs = Decimal(lhs.value.decimalNumberByDividingBy(NSDecimalNumber(integer: rhs)))
return lhs
}
public func /=(inout lhs: Decimal, rhs: Double) -> Decimal {
lhs = Decimal(lhs.value.decimalNumberByDividingBy(NSDecimalNumber(double: rhs)))
return lhs
}
// MARK: Power-of operators
public func ^(lhs: Decimal, rhs: Int) -> Decimal {
return Decimal(lhs.value.decimalNumberByRaisingToPower(rhs))
}
extension Decimal: Strideable {
/// Returns a stride `x` such that `self.advancedBy(x)` approximates
/// `other`.
///
/// - Complexity: O(1).
public func distanceTo(other: Decimal) -> Decimal {
return self - other
}
/// Returns a `Self` `x` such that `self.distanceTo(x)` approximates
/// `n`.
///
/// - Complexity: O(1).
public func advancedBy(amount: Decimal) -> Decimal {
return self + amount
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment