Skip to content

Commit

Permalink
[NBKCoreKit] Bits (#85).
Browse files Browse the repository at this point in the history
  • Loading branch information
oscbyspro committed Sep 21, 2023
1 parent 609bb1b commit aaa2b57
Show file tree
Hide file tree
Showing 5 changed files with 342 additions and 333 deletions.
115 changes: 0 additions & 115 deletions Sources/NBKCoreKit/Private/NBK+Limbs+Bits.swift

This file was deleted.

111 changes: 111 additions & 0 deletions Sources/NBKCoreKit/Private/NBKStrictBinaryInteger+Bits.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
//=----------------------------------------------------------------------------=
// This source file is part of the Numberick open source project.
//
// Copyright (c) 2023 Oscar Byström Ericsson
// Licensed under Apache License, Version 2.0
//
// See http://www.apache.org/licenses/LICENSE-2.0 for license information.
//=----------------------------------------------------------------------------=

//*============================================================================*
// MARK: * NBK x Strict Binary Integer x Bits x Sub Sequence
//*============================================================================*

extension NBK.StrictBinaryInteger.SubSequence {

//=------------------------------------------------------------------------=
// MARK: Details
//=------------------------------------------------------------------------=

/// Returns the leading zero bit count of `base`.
///
/// - Note: The leading zero bit count is zero when `base` is empty.
///
@inlinable public static func leadingZeroBitCount(of base: Base) -> Int {
var index = base.endIndex
var element = 0 as Base.Element

while index > base.startIndex, element.isZero {
base.formIndex(before: &index)
element = base[index]
}

let product = base.distance(from: index, to: base.endIndex) * Base.Element.bitWidth
return product - Base.Element.bitWidth + element.leadingZeroBitCount
}

/// Returns the trailing zero bit count of `base`.
///
/// - Note: The trailing zero bit count is zero when `base` is empty.
///
@inlinable public static func trailingZeroBitCount(of base: Base) -> Int {
var index = base.startIndex
var element = 0 as Base.Element

while index < base.endIndex, element.isZero {
element = base[index]
base.formIndex(after: &index)
}

let product = base.distance(from: base.startIndex, to: index) * Base.Element.bitWidth
return product - Base.Element.bitWidth + element.trailingZeroBitCount
}

/// Returns the most significant bit for the two's complement of `base`.
///
/// - Note: The most significant bit does not exist when `base` is empty.
///
@inlinable public static func mostSignificantBit(twosComplementOf base: Base) -> Bool? {
//=--------------------------------------=
guard let index = base.firstIndex(where:{ !$0.isZero }) else { return base.isEmpty ? nil : false }
//=--------------------------------------=
let lastIndex = base.index(before: base.endIndex)
return base[lastIndex].twosComplementSubsequence(index == lastIndex).partialValue.mostSignificantBit
}

//=------------------------------------------------------------------------=
// MARK: Details x Nonzero Bit Count
//=------------------------------------------------------------------------=

/// Returns the nonzero bit count of `base`.
///
/// - Note: The nonzero bit count is zero when `base` is empty.
///
@inlinable public static func nonzeroBitCount(of base: Base) -> Int {
base.reduce(0 as Int) { $0 + $1.nonzeroBitCount }
}

/// Returns whether the nonzero bit count of `base` equals `comparand`.
///
/// - Note: The nonzero bit count is zero when `base` is empty.
///
@inlinable public static func nonzeroBitCount(of base: Base, equals comparand: Int) -> Bool {
var nonzeroBitCount = 0 as Int
var index: Base.Index = base.startIndex

while index < base.endIndex, nonzeroBitCount <= comparand {
nonzeroBitCount += base[index].nonzeroBitCount
base.formIndex(after: &index)
}

return (nonzeroBitCount == comparand) as Bool
}

/// Returns the nonzero bit count for the two's complement of `base`.
///
/// - Note: The nonzero bit count is zero when `base` is empty.
///
@inlinable public static func nonzeroBitCount(twosComplementOf base: Base) -> Int {
//=--------------------------------------=
guard var index = base.firstIndex(where:{ !$0.isZero }) else { return 0 as Int }
//=--------------------------------------=
var nonzeroBitCount: Int = 1 - base[index].trailingZeroBitCount

while index < base.endIndex {
nonzeroBitCount += base[index].onesComplement().nonzeroBitCount
base.formIndex(after: &index)
}

return nonzeroBitCount as Int
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,28 @@ import NBKCoreKit
import XCTest

//*============================================================================*
// MARK: * NBK x Limbs x Bits
// MARK: * NBK x Strict Binary Integer x Bits x Sub Sequence
//*============================================================================*

final class NBKBenchmarksOnLimbsByBits: XCTestCase {
final class NBKStrictBinaryIntegerBenchmarksOnBitsAsSubSequence: XCTestCase {

private typealias U64 = [UInt64]
private typealias U32 = [UInt32]

private typealias T64 = NBK.StrictBinaryInteger<U64>.SubSequence
private typealias T32 = NBK.StrictBinaryInteger<U32>.SubSequence

//=------------------------------------------------------------------------=
// MARK: Tests
//=------------------------------------------------------------------------=

func testLeadingZeroBitCount() {
var abc = NBK.blackHoleIdentity([ 0, 0, 0, 0, 0, 0, 0, 0] as U64)
var xyz = NBK.blackHoleIdentity([~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0] as U64)

for _ in 0 ..< 5_000_000 {
NBK.blackHole(NBK.leadingZeroBitCount(of: abc))
NBK.blackHole(NBK.leadingZeroBitCount(of: xyz))
NBK.blackHole(T64.leadingZeroBitCount(of: abc))
NBK.blackHole(T64.leadingZeroBitCount(of: xyz))

NBK.blackHoleInoutIdentity(&abc)
NBK.blackHoleInoutIdentity(&xyz)
Expand All @@ -41,10 +44,10 @@ final class NBKBenchmarksOnLimbsByBits: XCTestCase {
func testTrailingZeroBitCount() {
var abc = NBK.blackHoleIdentity([ 0, 0, 0, 0, 0, 0, 0, 0] as U64)
var xyz = NBK.blackHoleIdentity([~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0] as U64)

for _ in 0 ..< 5_000_000 {
NBK.blackHole(NBK.trailingZeroBitCount(of: abc))
NBK.blackHole(NBK.trailingZeroBitCount(of: xyz))
NBK.blackHole(T64.trailingZeroBitCount(of: abc))
NBK.blackHole(T64.trailingZeroBitCount(of: xyz))

NBK.blackHoleInoutIdentity(&abc)
NBK.blackHoleInoutIdentity(&xyz)
Expand All @@ -56,8 +59,8 @@ final class NBKBenchmarksOnLimbsByBits: XCTestCase {
var xyz = NBK.blackHoleIdentity([~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0] as U64)

for _ in 0 ..< 5_000_000 {
NBK.blackHole(NBK.mostSignificantBit(twosComplementOf: abc)!)
NBK.blackHole(NBK.mostSignificantBit(twosComplementOf: xyz)!)
NBK.blackHole(T64.mostSignificantBit(twosComplementOf: abc)!)
NBK.blackHole(T64.mostSignificantBit(twosComplementOf: xyz)!)

NBK.blackHoleInoutIdentity(&abc)
NBK.blackHoleInoutIdentity(&xyz)
Expand All @@ -71,10 +74,10 @@ final class NBKBenchmarksOnLimbsByBits: XCTestCase {
func testNonzeroBitCount() {
var abc = NBK.blackHoleIdentity([ 0, 0, 0, 0, 0, 0, 0, 0] as U64)
var xyz = NBK.blackHoleIdentity([~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0] as U64)

for _ in 0 ..< 5_000_000 {
NBK.blackHole(NBK.nonzeroBitCount(of: abc))
NBK.blackHole(NBK.nonzeroBitCount(of: xyz))
NBK.blackHole(T64.nonzeroBitCount(of: abc))
NBK.blackHole(T64.nonzeroBitCount(of: xyz))

NBK.blackHoleInoutIdentity(&abc)
NBK.blackHoleInoutIdentity(&xyz)
Expand All @@ -84,10 +87,10 @@ final class NBKBenchmarksOnLimbsByBits: XCTestCase {
func testNonzeroBitCountEquals() {
var abc = NBK.blackHoleIdentity([ 0, 0, 0, 0, 0, 0, 0, 0] as U64)
var xyz = NBK.blackHoleIdentity([~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0] as U64)

for _ in 0 ..< 5_000_000 {
NBK.blackHole(NBK.nonzeroBitCount(of: abc, equals: 1))
NBK.blackHole(NBK.nonzeroBitCount(of: xyz, equals: 1))
NBK.blackHole(T64.nonzeroBitCount(of: abc, equals: 1))
NBK.blackHole(T64.nonzeroBitCount(of: xyz, equals: 1))

NBK.blackHoleInoutIdentity(&abc)
NBK.blackHoleInoutIdentity(&xyz)
Expand All @@ -97,10 +100,10 @@ final class NBKBenchmarksOnLimbsByBits: XCTestCase {
func testNonzeroBitCountTwosComplementOf() {
var abc = NBK.blackHoleIdentity([ 0, 0, 0, 0, 0, 0, 0, 0] as U64)
var xyz = NBK.blackHoleIdentity([~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0] as U64)

for _ in 0 ..< 5_000_000 {
NBK.blackHole(NBK.nonzeroBitCount(twosComplementOf: abc))
NBK.blackHole(NBK.nonzeroBitCount(twosComplementOf: xyz))
NBK.blackHole(T64.nonzeroBitCount(twosComplementOf: abc))
NBK.blackHole(T64.nonzeroBitCount(twosComplementOf: xyz))

NBK.blackHoleInoutIdentity(&abc)
NBK.blackHoleInoutIdentity(&xyz)
Expand Down
Loading

0 comments on commit aaa2b57

Please sign in to comment.