Created
November 8, 2015 17:58
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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