Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 82 additions & 10 deletions cpp/Platform.Numbers.Tests/BitTests.cpp
Original file line number Diff line number Diff line change
@@ -1,22 +1,94 @@
namespace Platform::Numbers::Tests
#include "gtest/gtest.h"
#include "Platform.Numbers.h"

namespace Platform::Numbers::Tests
{
// Assuming that GetLowestPosition is a valid function in your bit operations library
// Test GetLowestPosition function with various values based on C# tests
TEST(BitTests, GetLowestBitPositionTest)
{
std::uint64_t value = 32;
std::int32_t expectedPosition = 5;
ASSERT_EQ(Platform::Numbers::Bit::GetLowestPosition(value), expectedPosition);
// Test cases from C# implementation
ASSERT_EQ(Platform::Numbers::Bit::GetLowestPosition(0), -1); // 0000 0000 (none, -1)
ASSERT_EQ(Platform::Numbers::Bit::GetLowestPosition(1), 0); // 0000 0001 (first, 0)
ASSERT_EQ(Platform::Numbers::Bit::GetLowestPosition(8), 3); // 0000 1000 (forth, 3)
ASSERT_EQ(Platform::Numbers::Bit::GetLowestPosition(88), 3); // 0101 1000 (forth, 3)
ASSERT_EQ(Platform::Numbers::Bit::GetLowestPosition(32), 5); // Previous test case
}

// Similar tests can be written for other operations like And, Or, ShiftLeft, ShiftRight, etc.
// Test Count function
TEST(BitTests, CountTest)
{
ASSERT_EQ(Platform::Numbers::Bit::Count(0), 0);
ASSERT_EQ(Platform::Numbers::Bit::Count(1), 1); // 0001
ASSERT_EQ(Platform::Numbers::Bit::Count(3), 2); // 0011
ASSERT_EQ(Platform::Numbers::Bit::Count(7), 3); // 0111
ASSERT_EQ(Platform::Numbers::Bit::Count(15), 4); // 1111
}

// PartialRead and PartialWrite tests
// PartialRead and PartialWrite tests based on C# implementation
TEST(BitTests, PartialReadWriteTest)
{
std::uint32_t firstValue = 1;
std::uint32_t secondValue = 1543;
std::uint32_t value = Platform::Numbers::Bit::PartialWrite(secondValue, firstValue, 0, 1);
std::uint32_t readValue = Platform::Numbers::Bit::PartialRead(value, 0, 1);
ASSERT_EQ(readValue, firstValue);

// Pack (join) two values at the same time
std::uint32_t value = secondValue << 1 | firstValue;

std::uint32_t unpackagedFirstValue = value & 1;
std::uint32_t unpackagedSecondValue = (value & 0xFFFFFFFE) >> 1;

ASSERT_EQ(firstValue, unpackagedFirstValue);
ASSERT_EQ(secondValue, unpackagedSecondValue);

// Using universal functions:
ASSERT_EQ(Platform::Numbers::Bit::PartialRead(value, 0, 1), firstValue);
ASSERT_EQ(Platform::Numbers::Bit::PartialRead(value, 1, -1), secondValue);

firstValue = 0;
secondValue = 6892;

value = Platform::Numbers::Bit::PartialWrite(value, firstValue, 0, 1);
value = Platform::Numbers::Bit::PartialWrite(value, secondValue, 1, -1);

ASSERT_EQ(Platform::Numbers::Bit::PartialRead(value, 0, 1), firstValue);
ASSERT_EQ(Platform::Numbers::Bit::PartialRead(value, 1, -1), secondValue);
}

// Test Math functions
TEST(MathTests, FactorialTest)
{
ASSERT_EQ(Platform::Numbers::Math::Factorial<std::uint64_t>(0), 1);
ASSERT_EQ(Platform::Numbers::Math::Factorial<std::uint64_t>(1), 1);
ASSERT_EQ(Platform::Numbers::Math::Factorial<std::uint64_t>(2), 2);
ASSERT_EQ(Platform::Numbers::Math::Factorial<std::uint64_t>(3), 6);
ASSERT_EQ(Platform::Numbers::Math::Factorial<std::uint64_t>(4), 24);
ASSERT_EQ(Platform::Numbers::Math::Factorial<std::uint64_t>(5), 120);

// Test out of range
ASSERT_THROW(Platform::Numbers::Math::Factorial<std::uint64_t>(21), std::out_of_range);
}

TEST(MathTests, CatalanTest)
{
ASSERT_EQ(Platform::Numbers::Math::Catalan<std::uint64_t>(0), 1);
ASSERT_EQ(Platform::Numbers::Math::Catalan<std::uint64_t>(1), 1);
ASSERT_EQ(Platform::Numbers::Math::Catalan<std::uint64_t>(2), 2);
ASSERT_EQ(Platform::Numbers::Math::Catalan<std::uint64_t>(3), 5);
ASSERT_EQ(Platform::Numbers::Math::Catalan<std::uint64_t>(4), 14);

// Test out of range
ASSERT_THROW(Platform::Numbers::Math::Catalan<std::uint64_t>(37), std::out_of_range);
}

TEST(MathTests, IsPowerOfTwoTest)
{
ASSERT_FALSE(Platform::Numbers::Math::IsPowerOfTwo<std::uint64_t>(0));
ASSERT_TRUE(Platform::Numbers::Math::IsPowerOfTwo<std::uint64_t>(1));
ASSERT_TRUE(Platform::Numbers::Math::IsPowerOfTwo<std::uint64_t>(2));
ASSERT_FALSE(Platform::Numbers::Math::IsPowerOfTwo<std::uint64_t>(3));
ASSERT_TRUE(Platform::Numbers::Math::IsPowerOfTwo<std::uint64_t>(4));
ASSERT_FALSE(Platform::Numbers::Math::IsPowerOfTwo<std::uint64_t>(5));
ASSERT_TRUE(Platform::Numbers::Math::IsPowerOfTwo<std::uint64_t>(8));
ASSERT_TRUE(Platform::Numbers::Math::IsPowerOfTwo<std::uint64_t>(16));
ASSERT_FALSE(Platform::Numbers::Math::IsPowerOfTwo<std::uint64_t>(17));
}
}
30 changes: 29 additions & 1 deletion cpp/Platform.Numbers/Bit.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
namespace Platform::Numbers::Bit
#pragma once
#include <cstdint>
#include <limits>

