Skip to content

Commit

Permalink
Developed binary read/write and blocks get/set functionality with cor…
Browse files Browse the repository at this point in the history
…responding testing.
  • Loading branch information
Alvov1 committed Jan 20, 2024
1 parent 7894dc4 commit 99defa4
Show file tree
Hide file tree
Showing 6 changed files with 681 additions and 14 deletions.
102 changes: 91 additions & 11 deletions Aesi.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@ class Aesi final {
/**
* @brief Block line of the number
*/
blockLine blocks {};
blockLine blocks;

/**
* @enum Aesi::Sign
* @brief Specifies sign of the number. Should be Positive, Negative or Zero
*/
enum Sign { Zero = 0, Positive = 1, Negative = 2 } sign { Zero };
enum Sign { Zero = 0, Positive = 1, Negative = 2 } sign;
/* ----------------------------------------------------------------------- */


Expand Down Expand Up @@ -130,7 +130,7 @@ class Aesi final {
/**
* @brief Default constructor
*/
gpu constexpr Aesi() noexcept : blocks{}, sign { Zero } {};
gpu constexpr Aesi() noexcept = default;

/**
* @brief Copy constructor
Expand Down Expand Up @@ -179,7 +179,7 @@ class Aesi final {
* @details Accepts decimal literals along with binary (starting with 0b/0B), octal (0o/0O) and hexadecimal (0x/0X)
*/
template <typename Char> requires (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>)
gpu constexpr Aesi(const Char* ptr, std::size_t size) noexcept : Aesi() {
gpu constexpr Aesi(const Char* ptr, std::size_t size) noexcept : Aesi {} {
if(size == 0) return;

constexpr const Char* characters = [] {
Expand Down Expand Up @@ -248,7 +248,7 @@ class Aesi final {
*/
template <typename String, typename Char = typename String::value_type> requires (std::is_same_v<std::basic_string<Char>,
typename std::decay<String>::type> || std::is_same_v<std::basic_string_view<Char>, typename std::decay<String>::type>)
gpu constexpr Aesi(String&& stringView) noexcept : Aesi(stringView.data(), stringView.size()){}
gpu constexpr Aesi(String&& stringView) noexcept : Aesi(stringView.data(), stringView.size()) {}

/**
* @brief Different precision copy constructor
Expand Down Expand Up @@ -415,14 +415,29 @@ class Aesi final {
return *this;
}

/**
* @brief Integer multiplication.
* @param Aesi left
* @param Aesi right
* @return Product and carry-out by reference
*/
gpu static constexpr auto multiply(const Aesi& left, const Aesi& right, Aesi& product, block& carryOut) noexcept -> void {
if(left.sign == Zero || right.sign == Zero) { product = 0; carryOut = 0; return; }
product.sign = (left.sign != right.sign ? Negative : Positive);


}

/**
* @brief Division operator
* @param Aesi divisor
* @return Aesi
*/
[[nodiscard]]
gpu constexpr auto operator/(const Aesi& divisor) const noexcept -> Aesi {
Aesi quotient, _; divide(*this, divisor, quotient, _); return quotient;
Aesi quotient, _;
divide(*this, divisor, quotient, _);
return quotient;
}

/**
Expand Down Expand Up @@ -797,6 +812,30 @@ class Aesi final {
return (blocks[blockNumber] & (0xffU << shift)) >> shift;
}

/**
* @brief Set block in number by index starting from the right
* @param Size_t index
* @param Block byte
* @note Does nothing for index out of range
*/
gpu constexpr auto setBlock(std::size_t index, block block) noexcept -> void {
if(index >= blocksNumber) return; blocks[index] = block;

if(sign == Zero && block != 0) sign = Positive;
if(sign != Zero && block == 0 && isLineEmpty(blocks)) sign = Zero;
}

/**
* @brief Get block in number by index starting from the right
* @param Size_t index
* @return Block
* @note Returns zero for index out of range
*/
[[nodiscard]]
gpu constexpr auto getBlock(std::size_t index) const noexcept -> block {
if(index >= blocksNumber) return block(); return blocks[index];
}

/**
* @brief Get amount of non-empty bytes in number right to left
* @return Size_t
Expand Down Expand Up @@ -919,8 +958,7 @@ class Aesi final {
const Aesi divAbs = divisor.abs();
const auto ratio = number.abs().compareTo(divAbs);

if(!quotient.isZero()) quotient = Aesi {};
if(!remainder.isZero()) remainder = Aesi {};
quotient = Aesi {}; remainder = Aesi {};

if(ratio == AesiCMP::greater) {
const auto bitsUsed = lineLength(number.blocks) * blockBitLength;
Expand Down Expand Up @@ -950,7 +988,7 @@ class Aesi final {
*/
[[nodiscard]]
gpu static constexpr auto divide(const Aesi& number, const Aesi& divisor) noexcept -> pair<Aesi, Aesi> {
pair<Aesi, Aesi> results = { 0, 0 }; divide(number, divisor, results.first, results.second); return results;
pair<Aesi, Aesi> results; divide(number, divisor, results.first, results.second); return results;
}

/**
Expand Down Expand Up @@ -1084,7 +1122,7 @@ class Aesi final {
*/
template <std::size_t newBitness> requires (newBitness != bitness) [[nodiscard]]
gpu constexpr auto precisionCast() const noexcept -> Aesi<newBitness> {
Aesi<newBitness> result = 0;
Aesi<newBitness> result {};

long long startBlock = (blocksNumber < (newBitness / blockBitLength) ? blocksNumber - 1 : (newBitness / blockBitLength) - 1);
for(; startBlock >= 0; --startBlock) {
Expand All @@ -1096,6 +1134,7 @@ class Aesi final {
return result;
}

/* ----------------- @name Public input-output operators. ---------------- */
/**
* @brief Print number inside C-style array buffer
* @param Byte base TEMPLATE
Expand Down Expand Up @@ -1195,7 +1234,7 @@ class Aesi final {
* @note Works significantly faster for hexadecimal notation
*/
template <typename Char> requires (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>)
friend constexpr auto operator<<(std::basic_ostream<Char>& ss, const Aesi& value) noexcept -> std::basic_ostream<Char>& {
friend constexpr auto operator<<(std::basic_ostream<Char>& ss, const Aesi& value) -> std::basic_ostream<Char>& {
auto flags = ss.flags();

if(value.sign != Zero) {
Expand Down Expand Up @@ -1238,6 +1277,47 @@ class Aesi final {
return ss;
}

/**
* @brief Read a number in binary from an input stream
* @param Istream stream
* @param Boolean big_endian
* @return Aesi
* @details Reads number from stream using .read method. Accepts STD streams based on char or wchar_t.
* @note Fills empty bits with 0s on eof of the stream
*/
template <typename Char> requires (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>)
static constexpr auto readBinary(std::basic_istream<Char>& istream, bool bigEndian = true) -> Aesi {
Aesi result {}; result.sign = Positive;

if(bigEndian) {
for(auto it = result.blocks.rbegin(); it != result.blocks.rend(); ++it)
if(!istream.read(reinterpret_cast<char*>(&*it), sizeof(block))) break;
} else {
for(auto& tBlock: result.blocks)
if(!istream.read(reinterpret_cast<char*>(&tBlock), sizeof(block))) break;
}

return result;
}

/**
* @brief Write a number in binary to the output stream
* @param Ostream stream
* @param Boolean big_endian
* @details Writes number in stream using .write method. Accepts STD streams based on char or wchar_t.
*/
template <typename Char> requires (std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>)
constexpr auto writeBinary(std::basic_ostream<Char>& ostream, bool bigEndian = true) noexcept -> void {
if(bigEndian) {
for(auto& block: blocks)
if(!ostream.write(reinterpret_cast<const char*>(&block), sizeof(block))) break;
} else {
for(auto it = blocks.rbegin(); it != blocks.rend(); ++it)
if(!ostream.write(reinterpret_cast<const char*>(&*it), sizeof(block))) break;
}
}
/* ----------------------------------------------------------------------- */

#ifdef __CUDACC__
/**
* @brief Object assignation using atomic CUDA operations
Expand Down
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,5 @@ std::cout << Aesi<256>::powm(base, power, modulo) << std::endl; // Fine
- Sign in bitwise operators depends on the sign of the first operand.
- The tilde operator (~) does __NOT__ affect the sign of a number.
- Both bitshift operators do not make any effort if the shift value is greater than the bitness of the number. If the shift is negative, the opposite operator is called with the absolute value of the shift.
- Be careful with exponentiation overflow when using the __POWM__ function and similar.
- GetString method for hexadecimal notation returns number representation with letters in __LOWERCASE__.
- Be careful with exponentiation overflow when using the __POWM__ function and similar.
- Both display methods (stream operator, getString()) work significantly faster for hexadecimal notation.
2 changes: 1 addition & 1 deletion test/arithmetic/square-root.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
TEST(SquareRoot, SquareRoot) {
const auto timeStart = std::chrono::system_clock::now();

Aesi512 m {};
Aesi512 m;
m = "6090725157803385683847790262910475439880944489553750045786895303294805776058380471608951628613013763332789951290275640362243141926540167423390151885627587.";
EXPECT_EQ(m.squareRoot(), "78043098079224056927951137119052045281574520557910376004565433003118507400052.");
m = "2198442897630760572542562253325024201444903498242188983498631852277766153592956295915984611974235359574640385959965624634128999962215308936301754007314365.";
Expand Down
Binary file modified test/benchmarks/measures.db
Binary file not shown.
Loading

0 comments on commit 99defa4

Please sign in to comment.