Skip to content

Instantly share code, notes, and snippets.

@CTMacUser
Created June 23, 2018 22:34
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CTMacUser/1c09374a9fdb0f58fd9b0e9d8a3d1157 to your computer and use it in GitHub Desktop.
Save CTMacUser/1c09374a9fdb0f58fd9b0e9d8a3d1157 to your computer and use it in GitHub Desktop.
Four-bit signed and unsigned integer types in Swift.
//
// 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()
}
}
//
// 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