Created
June 23, 2018 22:34
-
-
Save CTMacUser/1c09374a9fdb0f58fd9b0e9d8a3d1157 to your computer and use it in GitHub Desktop.
Four-bit signed and unsigned integer types 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
// | |
// Int4.swift | |
// NegaSuperBinary | |
// | |
// Created by Daryle Walker on 6/22/18. | |
// Copyright © 2018 Daryle Walker. All rights reserved. | |
// | |
import Foundation | |
/// A 4-bit signed integer | |
public struct Int4: FixedWidthInteger, SignedInteger { | |
/// The represented value. | |
var value: Int8 | |
/// A mask for the highest significant bit, excluding bits past the model's bit width | |
static let highOrderBitMask = Int8(1 << (bitWidth - 1)) | |
/// A mask to exclude the unneeded bits of the storage register. | |
static let valueMask = (highOrderBitMask << 1) - 1 | |
/// A mask to exclude unneeded bits of a bit-shift within the bit width. | |
static let shiftMask: Int8 = { | |
precondition(bitWidth.nonzeroBitCount == 1) | |
return Int8(bitWidth) - 1 | |
}() | |
/// Returns the value except the higher-order bits are replaced with a sign extension of the 8-place bit. | |
static func signExtendTheLowNybble(of x: Int8) -> Int8 { | |
return x & highOrderBitMask != 0 ? x | ~valueMask : x & valueMask | |
} | |
/// Makes sure the ignored higher-order bits properly sign-extend the highest official bit. | |
mutating func properlySignExtend() { | |
value = Int4.signExtendTheLowNybble(of: value) | |
} | |
// ExpressibleByIntegerLiteral | |
public init(integerLiteral value: Int8) { | |
precondition(-8...7 ~= value) | |
self.value = value | |
} | |
// Numeric | |
public var magnitude: UInt4 { | |
return UInt4(value.magnitude) | |
} | |
public static func * (lhs: Int4, rhs: Int4) -> Int4 { | |
let longResult = lhs.multipliedReportingOverflow(by: rhs) | |
assert(!longResult.overflow) | |
return longResult.partialValue | |
} | |
public static func *= (lhs: inout Int4, rhs: Int4) { | |
lhs = lhs * rhs | |
} | |
public static func + (lhs: Int4, rhs: Int4) -> Int4 { | |
let longResult = lhs.addingReportingOverflow(rhs) | |
assert(!longResult.overflow) | |
return longResult.partialValue | |
} | |
public static func += (lhs: inout Int4, rhs: Int4) { | |
lhs = lhs + rhs | |
} | |
public static func - (lhs: Int4, rhs: Int4) -> Int4 { | |
let longResult = lhs.subtractingReportingOverflow(rhs) | |
assert(!longResult.overflow) | |
return longResult.partialValue | |
} | |
public static func -= (lhs: inout Int4, rhs: Int4) { | |
lhs = lhs - rhs | |
} | |
// Stridable | |
public func advanced(by n: Int) -> Int4 { | |
let newValue = Int(value) + n | |
return Int4(integerLiteral: Int8(newValue)) | |
} | |
public func distance(to other: Int4) -> Int { | |
return Int(other.value) - Int(value) | |
} | |
// BinaryInteger | |
public var words: Int8.Words { | |
return value.words | |
} | |
public var trailingZeroBitCount: Int { | |
return Swift.min(value.trailingZeroBitCount, 4) | |
} | |
public func quotientAndRemainder(dividingBy rhs: Int4) -> (quotient: Int4, remainder: Int4) { | |
return rhs.dividingFullWidth((high: self < 0 ? ~0 : 0, low: self.magnitude)) | |
} | |
public static func / (lhs: Int4, rhs: Int4) -> Int4 { | |
let longResult = lhs.dividedReportingOverflow(by: rhs) | |
assert(!longResult.overflow) | |
return longResult.partialValue | |
} | |
public static func /= (lhs: inout Int4, rhs: Int4) { | |
lhs = lhs / rhs | |
} | |
public static func % (lhs: Int4, rhs: Int4) -> Int4 { | |
let longResult = lhs.remainderReportingOverflow(dividingBy: rhs) | |
assert(!longResult.overflow) | |
return longResult.partialValue | |
} | |
public static func %= (lhs: inout Int4, rhs: Int4) { | |
lhs = lhs % rhs | |
} | |
public static func &= (lhs: inout Int4, rhs: Int4) { | |
lhs.value &= rhs.value | |
lhs.properlySignExtend() | |
} | |
public static func |= (lhs: inout Int4, rhs: Int4) { | |
lhs.value |= rhs.value | |
lhs.properlySignExtend() | |
} | |
public static func ^= (lhs: inout Int4, rhs: Int4) { | |
lhs.value ^= rhs.value | |
lhs.properlySignExtend() | |
} | |
// FixedWidthInteger | |
public static var bitWidth: Int { | |
return 4 | |
} | |
public init(_truncatingBits: UInt) { | |
self.init(integerLiteral: Int4.signExtendTheLowNybble(of: Int8(truncatingIfNeeded: _truncatingBits))) | |
} | |
public func addingReportingOverflow(_ rhs: Int4) -> (partialValue: Int4, overflow: Bool) { | |
let (sum, overflow) = value.addingReportingOverflow(rhs.value) | |
return (Int4(_truncatingBits: sum.words.first ?? 0), overflow || !(-8...7 ~= sum)) | |
} | |
public func subtractingReportingOverflow(_ rhs: Int4) -> (partialValue: Int4, overflow: Bool) { | |
let (difference, overflow) = value.subtractingReportingOverflow(rhs.value) | |
return (Int4(_truncatingBits: difference.words.first ?? 0), overflow || !(-8...7 ~= difference)) | |
} | |
public func multipliedReportingOverflow(by rhs: Int4) -> (partialValue: Int4, overflow: Bool) { | |
let (product, overflow) = value.multipliedReportingOverflow(by: rhs.value) | |
return (Int4(_truncatingBits: product.words.first ?? 0), overflow || !(-8...7 ~= product)) | |
} | |
public func dividedReportingOverflow(by rhs: Int4) -> (partialValue: Int4, overflow: Bool) { | |
let (quotient, overflow) = value.dividedReportingOverflow(by: rhs.value) | |
return (Int4(_truncatingBits: quotient.words.first ?? 0), overflow || !(-8...7 ~= quotient)) | |
} | |
public func remainderReportingOverflow(dividingBy rhs: Int4) -> (partialValue: Int4, overflow: Bool) { | |
let (remainder, overflow) = value.remainderReportingOverflow(dividingBy: rhs.value) | |
return (Int4(_truncatingBits: remainder.words.first ?? 0), overflow || !(-8...7 ~= remainder)) | |
} | |
public func multipliedFullWidth(by other: Int4) -> (high: Int4, low: UInt4) { | |
let (product, didOverflow) = value.multipliedReportingOverflow(by: other.value) | |
precondition(!didOverflow) | |
return (Int4(truncatingIfNeeded: product >> 4), UInt4(truncatingIfNeeded: product)) | |
} | |
public func dividingFullWidth(_ dividend: (high: Int4, low: UInt4)) -> (quotient: Int4, remainder: Int4) { | |
let fullDividend = (dividend.high.value << 4) | Int8(truncatingIfNeeded: dividend.low.value) | |
let (quotient, remainder) = fullDividend.quotientAndRemainder(dividingBy: self.value) | |
return (Int4(quotient), Int4(remainder)) | |
} | |
public var nonzeroBitCount: Int { | |
return (value & Int4.valueMask).nonzeroBitCount - 4 | |
} | |
public var leadingZeroBitCount: Int { | |
return (value & Int4.valueMask).leadingZeroBitCount - 4 | |
} | |
public var byteSwapped: Int4 { | |
return self | |
} | |
public static func &>>= (lhs: inout Int4, rhs: Int4) { | |
lhs.value >>= rhs.value & Int4.shiftMask | |
lhs.properlySignExtend() | |
} | |
public static func &<<= (lhs: inout Int4, rhs: Int4) { | |
lhs.value <<= rhs.value & Int4.shiftMask | |
lhs.properlySignExtend() | |
} | |
} |
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
// | |
// UInt4.swift | |
// NegaSuperBinary | |
// | |
// Created by Daryle Walker on 6/22/18. | |
// Copyright © 2018 Daryle Walker. All rights reserved. | |
// | |
import Foundation | |
/// A 4-bit unsigned integer type. Adapted from <https://github.com/markrenaud/UInt4> by Mark Renaud. | |
public struct UInt4: FixedWidthInteger, UnsignedInteger { | |
/// The stored value. | |
var value: UInt8 | |
/// A mask to exclude the unneeded bits of the storage register. | |
static let valueMask: UInt8 = (1 << bitWidth) - 1 | |
// ExpressibleByIntegerLiteral | |
public init(integerLiteral value: UInt8) { | |
precondition(value & ~UInt4.valueMask == 0) | |
self.value = value | |
} | |
// Numeric | |
public static func + (lhs: UInt4, rhs: UInt4) -> UInt4 { | |
let longResult = lhs.addingReportingOverflow(rhs) | |
assert(!longResult.overflow) | |
return longResult.partialValue | |
} | |
public static func += (lhs: inout UInt4, rhs: UInt4) { | |
lhs = lhs + rhs | |
} | |
public static func * (lhs: UInt4, rhs: UInt4) -> UInt4 { | |
let longResult = lhs.multipliedReportingOverflow(by: rhs) | |
assert(!longResult.overflow) | |
return longResult.partialValue | |
} | |
public static func *= (lhs: inout UInt4, rhs: UInt4) { | |
lhs = lhs * rhs | |
} | |
public static func - (lhs: UInt4, rhs: UInt4) -> UInt4 { | |
let longResult = lhs.subtractingReportingOverflow(rhs) | |
assert(!longResult.overflow) | |
return longResult.partialValue | |
} | |
public static func -= (lhs: inout UInt4, rhs: UInt4) { | |
lhs = lhs - rhs | |
} | |
// Strideable | |
public func advanced(by n: Int) -> UInt4 { | |
let newValue = Int(value) + n | |
return UInt4(integerLiteral: UInt8(newValue)) | |
} | |
public func distance(to other: UInt4) -> Int { | |
return Int(other.value) - Int(value) | |
} | |
// BinaryInteger | |
public var words: UInt8.Words { | |
return value.words | |
} | |
public var trailingZeroBitCount: Int { | |
return Swift.min(UInt4.bitWidth, value.trailingZeroBitCount) | |
} | |
public static func / (lhs: UInt4, rhs: UInt4) -> UInt4 { | |
let longResult = lhs.dividedReportingOverflow(by: rhs) | |
assert(!longResult.overflow) | |
return longResult.partialValue | |
} | |
public static func /= (lhs: inout UInt4, rhs: UInt4) { | |
lhs = lhs / rhs | |
} | |
public static func % (lhs: UInt4, rhs: UInt4) -> UInt4 { | |
let longResult = lhs.remainderReportingOverflow(dividingBy: rhs) | |
assert(!longResult.overflow) | |
return longResult.partialValue | |
} | |
public static func %= (lhs: inout UInt4, rhs: UInt4) { | |
lhs = lhs % rhs | |
} | |
public static func &= (lhs: inout UInt4, rhs: UInt4) { | |
lhs.value &= rhs.value | |
} | |
public static func ^= (lhs: inout UInt4, rhs: UInt4) { | |
lhs.value ^= rhs.value | |
} | |
public static func |= (lhs: inout UInt4, rhs: UInt4) { | |
lhs.value |= rhs.value | |
} | |
// FixedWidthInteger | |
public static var bitWidth: Int { | |
return 4 | |
} | |
public init(_truncatingBits bits: UInt) { | |
self.init(integerLiteral: UInt8(bits & 0xF)) | |
} | |
public var nonzeroBitCount: Int { | |
return value.nonzeroBitCount - 4 | |
} | |
public var leadingZeroBitCount: Int { | |
return value.leadingZeroBitCount - 4 | |
} | |
public var byteSwapped: UInt4 { | |
return self | |
} | |
public func addingReportingOverflow(_ rhs: UInt4) -> (partialValue: UInt4, overflow: Bool) { | |
let longSum = value + rhs.value | |
return (UInt4(truncatingIfNeeded: longSum), longSum > 15) | |
} | |
public func subtractingReportingOverflow(_ rhs: UInt4) -> (partialValue: UInt4, overflow: Bool) { | |
let longResult = value.subtractingReportingOverflow(rhs.value) | |
return (UInt4(truncatingIfNeeded: longResult.partialValue), longResult.overflow) | |
} | |
public func multipliedReportingOverflow(by rhs: UInt4) -> (partialValue: UInt4, overflow: Bool) { | |
let longResult = multipliedFullWidth(by: rhs) | |
return (longResult.low, longResult.high > 0) | |
} | |
public func dividedReportingOverflow(by rhs: UInt4) -> (partialValue: UInt4, overflow: Bool) { | |
let longResult = value.dividedReportingOverflow(by: rhs.value) | |
return (UInt4(truncatingIfNeeded: longResult.partialValue), longResult.overflow || longResult.partialValue > 15) | |
} | |
public func remainderReportingOverflow(dividingBy rhs: UInt4) -> (partialValue: UInt4, overflow: Bool) { | |
let longResult = value.remainderReportingOverflow(dividingBy: rhs.value) | |
return (UInt4(truncatingIfNeeded: longResult.partialValue), longResult.overflow) | |
} | |
public func multipliedFullWidth(by other: UInt4) -> (high: UInt4, low: UInt4) { | |
let longProduct = value * other.value | |
return (UInt4(truncatingIfNeeded: longProduct >> 4), UInt4(truncatingIfNeeded: longProduct)) | |
} | |
public func dividingFullWidth(_ dividend: (high: UInt4, low: UInt4)) -> (quotient: UInt4, remainder: UInt4) { | |
let unifiedDividend = (dividend.high.value << 4) | dividend.low.value | |
let longResult = unifiedDividend.quotientAndRemainder(dividingBy: value) | |
return (UInt4(longResult.quotient), UInt4(longResult.remainder)) | |
} | |
public static func &<<= (lhs: inout UInt4, rhs: UInt4) { | |
lhs.value <<= Int(rhs.value) % UInt4.bitWidth | |
lhs.value &= UInt4.valueMask | |
} | |
public static func &>>= (lhs: inout UInt4, rhs: UInt4) { | |
lhs.value >>= Int(rhs.value) % UInt4.bitWidth | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment