From 86b709987f547df002011b93ff4d2aa3e37961a1 Mon Sep 17 00:00:00 2001 From: LegendaV <115637903+LegendaV@users.noreply.github.com> Date: Thu, 22 Jan 2026 17:42:15 +0500 Subject: [PATCH 01/15] real48 --- .gitignore | 1 + real48.cpp | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++++ real48.hpp | 42 +++++++++-- 3 files changed, 252 insertions(+), 5 deletions(-) create mode 100644 real48.cpp 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..41253b5 --- /dev/null +++ b/real48.cpp @@ -0,0 +1,214 @@ +#include +#include +#include "real48.hpp" + +namespace math +{ +Real48::Real48(const float number) +{ + uint64_t bits; + + std::memcpy(&bits, &number, sizeof(float)); + + const uint64_t sFloat = bits >> 31; + const uint64_t eFloat = bits >> 23 & ((1 << 8) - 1); + const uint64_t fFloat = bits & ((1 << 23) - 1); + + if (eFloat == 0) + { + real48[5] = 0; + return; + } + + const uint64_t e = eFloat + 2; + + if (e < 1 || e > 255) { + throw std::overflow_error("e < 1 || e > 255"); + } + + uint64_t result = 0; + result |= (sFloat & 1ULL); + result |= (fFloat & ((1ULL << 39) - 1)) << 1; + result |= (e & 0xFFULL) << 40; + + std::memcpy(real48, &result, 6); +} + +Real48::Real48(const double number) +{ + uint64_t bits; + + std::memcpy(&bits, &number, sizeof(float)); + + const uint64_t sDouble = bits >> 63; + const uint64_t eDouble = bits >> 52 & ((1 << 11) - 1); + const uint64_t fDouble = bits & ((1ll << 52) - 1); + + if (eDouble == 0) + { + real48[5] = 0; + return; + } + + const uint64_t e = eDouble - 894; + + if (e < 1 || e > 255) { + throw std::overflow_error("e < 1 || e > 255"); + } + + uint64_t result = 0; + result |= (sDouble & 1ULL); + result |= (fDouble & ((1ULL << 39) - 1)) << 1; + result |= (e & 0xFFULL) << 40; + + std::memcpy(real48, &result, 6); +} + +// 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 result; +} + +Real48::operator double() const noexcept +{ + auto s_ = s(); + auto e_ = e(); + auto f_ = f(); + + if (e_ == 0) + { + return 0; + } + + uint64_t result = 0; + result |= (s_ << 63); + result |= ((e_ + 894) << 52); + result |= (f_ >> 13); + + double resultDouble; + std::memcpy(&resultDouble, &result, sizeof(double)); + return result; +} + +// 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 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)); +} + +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..fe648d8 100644 --- a/real48.hpp +++ b/real48.hpp @@ -1,3 +1,7 @@ +#pragma once +#include +#include + namespace math { @@ -5,7 +9,7 @@ class Real48 { public: // constructors - constexpr Real48(); // TODO: add definition + constexpr Real48(): real48{} {}; Real48(const float number); Real48(const double number); constexpr Real48(const Real48& o) = default; @@ -42,12 +46,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.data[0] = 0x7F; + m.data[1] = 0xFF; + m.data[2] = 0xFF; + m.data[3] = 0xFF; + m.data[4] = 0xFF; + m.data[5] = 0xFF; + return t; + } + + 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 From 5687e28e893e8d87e8dc7507893eb9ee18330047 Mon Sep 17 00:00:00 2001 From: LegendaV <115637903+LegendaV@users.noreply.github.com> Date: Thu, 22 Jan 2026 17:47:03 +0500 Subject: [PATCH 02/15] fix --- real48.cpp | 1 + real48.hpp | 13 +++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/real48.cpp b/real48.cpp index 41253b5..ceac8d7 100644 --- a/real48.cpp +++ b/real48.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "real48.hpp" namespace math diff --git a/real48.hpp b/real48.hpp index fe648d8..f7ab97f 100644 --- a/real48.hpp +++ b/real48.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include #include namespace math @@ -56,12 +57,12 @@ class Real48 consteval static Real48 max() { Real48 m{}; - m.data[0] = 0x7F; - m.data[1] = 0xFF; - m.data[2] = 0xFF; - m.data[3] = 0xFF; - m.data[4] = 0xFF; - m.data[5] = 0xFF; + 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 t; } From 014aa1e0b292a5b1134d8f71935a1a83a702003a Mon Sep 17 00:00:00 2001 From: LegendaV <115637903+LegendaV@users.noreply.github.com> Date: Thu, 22 Jan 2026 17:54:59 +0500 Subject: [PATCH 03/15] fix --- real48.cpp | 13 +++++++++---- real48.hpp | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/real48.cpp b/real48.cpp index ceac8d7..d42e63c 100644 --- a/real48.cpp +++ b/real48.cpp @@ -104,8 +104,8 @@ Real48::operator double() const noexcept } uint64_t result = 0; - result |= (s_ << 63); - result |= ((e_ + 894) << 52); + result |= (uint64_t(s_) << 63); + result |= ((uint64_t(e_) + 894) << 52); result |= (f_ >> 13); double resultDouble; @@ -148,7 +148,12 @@ Real48 Real48::operator+() const noexcept return *this; } -Real48 Real48::operator-() const noexcept; +Real48 Real48::operator-() const noexcept +{ + Real48 result{*this}; + result.data[5] b |= 0x80; + return result; +} Real48 Real48::operator+(const Real48& o) const { @@ -185,7 +190,7 @@ bool Real48::operator<(const Real48& o) const noexcept return (static_cast(*this) < static_cast(o)); } -Class Real48::Classify() const noexcept +Real48::Class Real48::Classify() const noexcept { if (e() == 0) { diff --git a/real48.hpp b/real48.hpp index f7ab97f..f43f171 100644 --- a/real48.hpp +++ b/real48.hpp @@ -63,7 +63,7 @@ class Real48 m.real48[3] = 0xFF; m.real48[4] = 0xFF; m.real48[5] = 0xFF; - return t; + return m; } consteval static Real48 epsilon() From 4dcb1c53df45f41b052f275a4c5d12ea1e834c0e Mon Sep 17 00:00:00 2001 From: LegendaV <115637903+LegendaV@users.noreply.github.com> Date: Thu, 22 Jan 2026 17:56:28 +0500 Subject: [PATCH 04/15] fix --- real48.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/real48.cpp b/real48.cpp index d42e63c..5aebc57 100644 --- a/real48.cpp +++ b/real48.cpp @@ -151,7 +151,7 @@ Real48 Real48::operator+() const noexcept Real48 Real48::operator-() const noexcept { Real48 result{*this}; - result.data[5] b |= 0x80; + result.real48[5] b |= 0x80; return result; } From 60fedd6914c25cd504e1d86706b9f441882d952d Mon Sep 17 00:00:00 2001 From: LegendaV <115637903+LegendaV@users.noreply.github.com> Date: Thu, 22 Jan 2026 17:57:34 +0500 Subject: [PATCH 05/15] fix --- real48.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/real48.cpp b/real48.cpp index 5aebc57..ed870d0 100644 --- a/real48.cpp +++ b/real48.cpp @@ -151,7 +151,7 @@ Real48 Real48::operator+() const noexcept Real48 Real48::operator-() const noexcept { Real48 result{*this}; - result.real48[5] b |= 0x80; + result.real48[5] |= 0x80; return result; } From ff4b7a81dd7bcb5495d8001a3417e58156aaa7e1 Mon Sep 17 00:00:00 2001 From: LegendaV <115637903+LegendaV@users.noreply.github.com> Date: Thu, 22 Jan 2026 18:00:25 +0500 Subject: [PATCH 06/15] fix --- real48.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/real48.cpp b/real48.cpp index ed870d0..09a9684 100644 --- a/real48.cpp +++ b/real48.cpp @@ -103,6 +103,11 @@ Real48::operator double() const noexcept return 0; } + if (exponent >= 0x7FF) + { + throw std::overflow_error(); + } + uint64_t result = 0; result |= (uint64_t(s_) << 63); result |= ((uint64_t(e_) + 894) << 52); From 5c2243b3219d01cee1d9d09c1661ace9dbd7406d Mon Sep 17 00:00:00 2001 From: LegendaV <115637903+LegendaV@users.noreply.github.com> Date: Thu, 22 Jan 2026 18:01:55 +0500 Subject: [PATCH 07/15] fix --- real48.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/real48.cpp b/real48.cpp index 09a9684..d31a795 100644 --- a/real48.cpp +++ b/real48.cpp @@ -105,7 +105,7 @@ Real48::operator double() const noexcept if (exponent >= 0x7FF) { - throw std::overflow_error(); + throw std::overflow_error("exponent >= 0x7FF"); } uint64_t result = 0; From 81e510ed16b244ea2787c86aa102b37e07d381f3 Mon Sep 17 00:00:00 2001 From: LegendaV <115637903+LegendaV@users.noreply.github.com> Date: Thu, 22 Jan 2026 18:03:00 +0500 Subject: [PATCH 08/15] fix --- real48.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/real48.cpp b/real48.cpp index d31a795..f713330 100644 --- a/real48.cpp +++ b/real48.cpp @@ -103,7 +103,7 @@ Real48::operator double() const noexcept return 0; } - if (exponent >= 0x7FF) + if (e_ >= 0x7FF) { throw std::overflow_error("exponent >= 0x7FF"); } From e1a1cf8a417b5daa17c16f9116f116b93ca30099 Mon Sep 17 00:00:00 2001 From: LegendaV <115637903+LegendaV@users.noreply.github.com> Date: Thu, 22 Jan 2026 18:05:16 +0500 Subject: [PATCH 09/15] fix --- real48.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/real48.cpp b/real48.cpp index f713330..0d2531f 100644 --- a/real48.cpp +++ b/real48.cpp @@ -51,6 +51,11 @@ Real48::Real48(const double number) return; } + if (eDouble >= 0x7FF) + { + throw std::overflow_error("exponent >= 0x7FF"); + } + const uint64_t e = eDouble - 894; if (e < 1 || e > 255) { @@ -103,11 +108,6 @@ Real48::operator double() const noexcept return 0; } - if (e_ >= 0x7FF) - { - throw std::overflow_error("exponent >= 0x7FF"); - } - uint64_t result = 0; result |= (uint64_t(s_) << 63); result |= ((uint64_t(e_) + 894) << 52); From 8298526bf5ce71da61994d19de2afba7cfc7a2d0 Mon Sep 17 00:00:00 2001 From: LegendaV <115637903+LegendaV@users.noreply.github.com> Date: Thu, 22 Jan 2026 18:09:50 +0500 Subject: [PATCH 10/15] fix --- real48.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/real48.cpp b/real48.cpp index 0d2531f..c52cb83 100644 --- a/real48.cpp +++ b/real48.cpp @@ -21,6 +21,11 @@ Real48::Real48(const float number) return; } + if (eFloat >= 0xFF) + { + throw std::overflow_error("eFloat >= 0xFF"); + } + const uint64_t e = eFloat + 2; if (e < 1 || e > 255) { @@ -53,12 +58,12 @@ Real48::Real48(const double number) if (eDouble >= 0x7FF) { - throw std::overflow_error("exponent >= 0x7FF"); + throw std::overflow_error("eDouble >= 0x7FF"); } const uint64_t e = eDouble - 894; - if (e < 1 || e > 255) { + if (e < 1 || e >= 255) { throw std::overflow_error("e < 1 || e > 255"); } From a646dd6341a963415ef6c677e311a8d2e879e244 Mon Sep 17 00:00:00 2001 From: LegendaV <115637903+LegendaV@users.noreply.github.com> Date: Thu, 22 Jan 2026 18:14:20 +0500 Subject: [PATCH 11/15] fix --- real48.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/real48.cpp b/real48.cpp index c52cb83..379e9bb 100644 --- a/real48.cpp +++ b/real48.cpp @@ -44,7 +44,7 @@ Real48::Real48(const double number) { uint64_t bits; - std::memcpy(&bits, &number, sizeof(float)); + std::memcpy(&bits, &number, sizeof(double)); const uint64_t sDouble = bits >> 63; const uint64_t eDouble = bits >> 52 & ((1 << 11) - 1); @@ -99,7 +99,7 @@ Real48::operator float() const float resultFloat; std::memcpy(&resultFloat, &result, sizeof(float)); - return result; + return resultFloat; } Real48::operator double() const noexcept @@ -120,7 +120,7 @@ Real48::operator double() const noexcept double resultDouble; std::memcpy(&resultDouble, &result, sizeof(double)); - return result; + return resultDouble; } // assignment operators From e68f6066d1f23824fba45c1d81060a25235a3650 Mon Sep 17 00:00:00 2001 From: LegendaV <115637903+LegendaV@users.noreply.github.com> Date: Thu, 22 Jan 2026 18:26:27 +0500 Subject: [PATCH 12/15] fix --- real48.cpp | 289 ++++++++++++++++++++--------------------------------- 1 file changed, 109 insertions(+), 180 deletions(-) diff --git a/real48.cpp b/real48.cpp index 379e9bb..394c0c9 100644 --- a/real48.cpp +++ b/real48.cpp @@ -1,230 +1,159 @@ #include -#include #include +#include +#include #include "real48.hpp" -namespace math -{ -Real48::Real48(const float number) -{ - uint64_t bits; - - std::memcpy(&bits, &number, sizeof(float)); - - const uint64_t sFloat = bits >> 31; - const uint64_t eFloat = bits >> 23 & ((1 << 8) - 1); - const uint64_t fFloat = bits & ((1 << 23) - 1); - - if (eFloat == 0) - { - real48[5] = 0; - return; - } - - if (eFloat >= 0xFF) - { - throw std::overflow_error("eFloat >= 0xFF"); - } - - const uint64_t e = eFloat + 2; - - if (e < 1 || e > 255) { - throw std::overflow_error("e < 1 || e > 255"); - } +namespace math { - uint64_t result = 0; - result |= (sFloat & 1ULL); - result |= (fFloat & ((1ULL << 39) - 1)) << 1; - result |= (e & 0xFFULL) << 40; +static inline void store_u48_be(unsigned char out[6], uint64_t v48) { + out[0] = (v48 >> 40) & 0xFF; + out[1] = (v48 >> 32) & 0xFF; + out[2] = (v48 >> 24) & 0xFF; + out[3] = (v48 >> 16) & 0xFF; + out[4] = (v48 >> 8) & 0xFF; + out[5] = (v48 >> 0) & 0xFF; +} - std::memcpy(real48, &result, 6); +static inline uint64_t load_u48_be(const unsigned char in[6]) { + uint64_t v = 0; + v |= uint64_t(in[0]) << 40; + v |= uint64_t(in[1]) << 32; + v |= uint64_t(in[2]) << 24; + v |= uint64_t(in[3]) << 16; + v |= uint64_t(in[4]) << 8; + v |= uint64_t(in[5]) << 0; + return v; } -Real48::Real48(const double number) -{ - uint64_t bits; +Real48::Real48(const float number) { + if (number == 0.0f) { + std::memset(real48, 0, 6); + return; + } + if (!std::isfinite(number)) { + throw std::overflow_error("float is not finite"); + } - std::memcpy(&bits, &number, sizeof(double)); + uint32_t bits = 0; + std::memcpy(&bits, &number, sizeof(bits)); - const uint64_t sDouble = bits >> 63; - const uint64_t eDouble = bits >> 52 & ((1 << 11) - 1); - const uint64_t fDouble = bits & ((1ll << 52) - 1); + const uint64_t sFloat = (bits >> 31) & 1u; + const uint64_t eFloat = (bits >> 23) & 0xFFu; + const uint64_t fFloat = bits & ((1u << 23) - 1u); - if (eDouble == 0) - { - real48[5] = 0; + if (eFloat == 0) { + std::memset(real48, 0, 6); return; } - - if (eDouble >= 0x7FF) - { - throw std::overflow_error("eDouble >= 0x7FF"); + if (eFloat == 0xFF) { + throw std::overflow_error("float inf/nan"); } - const uint64_t e = eDouble - 894; - - if (e < 1 || e >= 255) { - throw std::overflow_error("e < 1 || e > 255"); + const uint64_t e = eFloat + 2; + if (e < 1 || e > 255) { + throw std::overflow_error("float exponent out of range"); } - uint64_t result = 0; - result |= (sDouble & 1ULL); - result |= (fDouble & ((1ULL << 39) - 1)) << 1; - result |= (e & 0xFFULL) << 40; + const uint64_t f = (fFloat << 16) & ((1ULL << 39) - 1); - std::memcpy(real48, &result, 6); + const uint64_t v48 = (sFloat << 47) | (f << 8) | (e & 0xFF); + store_u48_be(real48, v48); } -// conversion operators -Real48::operator float() const -{ - auto s_ = s(); - auto e_ = e(); - auto f_ = f(); - - if (e_ == 0) - { - return 0; +Real48::Real48(const double number) { + if (number == 0.0) { + std::memset(real48, 0, 6); + return; } - - if (e_ <= 1) - { - throw std::runtime_error("e_ <= 1"); + if (!std::isfinite(number)) { + throw std::overflow_error("double is not finite"); } - uint64_t result = 0; - result |= (s_ << 31); - result |= ((e_ - 2) << 23); - result |= (f_ >> 16); + uint64_t bits = 0; + std::memcpy(&bits, &number, sizeof(bits)); - float resultFloat; - std::memcpy(&resultFloat, &result, sizeof(float)); - return resultFloat; -} + const uint64_t sDouble = (bits >> 63) & 1ULL; + const uint64_t eDouble = (bits >> 52) & 0x7FFULL; + const uint64_t fDouble = bits & ((1ULL << 52) - 1); -Real48::operator double() const noexcept -{ - auto s_ = s(); - auto e_ = e(); - auto f_ = f(); + if (eDouble == 0) { + std::memset(real48, 0, 6); + return; + } + if (eDouble == 0x7FF) { + throw std::overflow_error("double inf/nan"); + } - if (e_ == 0) - { - return 0; + const uint64_t e = eDouble - 894; + if (e < 1 || e > 255) { + throw std::overflow_error("double exponent out of range"); } - uint64_t result = 0; - result |= (uint64_t(s_) << 63); - result |= ((uint64_t(e_) + 894) << 52); - result |= (f_ >> 13); + const uint64_t f = (fDouble >> 13) & ((1ULL << 39) - 1); - double resultDouble; - std::memcpy(&resultDouble, &result, sizeof(double)); - return resultDouble; + const uint64_t v48 = (sDouble << 47) | (f << 8) | (e & 0xFF); + store_u48_be(real48, v48); } -// assignment operators -Real48& Real48::operator+=(const Real48& b) -{ - auto doubleResult = static_cast(*this) + static_cast(b); - *this = Real48(doubleResult); - return *this; -} +Real48::operator float() const { + const uint64_t sign = s() ? 1ULL : 0ULL; + const uint64_t exp = e(); + const uint64_t frac = f(); -Real48& Real48::operator-=(const Real48& b) -{ - auto doubleResult = static_cast(*this) - static_cast(b); - *this = Real48(doubleResult); - return *this; -} + if (exp == 0) return 0.0f; -Real48& Real48::operator*=(const Real48& b) -{ - auto doubleResult = static_cast(*this) * static_cast(b); - *this = Real48(doubleResult); - return *this; -} + const uint64_t eFloat = exp - 2; + if (eFloat == 0 || eFloat >= 0xFF) { + throw std::overflow_error("cannot convert to float"); + } -Real48& Real48::operator/=(const Real48& b) -{ - auto doubleResult = static_cast(*this) / static_cast(b); - *this = Real48(doubleResult); - return *this; -} + const uint32_t bits = + (uint32_t(sign) << 31) | + (uint32_t(eFloat) << 23) | + uint32_t((frac >> 16) & ((1ULL << 23) - 1)); -// arithmetic operators -Real48 Real48::operator+() const noexcept -{ - return *this; + float out; + std::memcpy(&out, &bits, sizeof(out)); + return out; } -Real48 Real48::operator-() const noexcept -{ - Real48 result{*this}; - result.real48[5] |= 0x80; - return result; -} +Real48::operator double() const noexcept { + const uint64_t sign = s() ? 1ULL : 0ULL; + const uint64_t exp = e(); + const uint64_t frac = f(); -Real48 Real48::operator+(const Real48& o) const -{ - auto doubleResult = static_cast(*this) + static_cast(o); - return Real48(doubleResult); -} + if (exp == 0) return 0.0; -Real48 Real48::operator-(const Real48& o) const -{ - auto doubleResult = static_cast(*this) - static_cast(o); - return Real48(doubleResult); -} + const uint64_t eDouble = exp + 894; -Real48 Real48::operator*(const Real48& o) const -{ - auto doubleResult = static_cast(*this) * static_cast(o); - return Real48(doubleResult); -} + const uint64_t bits = + (sign << 63) | + (eDouble << 52) | + ((frac & ((1ULL << 39) - 1)) << 13); -Real48 Real48::operator/(const Real48& o) const -{ - auto doubleResult = static_cast(*this) / static_cast(o); - return Real48(doubleResult); + double out; + std::memcpy(&out, &bits, sizeof(out)); + return out; } -// comparison operators -bool Real48::operator>(const Real48& o) const noexcept -{ - return (static_cast(*this) > static_cast(o)); +Real48 Real48::operator-() const noexcept { + Real48 r{*this}; + r.real48[0] ^= 0x80; + return r; } -bool Real48::operator<(const Real48& o) const noexcept -{ - return (static_cast(*this) < static_cast(o)); +bool Real48::s() const { + return (real48[0] & 0x80) != 0; } -Real48::Class Real48::Classify() const noexcept -{ - if (e() == 0) - { - return Class::ZERO; - } - return Class::NORMAL; +uint8_t Real48::e() const { + return static_cast(real48[5]); } -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]; +uint64_t Real48::f() const { + const uint64_t v48 = load_u48_be(real48); + return (v48 >> 8) & ((1ULL << 39) - 1); +} - return (f >> 8) & ((1ULL << 39) - 1); - } -} // namespace math +} // namespace math \ No newline at end of file From 884127867e3c1a0df632af5401eebd77ecb7fac5 Mon Sep 17 00:00:00 2001 From: LegendaV <115637903+LegendaV@users.noreply.github.com> Date: Thu, 22 Jan 2026 18:35:16 +0500 Subject: [PATCH 13/15] fix --- real48.cpp | 250 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 161 insertions(+), 89 deletions(-) diff --git a/real48.cpp b/real48.cpp index 394c0c9..d064f6d 100644 --- a/real48.cpp +++ b/real48.cpp @@ -1,40 +1,12 @@ #include -#include #include -#include +#include #include "real48.hpp" -namespace math { - -static inline void store_u48_be(unsigned char out[6], uint64_t v48) { - out[0] = (v48 >> 40) & 0xFF; - out[1] = (v48 >> 32) & 0xFF; - out[2] = (v48 >> 24) & 0xFF; - out[3] = (v48 >> 16) & 0xFF; - out[4] = (v48 >> 8) & 0xFF; - out[5] = (v48 >> 0) & 0xFF; -} - -static inline uint64_t load_u48_be(const unsigned char in[6]) { - uint64_t v = 0; - v |= uint64_t(in[0]) << 40; - v |= uint64_t(in[1]) << 32; - v |= uint64_t(in[2]) << 24; - v |= uint64_t(in[3]) << 16; - v |= uint64_t(in[4]) << 8; - v |= uint64_t(in[5]) << 0; - return v; -} - -Real48::Real48(const float number) { - if (number == 0.0f) { - std::memset(real48, 0, 6); - return; - } - if (!std::isfinite(number)) { - throw std::overflow_error("float is not finite"); - } - +namespace math +{ +Real48::Real48(const float number) +{ uint32_t bits = 0; std::memcpy(&bits, &number, sizeof(bits)); @@ -46,6 +18,7 @@ Real48::Real48(const float number) { std::memset(real48, 0, 6); return; } + if (eFloat == 0xFF) { throw std::overflow_error("float inf/nan"); } @@ -55,105 +28,204 @@ Real48::Real48(const float number) { throw std::overflow_error("float exponent out of range"); } - const uint64_t f = (fFloat << 16) & ((1ULL << 39) - 1); + const uint64_t f = (uint64_t(fFloat) << 16) & ((1ULL << 39) - 1); - const uint64_t v48 = (sFloat << 47) | (f << 8) | (e & 0xFF); - store_u48_be(real48, v48); -} + const uint64_t v48 = (sFloat << 47) | (f << 8) | (e & 0xFFULL); -Real48::Real48(const double number) { - if (number == 0.0) { - std::memset(real48, 0, 6); - return; - } - if (!std::isfinite(number)) { - throw std::overflow_error("double is not finite"); - } + 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) - 1); + 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) - 1); + const uint64_t f = (fDouble >> 13) & ((1ULL << 39) - 1ULL); - const uint64_t v48 = (sDouble << 47) | (f << 8) | (e & 0xFF); - store_u48_be(real48, v48); + 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; } -Real48::operator float() const { - const uint64_t sign = s() ? 1ULL : 0ULL; - const uint64_t exp = e(); - const uint64_t frac = f(); +// 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); - if (exp == 0) return 0.0f; + float resultFloat; + std::memcpy(&resultFloat, &result, sizeof(float)); + return resultFloat; +} + +Real48::operator double() const noexcept +{ + auto s_ = s(); + auto e_ = e(); + auto f_ = f(); - const uint64_t eFloat = exp - 2; - if (eFloat == 0 || eFloat >= 0xFF) { - throw std::overflow_error("cannot convert to float"); + if (e_ == 0) + { + return 0; } - const uint32_t bits = - (uint32_t(sign) << 31) | - (uint32_t(eFloat) << 23) | - uint32_t((frac >> 16) & ((1ULL << 23) - 1)); + 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; +} - float out; - std::memcpy(&out, &bits, sizeof(out)); - return out; +Real48& Real48::operator/=(const Real48& b) +{ + auto doubleResult = static_cast(*this) / static_cast(b); + *this = Real48(doubleResult); + return *this; } -Real48::operator double() const noexcept { - const uint64_t sign = s() ? 1ULL : 0ULL; - const uint64_t exp = e(); - const uint64_t frac = f(); +// arithmetic operators +Real48 Real48::operator+() const noexcept +{ + return *this; +} - if (exp == 0) return 0.0; +Real48 Real48::operator-() const noexcept +{ + Real48 result{*this}; + result.real48[0] ^= 0x01; + return result; +} - const uint64_t eDouble = exp + 894; +Real48 Real48::operator+(const Real48& o) const +{ + auto doubleResult = static_cast(*this) + static_cast(o); + return Real48(doubleResult); +} - const uint64_t bits = - (sign << 63) | - (eDouble << 52) | - ((frac & ((1ULL << 39) - 1)) << 13); +Real48 Real48::operator-(const Real48& o) const +{ + auto doubleResult = static_cast(*this) - static_cast(o); + return Real48(doubleResult); +} - double out; - std::memcpy(&out, &bits, sizeof(out)); - return out; +Real48 Real48::operator*(const Real48& o) const +{ + auto doubleResult = static_cast(*this) * static_cast(o); + return Real48(doubleResult); } -Real48 Real48::operator-() const noexcept { - Real48 r{*this}; - r.real48[0] ^= 0x80; - return r; +Real48 Real48::operator/(const Real48& o) const +{ + auto doubleResult = static_cast(*this) / static_cast(o); + return Real48(doubleResult); } -bool Real48::s() const { - return (real48[0] & 0x80) != 0; +// comparison operators +bool Real48::operator>(const Real48& o) const noexcept +{ + return (static_cast(*this) > static_cast(o)); } -uint8_t Real48::e() const { - return static_cast(real48[5]); +bool Real48::operator<(const Real48& o) const noexcept +{ + return (static_cast(*this) < static_cast(o)); } -uint64_t Real48::f() const { - const uint64_t v48 = load_u48_be(real48); - return (v48 >> 8) & ((1ULL << 39) - 1); +Real48::Class Real48::Classify() const noexcept +{ + if (e() == 0) + { + return Class::ZERO; + } + return Class::NORMAL; } -} // namespace math \ No newline at end of file +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 From cf4260765bdec33beba43d29ace6b0cbb9e36d7b Mon Sep 17 00:00:00 2001 From: LegendaV <115637903+LegendaV@users.noreply.github.com> Date: Thu, 22 Jan 2026 18:39:28 +0500 Subject: [PATCH 14/15] fix --- real48.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/real48.cpp b/real48.cpp index d064f6d..6e0cbae 100644 --- a/real48.cpp +++ b/real48.cpp @@ -162,7 +162,7 @@ Real48 Real48::operator+() const noexcept Real48 Real48::operator-() const noexcept { Real48 result{*this}; - result.real48[0] ^= 0x01; + result.real48[0] ^= 0x80; return result; } From 4ac0f70925d38dcb3fd81bc90a5e2ef2377e6bf2 Mon Sep 17 00:00:00 2001 From: LegendaV <115637903+LegendaV@users.noreply.github.com> Date: Sat, 24 Jan 2026 17:55:52 +0500 Subject: [PATCH 15/15] fix --- real48.cpp | 22 +++++++++++----------- real48.hpp | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/real48.cpp b/real48.cpp index 6e0cbae..e88aeb5 100644 --- a/real48.cpp +++ b/real48.cpp @@ -23,14 +23,14 @@ Real48::Real48(const float number) throw std::overflow_error("float inf/nan"); } - const uint64_t e = eFloat + 2; - if (e < 1 || e > 255) { + 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 f_ = (uint64_t(fFloat) << 16) & ((1ULL << 39) - 1); - const uint64_t v48 = (sFloat << 47) | (f << 8) | (e & 0xFFULL); + const uint64_t v48 = (sFloat << 47) | (f_ << 8) | (e_ & 0xFFULL); real48[0] = (v48 >> 40) & 0xFF; real48[1] = (v48 >> 32) & 0xFF; @@ -58,15 +58,15 @@ Real48::Real48(const double number) throw std::overflow_error("double inf/nan"); } - const uint64_t e = eDouble - 894; + const uint64_t e_ = eDouble - 894; - if (e < 1 || e > 255) { + 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 f_ = (fDouble >> 13) & ((1ULL << 39) - 1ULL); - const uint64_t v48 = (sDouble << 47) | (f << 8) | (e & 0xFFULL); + const uint64_t v48 = (sDouble << 47) | (f_ << 8) | (e_ & 0xFFULL); real48[0] = (v48 >> 40) & 0xFF; real48[1] = (v48 >> 32) & 0xFF; @@ -222,10 +222,10 @@ bool Real48::s() const uint64_t Real48::f() const { - uint64_t f = 0; + uint64_t f_ = 0; for (int i = 0; i < 6; ++i) - f = (f << 8) | real48[i]; + f_ = (f_ << 8) | real48[i]; - return (f >> 8) & ((1ULL << 39) - 1); + return (f_ >> 8) & ((1ULL << 39) - 1); } } // namespace math diff --git a/real48.hpp b/real48.hpp index f43f171..38f75e3 100644 --- a/real48.hpp +++ b/real48.hpp @@ -11,8 +11,8 @@ class Real48 public: // constructors constexpr Real48(): real48{} {}; - Real48(const float number); - Real48(const double number); + explicit Real48(const float number); + explicit Real48(const double number); constexpr Real48(const Real48& o) = default; // conversion operators