namespace Platform::Numbers::Bit
{
/// <summary>
/// <para>Counts the number of bits set in a number.</para>
/// <para>Подсчитывает количество установленных бит в числе.</para>
/// </summary>
/// <param name="x">
/// <para>Bitwise number.</para>
/// <para>Число в битовом представлении.</para>
/// </param>
/// <returns>
/// <para>Number of bits set in a number.</para>
/// <para>Количество установленных бит в числе.</para>
/// </returns>
constexpr std::int64_t Count(std::int64_t x)
{
std::int64_t n = 0;
Expand All @@ -11,6 +27,18 @@
return n;
}

/// <summary>
/// <para>Searches for the first bit set in a number.</para>
/// <para>Ищет первый установленный бит в числе.</para>
/// </summary>
/// <param name="value">
/// <para>Bitwise number.</para>
/// <para>Число в битовом представлении.</para>
/// </param>
/// <returns>
/// <para>First bit set.</para>
/// <para>Первый установленный бит.</para>
/// </returns>
constexpr std::int32_t GetLowestPosition(std::uint64_t value)
{
if (value == 0)
Expand Down
139 changes: 100 additions & 39 deletions cpp/Platform.Numbers/Math.h
Original file line number Diff line number Diff line change
@@ -1,55 +1,116 @@
namespace Platform::Numbers
{
#pragma once
#include <cstdint>
#include <stdexcept>
#include <string>
#include <type_traits>

namespace Platform::Numbers
{
/// <summary>
/// <para>Represents a set of math methods.</para>
/// <para>Представляет набор математических методов.</para>
/// </summary>
class Math
{
private: static readonly std::uint64_t[] _factorials =
{
{
private:
static constexpr std::uint64_t _factorials[] =
{
1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800,
479001600, 6227020800, 87178291200, 1307674368000, 20922789888000,
355687428096000, 6402373705728000, 121645100408832000, 2432902008176640000
479001600, 6227020800ULL, 87178291200ULL, 1307674368000ULL, 20922789888000ULL,
355687428096000ULL, 6402373705728000ULL, 121645100408832000ULL, 2432902008176640000ULL
};

private: static readonly std::uint64_t[] _catalans =
{
static constexpr std::uint64_t _catalans[] =
{
1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012,
742900, 2674440, 9694845, 35357670, 129644790, 477638700, 1767263190,
6564120420, 24466267020, 91482563640, 343059613650, 1289904147324, 4861946401452,
18367353072152, 69533550916004, 263747951750360, 1002242216651368, 3814986502092304,
14544636039226909, 55534064877048198, 212336130412243110, 812944042149730764, 3116285494907301262, 11959798385860453492
6564120420ULL, 24466267020ULL, 91482563640ULL, 343059613650ULL, 1289904147324ULL, 4861946401452ULL,
18367353072152ULL, 69533550916004ULL, 263747951750360ULL, 1002242216651368ULL, 3814986502092304ULL,
14544636039226909ULL, 55534064877048198ULL, 212336130412243110ULL, 812944042149730764ULL, 3116285494907301262ULL, 11959798385860453492ULL
};

public: inline static const std::uint64_t MaximumFactorialNumber = 20;

public: inline static const std::uint64_t MaximumCatalanIndex = 36;

public: static std::uint64_t Factorial(std::uint64_t n)
{
if (n >= 0 && n <= MaximumFactorialNumber)
{
return _factorials[n] = { {0} };

public:
/// <summary>
/// <para>Represents the limit for calculating the factorial number, supported by the <see cref="ulong"/> type.</para>
/// <para>Представляет предел расчёта факториала числа, поддерживаемый <see cref="ulong"/> типом.</para>
/// </summary>
static constexpr std::uint64_t MaximumFactorialNumber = 20;

/// <summary>
/// <para>Represents the limit for calculating the catanal number, supported by the <see cref="ulong"/> type.</para>
/// <para>Представляет предел расчёта катаналового числа, поддерживаемый <see cref="ulong"/> типом.</para>
/// </summary>
static constexpr std::uint64_t MaximumCatalanIndex = 36;

/// <summary>
/// <para>Returns the product of all positive integers less than or equal to the number specified as an argument.</para>
/// <para>Возвращает произведение всех положительных чисел меньше или равных указанному в качестве аргумента числу.</para>
/// </summary>
/// <param name="n">
/// <para>The maximum positive number that will participate in factorial's product.</para>
/// <para>Максимальное положительное число, которое будет участвовать в произведении факториала.</para>
/// </param>
/// <returns>
/// <para>The product of all positive integers less than or equal to the number specified as an argument.</para>
/// <para>Произведение всех положительных чисел меньше или равных указанному, в качестве аргумента, числу.</para>
/// </returns>
template <typename TLinkAddress>
static constexpr TLinkAddress Factorial(TLinkAddress n)
{
static_assert(std::is_unsigned_v<TLinkAddress>, "TLinkAddress must be an unsigned integer type");
if (n <= MaximumFactorialNumber)
{
return static_cast<TLinkAddress>(_factorials[static_cast<std::size_t>(n)]);
}
else
{
throw std::invalid_argument(std::string("Only numbers from 0 to ").append(Platform::Converters::To<std::string>(MaximumFactorialNumber)).append(" are supported by unsigned integer with 64 bits length."));
{
throw std::out_of_range("Only numbers from 0 to " + std::to_string(MaximumFactorialNumber) + " are supported by unsigned integer with 64 bits length.");
}
}

public: static std::uint64_t Catalan(std::uint64_t n)
{
if (n >= 0 && n <= MaximumCatalanIndex)
{
return _catalans[n] = { {0} };

/// <summary>
/// <para>Returns the Catalan Number with the number specified as an argument.</para>
/// <para>Возвращает Число Катанала с номером, указанным в качестве аргумента.</para>
/// </summary>
/// <param name="n">
/// <para>The number of the Catalan number.</para>
/// <para>Номер Числа Катанала.</para>
/// </param>
/// <returns>
/// <para>The Catalan Number with the number specified as an argument.</para>
/// <para>Число Катанала с номером, указанным в качестве аргумента.</para>
/// </returns>
template <typename TLinkAddress>
static constexpr TLinkAddress Catalan(TLinkAddress n)
{
static_assert(std::is_unsigned_v<TLinkAddress>, "TLinkAddress must be an unsigned integer type");
if (n <= MaximumCatalanIndex)
{
return static_cast<TLinkAddress>(_catalans[static_cast<std::size_t>(n)]);
}
else
{
throw std::invalid_argument(std::string("Only numbers from 0 to ").append(Platform::Converters::To<std::string>(MaximumCatalanIndex)).append(" are supported by unsigned integer with 64 bits length."));
{
throw std::out_of_range("Only numbers from 0 to " + std::to_string(MaximumCatalanIndex) + " are supported by unsigned integer with 64 bits length.");
}
}

public: static bool IsPowerOfTwo(std::uint64_t x) { return {x & x - 1} == 0; }

public: template <typename T> static T Abs(T x) { return Math<T>.Abs(x); }

public: template <typename T> static T Negate(T x) { return Math<T>.Negate(x); }

/// <summary>
/// <para>Checks if a number is a power of two.</para>
/// <para>Проверяет, является ли число степенью двойки.</para>
/// </summary>
/// <param name="x">
/// <para>The number to check.</para>
/// <para>Число для проверки.</para>
/// </param>
/// <returns>
/// <para>True if the number is a power of two otherwise false.</para>
/// <para>True, если число является степенью двойки, иначе - false.</para>
/// </returns>
template <typename TLinkAddress>
static constexpr bool IsPowerOfTwo(TLinkAddress x)
{
static_assert(std::is_unsigned_v<TLinkAddress>, "TLinkAddress must be an unsigned integer type");
return x != 0 && (x & (x - 1)) == 0;
}
};
}
2 changes: 1 addition & 1 deletion cpp/Platform.Numbers/Platform.Numbers.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
#include "Bit.h"
//#include "BitExtensions.h"
//#include "Bit[T].h"
//#include "Math.h"
#include "Math.h"
//#include "MathExtensions.h"
//#include "Math[T].h"
Loading
Loading