diff --git a/.gitignore b/.gitignore index 7ca511f..a0cc458 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ build/ .cache/ compile_commands.json crash-* +.vs \ No newline at end of file diff --git a/real48.cpp b/real48.cpp new file mode 100644 index 0000000..e88aeb5 --- /dev/null +++ b/real48.cpp @@ -0,0 +1,231 @@ +#include +#include +#include +#include "real48.hpp" + +namespace math +{ +Real48::Real48(const float number) +{ + uint32_t bits = 0; + std::memcpy(&bits, &number, sizeof(bits)); + + const uint64_t sFloat = (bits >> 31) & 1u; + const uint64_t eFloat = (bits >> 23) & 0xFFu; + const uint64_t fFloat = bits & ((1u << 23) - 1u); + + if (eFloat == 0) { + std::memset(real48, 0, 6); + return; + } + + if (eFloat == 0xFF) { + throw std::overflow_error("float inf/nan"); + } + + const uint64_t e_ = eFloat + 2; + if (e_ > 255) { + throw std::overflow_error("float exponent out of range"); + } + + const uint64_t f_ = (uint64_t(fFloat) << 16) & ((1ULL << 39) - 1); + + const uint64_t v48 = (sFloat << 47) | (f_ << 8) | (e_ & 0xFFULL); + + real48[0] = (v48 >> 40) & 0xFF; + real48[1] = (v48 >> 32) & 0xFF; + real48[2] = (v48 >> 24) & 0xFF; + real48[3] = (v48 >> 16) & 0xFF; + real48[4] = (v48 >> 8) & 0xFF; + real48[5] = (v48 >> 0) & 0xFF; +} + +Real48::Real48(const double number) +{ + uint64_t bits = 0; + std::memcpy(&bits, &number, sizeof(bits)); + + const uint64_t sDouble = (bits >> 63) & 1ULL; + const uint64_t eDouble = (bits >> 52) & 0x7FFULL; + const uint64_t fDouble = bits & ((1ULL << 52) - 1ULL); + + if (eDouble == 0) { + std::memset(real48, 0, 6); + return; + } + + if (eDouble == 0x7FF) { + throw std::overflow_error("double inf/nan"); + } + + const uint64_t e_ = eDouble - 894; + + if (e_ < 1 || e_ > 255) { + throw std::overflow_error("double exponent out of range"); + } + + const uint64_t f_ = (fDouble >> 13) & ((1ULL << 39) - 1ULL); + + const uint64_t v48 = (sDouble << 47) | (f_ << 8) | (e_ & 0xFFULL); + + real48[0] = (v48 >> 40) & 0xFF; + real48[1] = (v48 >> 32) & 0xFF; + real48[2] = (v48 >> 24) & 0xFF; + real48[3] = (v48 >> 16) & 0xFF; + real48[4] = (v48 >> 8) & 0xFF; + real48[5] = (v48 >> 0) & 0xFF; +} + +// conversion operators +Real48::operator float() const +{ + auto s_ = s(); + auto e_ = e(); + auto f_ = f(); + + if (e_ == 0) + { + return 0; + } + + if (e_ <= 1) + { + throw std::runtime_error("e_ <= 1"); + } + + uint64_t result = 0; + result |= (s_ << 31); + result |= ((e_ - 2) << 23); + result |= (f_ >> 16); + + float resultFloat; + std::memcpy(&resultFloat, &result, sizeof(float)); + return resultFloat; +} + +Real48::operator double() const noexcept +{ + auto s_ = s(); + auto e_ = e(); + auto f_ = f(); + + if (e_ == 0) + { + return 0; + } + + uint64_t result = 0; + result |= (uint64_t(s_) << 63); + result |= ((uint64_t(e_) + 894) << 52); + result |= (f_ << 13); + + double resultDouble; + std::memcpy(&resultDouble, &result, sizeof(double)); + return resultDouble; +} + +// assignment operators +Real48& Real48::operator+=(const Real48& b) +{ + auto doubleResult = static_cast(*this) + static_cast(b); + *this = Real48(doubleResult); + return *this; +} + +Real48& Real48::operator-=(const Real48& b) +{ + auto doubleResult = static_cast(*this) - static_cast(b); + *this = Real48(doubleResult); + return *this; +} + +Real48& Real48::operator*=(const Real48& b) +{ + auto doubleResult = static_cast(*this) * static_cast(b); + *this = Real48(doubleResult); + return *this; +} + +Real48& Real48::operator/=(const Real48& b) +{ + auto doubleResult = static_cast(*this) / static_cast(b); + *this = Real48(doubleResult); + return *this; +} + +// arithmetic operators +Real48 Real48::operator+() const noexcept +{ + return *this; +} + +Real48 Real48::operator-() const noexcept +{ + Real48 result{*this}; + result.real48[0] ^= 0x80; + return result; +} + +Real48 Real48::operator+(const Real48& o) const +{ + auto doubleResult = static_cast(*this) + static_cast(o); + return Real48(doubleResult); +} + +Real48 Real48::operator-(const Real48& o) const +{ + auto doubleResult = static_cast(*this) - static_cast(o); + return Real48(doubleResult); +} + +Real48 Real48::operator*(const Real48& o) const +{ + auto doubleResult = static_cast(*this) * static_cast(o); + return Real48(doubleResult); +} + +Real48 Real48::operator/(const Real48& o) const +{ + auto doubleResult = static_cast(*this) / static_cast(o); + return Real48(doubleResult); +} + +// comparison operators +bool Real48::operator>(const Real48& o) const noexcept +{ + return (static_cast(*this) > static_cast(o)); +} + +bool Real48::operator<(const Real48& o) const noexcept +{ + return (static_cast(*this) < static_cast(o)); +} + +Real48::Class Real48::Classify() const noexcept +{ + if (e() == 0) + { + return Class::ZERO; + } + return Class::NORMAL; +} + +bool Real48::s() const + { + return (real48[0] >> 7) & 1; + } + + uint8_t Real48::e() const + { + return static_cast(real48[5]); + } + + uint64_t Real48::f() const + { + uint64_t f_ = 0; + for (int i = 0; i < 6; ++i) + f_ = (f_ << 8) | real48[i]; + + return (f_ >> 8) & ((1ULL << 39) - 1); + } +} // namespace math diff --git a/real48.hpp b/real48.hpp index bf21a25..38f75e3 100644 --- a/real48.hpp +++ b/real48.hpp @@ -1,3 +1,8 @@ +#pragma once +#include +#include +#include + namespace math { @@ -5,9 +10,9 @@ class Real48 { public: // constructors - constexpr Real48(); // TODO: add definition - Real48(const float number); - Real48(const double number); + constexpr Real48(): real48{} {}; + explicit Real48(const float number); + explicit Real48(const double number); constexpr Real48(const Real48& o) = default; // conversion operators @@ -42,12 +47,40 @@ class Real48 Class Classify() const noexcept; // limits - consteval static Real48 min(); // TODO: add definition - consteval static Real48 max(); // TODO: add definition - consteval static Real48 epsilon(); // TODO: add definition + consteval static Real48 min() + { + Real48 m{}; + m.real48[5] = 1; + return m; + } + + consteval static Real48 max() + { + Real48 m{}; + m.real48[0] = 0x7F; + m.real48[1] = 0xFF; + m.real48[2] = 0xFF; + m.real48[3] = 0xFF; + m.real48[4] = 0xFF; + m.real48[5] = 0xFF; + return m; + } + + consteval static Real48 epsilon() + { + Real48 eps; + eps.real48[5] = 90; + return eps; + } private: - // TODO: add members + unsigned char real48[6]; + + bool s() const; + + uint8_t e() const; + + uint64_t f() const; }; } // namespace math