diff options
Diffstat (limited to 'Userland/Applications')
-rw-r--r-- | Userland/Applications/Calculator/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Userland/Applications/Calculator/Calculator.cpp | 54 | ||||
-rw-r--r-- | Userland/Applications/Calculator/Calculator.h | 26 | ||||
-rw-r--r-- | Userland/Applications/Calculator/CalculatorWidget.cpp | 24 | ||||
-rw-r--r-- | Userland/Applications/Calculator/CalculatorWidget.h | 4 | ||||
-rw-r--r-- | Userland/Applications/Calculator/Keypad.cpp | 122 | ||||
-rw-r--r-- | Userland/Applications/Calculator/Keypad.h | 19 | ||||
-rw-r--r-- | Userland/Applications/Calculator/KeypadValue.cpp | 162 | ||||
-rw-r--r-- | Userland/Applications/Calculator/KeypadValue.h | 48 | ||||
-rw-r--r-- | Userland/Applications/Calculator/main.cpp | 11 |
10 files changed, 110 insertions, 361 deletions
diff --git a/Userland/Applications/Calculator/CMakeLists.txt b/Userland/Applications/Calculator/CMakeLists.txt index 74a3d9a58c..8584cd905b 100644 --- a/Userland/Applications/Calculator/CMakeLists.txt +++ b/Userland/Applications/Calculator/CMakeLists.txt @@ -10,7 +10,6 @@ set(SOURCES Calculator.cpp CalculatorWidget.cpp Keypad.cpp - KeypadValue.cpp CalculatorGML.h ) diff --git a/Userland/Applications/Calculator/Calculator.cpp b/Userland/Applications/Calculator/Calculator.cpp index e5865d94f9..451aa5ea01 100644 --- a/Userland/Applications/Calculator/Calculator.cpp +++ b/Userland/Applications/Calculator/Calculator.cpp @@ -6,13 +6,13 @@ */ #include "Calculator.h" -#include "KeypadValue.h" #include <AK/Assertions.h> #include <AK/Math.h> +#include <LibCrypto/BigFraction/BigFraction.h> -KeypadValue Calculator::begin_operation(Operation operation, KeypadValue argument) +Crypto::BigFraction Calculator::begin_operation(Operation operation, Crypto::BigFraction argument) { - KeypadValue res = 0; + Crypto::BigFraction res {}; switch (operation) { case Operation::None: @@ -27,7 +27,7 @@ KeypadValue Calculator::begin_operation(Operation operation, KeypadValue argumen return argument; case Operation::Sqrt: - if (argument < 0) { + if (argument < Crypto::BigFraction {}) { m_has_error = true; return argument; } @@ -35,7 +35,7 @@ KeypadValue Calculator::begin_operation(Operation operation, KeypadValue argumen clear_operation(); break; case Operation::Inverse: - if (argument == 0) { + if (argument == Crypto::BigFraction {}) { m_has_error = true; return argument; } @@ -43,14 +43,14 @@ KeypadValue Calculator::begin_operation(Operation operation, KeypadValue argumen clear_operation(); break; case Operation::Percent: - res = argument * KeypadValue { 1, 2 }; // also known as `KeypadValue{0.01}` + res = argument * Crypto::BigFraction { 1, 100 }; break; case Operation::ToggleSign: res = -argument; break; case Operation::MemClear: - m_mem = 0; + m_mem.set_to_0(); res = argument; break; case Operation::MemRecall: @@ -66,15 +66,12 @@ KeypadValue Calculator::begin_operation(Operation operation, KeypadValue argumen break; } - if (should_be_rounded(res)) - round(res); - return res; } -KeypadValue Calculator::finish_operation(KeypadValue argument) +Crypto::BigFraction Calculator::finish_operation(Crypto::BigFraction argument) { - KeypadValue res = 0; + Crypto::BigFraction res {}; switch (m_operation_in_progress) { case Operation::None: @@ -90,7 +87,7 @@ KeypadValue Calculator::finish_operation(KeypadValue argument) res = m_saved_argument * argument; break; case Operation::Divide: - if (argument == 0) { + if (argument == Crypto::BigFraction {}) { m_has_error = true; return argument; } @@ -108,9 +105,6 @@ KeypadValue Calculator::finish_operation(KeypadValue argument) VERIFY_NOT_REACHED(); } - if (should_be_rounded(res)) - round(res); - clear_operation(); return res; } @@ -118,32 +112,6 @@ KeypadValue Calculator::finish_operation(KeypadValue argument) void Calculator::clear_operation() { m_operation_in_progress = Operation::None; - m_saved_argument = 0; + m_saved_argument.set_to_0(); clear_error(); } - -bool Calculator::should_be_rounded(KeypadValue value) -{ - // We check if pow(10, value.m_decimal_places) overflow. - // If it does, the value can't be displayed (and provoke a division by zero), see Keypad::set_value() - // For u64, the threshold is 19 - return value.m_decimal_places > rounding_threshold; -} - -void Calculator::round(KeypadValue& value) -{ - while (value.m_decimal_places > rounding_threshold) { - bool const need_increment = value.m_value % 10 > 4; - - value.m_value /= 10; - if (need_increment) - value.m_value++; - - value.m_decimal_places--; - - if (value.m_value == 0) { - value = 0; - return; - } - } -} diff --git a/Userland/Applications/Calculator/Calculator.h b/Userland/Applications/Calculator/Calculator.h index bbfcac5546..5d995bf7e1 100644 --- a/Userland/Applications/Calculator/Calculator.h +++ b/Userland/Applications/Calculator/Calculator.h @@ -7,7 +7,7 @@ #pragma once -#include "KeypadValue.h" +#include <LibCrypto/BigFraction/BigFraction.h> // This type implements the regular calculator // behavior, such as performing arithmetic @@ -39,8 +39,8 @@ public: MemAdd }; - KeypadValue begin_operation(Operation, KeypadValue); - KeypadValue finish_operation(KeypadValue); + Crypto::BigFraction begin_operation(Operation, Crypto::BigFraction); + Crypto::BigFraction finish_operation(Crypto::BigFraction); bool has_error() const { return m_has_error; } @@ -48,24 +48,8 @@ public: void clear_error() { m_has_error = false; } private: - static bool should_be_rounded(KeypadValue); - static void round(KeypadValue&); - - static constexpr auto rounding_threshold = []() consteval - { - using used_type = u64; - - auto count = 1; - used_type res = 10; - while (!__builtin_mul_overflow(res, (used_type)10, &res)) { - count++; - } - return count; - } - (); - Operation m_operation_in_progress { Operation::None }; - KeypadValue m_saved_argument { (i64)0 }; - KeypadValue m_mem { (i64)0 }; + Crypto::BigFraction m_saved_argument {}; + Crypto::BigFraction m_mem {}; bool m_has_error { false }; }; diff --git a/Userland/Applications/Calculator/CalculatorWidget.cpp b/Userland/Applications/Calculator/CalculatorWidget.cpp index 887fd8fcb0..cfe111fe38 100644 --- a/Userland/Applications/Calculator/CalculatorWidget.cpp +++ b/Userland/Applications/Calculator/CalculatorWidget.cpp @@ -8,9 +8,9 @@ */ #include "CalculatorWidget.h" -#include "KeypadValue.h" #include <Applications/Calculator/CalculatorGML.h> #include <LibCore/Event.h> +#include <LibCrypto/BigFraction/BigFraction.h> #include <LibGUI/Button.h> #include <LibGUI/Label.h> #include <LibGUI/TextBox.h> @@ -50,14 +50,14 @@ CalculatorWidget::CalculatorWidget() m_clear_button = *find_descendant_of_type_named<GUI::Button>("clear_button"); m_clear_button->on_click = [this](auto) { - m_keypad.set_value(0.0); + m_keypad.set_to_0(); m_calculator.clear_operation(); update_display(); }; m_clear_error_button = *find_descendant_of_type_named<GUI::Button>("clear_error_button"); m_clear_error_button->on_click = [this](auto) { - m_keypad.set_value(0.0); + m_keypad.set_to_0(); update_display(); }; @@ -99,18 +99,18 @@ CalculatorWidget::CalculatorWidget() m_equals_button = *find_descendant_of_type_named<GUI::Button>("equal_button"); m_equals_button->on_click = [this](auto) { - KeypadValue argument = m_keypad.value(); - KeypadValue res = m_calculator.finish_operation(argument); - m_keypad.set_value(res); + Crypto::BigFraction argument = m_keypad.value(); + Crypto::BigFraction res = m_calculator.finish_operation(move(argument)); + m_keypad.set_value(move(res)); update_display(); }; } void CalculatorWidget::perform_operation(Calculator::Operation operation) { - KeypadValue argument = m_keypad.value(); - KeypadValue res = m_calculator.begin_operation(operation, argument); - m_keypad.set_value(res); + Crypto::BigFraction argument = m_keypad.value(); + Crypto::BigFraction res = m_calculator.begin_operation(operation, move(argument)); + m_keypad.set_value(move(res)); update_display(); } @@ -134,9 +134,9 @@ String CalculatorWidget::get_entry() return m_entry->text(); } -void CalculatorWidget::set_entry(KeypadValue value) +void CalculatorWidget::set_entry(Crypto::BigFraction value) { - m_keypad.set_value(value); + m_keypad.set_value(move(value)); update_display(); } @@ -167,7 +167,7 @@ void CalculatorWidget::keydown_event(GUI::KeyEvent& event) m_keypad.type_decimal_point(); mimic_pressed_button(m_decimal_point_button); } else if (event.key() == KeyCode::Key_Escape || event.key() == KeyCode::Key_Delete) { - m_keypad.set_value(0.0); + m_keypad.set_to_0(); m_calculator.clear_operation(); mimic_pressed_button(m_clear_button); } else if (event.key() == KeyCode::Key_Backspace) { diff --git a/Userland/Applications/Calculator/CalculatorWidget.h b/Userland/Applications/Calculator/CalculatorWidget.h index 282be01193..07845cd3df 100644 --- a/Userland/Applications/Calculator/CalculatorWidget.h +++ b/Userland/Applications/Calculator/CalculatorWidget.h @@ -10,8 +10,8 @@ #include "Calculator.h" #include "Keypad.h" -#include "KeypadValue.h" #include <AK/Vector.h> +#include <LibCrypto/BigFraction/BigFraction.h> #include <LibGUI/Widget.h> class CalculatorWidget final : public GUI::Widget { @@ -19,7 +19,7 @@ class CalculatorWidget final : public GUI::Widget { public: virtual ~CalculatorWidget() override = default; String get_entry(); - void set_entry(KeypadValue); + void set_entry(Crypto::BigFraction); private: CalculatorWidget(); diff --git a/Userland/Applications/Calculator/Keypad.cpp b/Userland/Applications/Calculator/Keypad.cpp index b600237929..b94fd79e2d 100644 --- a/Userland/Applications/Calculator/Keypad.cpp +++ b/Userland/Applications/Calculator/Keypad.cpp @@ -7,38 +7,31 @@ */ #include "Keypad.h" -#include "KeypadValue.h" -#include <AK/IntegralMath.h> #include <AK/StringBuilder.h> +#include <LibCrypto/BigFraction/BigFraction.h> +#include <LibCrypto/BigInt/UnsignedBigInteger.h> +#include <LibCrypto/NumberTheory/ModularFunctions.h> void Keypad::type_digit(int digit) { - u64 previous_value = 0; switch (m_state) { case State::External: m_state = State::TypingInteger; - m_negative = false; m_int_value = digit; - m_frac_value = 0; - m_frac_length = 0; + m_frac_value.set_to_0(); + m_frac_length.set_to_0(); break; case State::TypingInteger: - VERIFY(m_frac_value.value() == 0); + VERIFY(m_frac_value == 0); VERIFY(m_frac_length == 0); - previous_value = m_int_value.value(); - m_int_value *= 10; - m_int_value += digit; - if (m_int_value.has_overflow()) - m_int_value = previous_value; + m_int_value.set_to(m_int_value.multiplied_by(10)); + m_int_value.set_to(m_int_value.plus(digit)); break; case State::TypingDecimal: - previous_value = m_frac_value.value(); - m_frac_value *= 10; - m_frac_value += digit; - if (m_frac_value.has_overflow()) - m_frac_value = previous_value; - else - m_frac_length++; + m_frac_value.set_to(m_frac_value.multiplied_by(10)); + m_frac_value.set_to(m_frac_value.plus(digit)); + + m_frac_length.set_to(m_frac_length.plus(1)); break; } } @@ -47,14 +40,13 @@ void Keypad::type_decimal_point() { switch (m_state) { case State::External: - m_negative = false; - m_int_value = 0; - m_frac_value = 0; - m_frac_length = 0; + m_int_value.set_to_0(); + m_frac_value.set_to_0(); + m_frac_length.set_to_0(); m_state = State::TypingDecimal; break; case State::TypingInteger: - VERIFY(m_frac_value.value() == 0); + VERIFY(m_frac_value == 0); VERIFY(m_frac_length == 0); m_state = State::TypingDecimal; break; @@ -68,70 +60,78 @@ void Keypad::type_backspace() { switch (m_state) { case State::External: - m_negative = false; - m_int_value = 0; - m_frac_value = 0; - m_frac_length = 0; + m_int_value.set_to_0(); + m_frac_value.set_to_0(); + m_frac_length.set_to_0(); break; case State::TypingDecimal: if (m_frac_length > 0) { - m_frac_value /= 10; - m_frac_length--; + m_frac_value.set_to(m_frac_value.divided_by(10).quotient); + m_frac_length.set_to(m_frac_length.minus(1)); break; } - VERIFY(m_frac_value.value() == 0); + VERIFY(m_frac_value == 0); m_state = State::TypingInteger; [[fallthrough]]; case State::TypingInteger: - VERIFY(m_frac_value.value() == 0); + VERIFY(m_frac_value == 0); VERIFY(m_frac_length == 0); - m_int_value /= 10; - if (m_int_value.value() == 0) - m_negative = false; + m_int_value.set_to(m_int_value.divided_by(10).quotient); break; } } -KeypadValue Keypad::value() const +Crypto::BigFraction Keypad::value() const { - KeypadValue frac_part = { (i64)m_frac_value.value(), m_frac_length }; - KeypadValue int_part = { (i64)m_int_value.value() }; - KeypadValue res = int_part + frac_part; - if (m_negative) - res = -res; - return res; + if (m_state != State::External) { + Crypto::SignedBigInteger sum { m_int_value.multiplied_by(Crypto::NumberTheory::Power("10"_bigint, m_frac_length)).plus(m_frac_value) }; + Crypto::BigFraction res { move(sum), Crypto::NumberTheory::Power("10"_bigint, m_frac_length) }; + + m_internal_value = move(res); + } + + return m_internal_value; } -void Keypad::set_value(KeypadValue value) +void Keypad::set_value(Crypto::BigFraction value) { m_state = State::External; - if (value.m_value < 0) { - m_negative = true; - value = -value; - } else - m_negative = false; + m_internal_value = move(value); +} + +void Keypad::set_to_0() +{ + m_int_value.set_to_0(); + m_frac_value.set_to_0(); + m_frac_length.set_to_0(); - m_int_value = value.m_value / AK::pow<u64>(10, value.m_decimal_places); - m_frac_value = value.m_value % AK::pow<u64>(10, value.m_decimal_places); - m_frac_length = value.m_decimal_places; + m_internal_value.set_to_0(); + + m_state = State::External; } String Keypad::to_string() const { + // TODO: Implement custom rounding length in the calculator. + constexpr auto maximum_precision = 6; + if (m_state == State::External) + return m_internal_value.to_string(maximum_precision); + StringBuilder builder; - if (m_negative) - builder.append('-'); - builder.appendff("{}", m_int_value.value()); - // NOTE: This is so the decimal point appears on screen as soon as you type it. - if (m_frac_length > 0 || m_state == State::TypingDecimal) - builder.append('.'); + String const integer_value = m_int_value.to_base(10); + String const frac_value = m_frac_value.to_base(10); + unsigned const number_pre_zeros = m_frac_length.to_u64() - (frac_value.length() - 1) - (frac_value == "0" ? 0 : 1); + + builder.append(integer_value); - if (m_frac_length > 0) { - // FIXME: This disables the compiletime format string check since we can't parse '}}' here correctly. - // remove the 'StringView { }' when that's fixed. - builder.appendff("{:0{}}"sv, m_frac_value.value(), m_frac_length); + // NOTE: We test for the state so the decimal point appears on screen as soon as you type it. + if (m_state == State::TypingDecimal) { + builder.append('.'); + builder.append_repeated('0', number_pre_zeros); + if (frac_value != "0") + builder.append(frac_value); } return builder.to_string(); diff --git a/Userland/Applications/Calculator/Keypad.h b/Userland/Applications/Calculator/Keypad.h index f542aa38bf..0410e31b51 100644 --- a/Userland/Applications/Calculator/Keypad.h +++ b/Userland/Applications/Calculator/Keypad.h @@ -7,8 +7,9 @@ #pragma once -#include "KeypadValue.h" #include <AK/String.h> +#include <LibCrypto/BigFraction/BigFraction.h> +#include <LibCrypto/BigInt/UnsignedBigInteger.h> // This type implements number typing and // displaying mechanics. It does not perform @@ -24,23 +25,27 @@ public: void type_decimal_point(); void type_backspace(); - KeypadValue value() const; - void set_value(KeypadValue); + Crypto::BigFraction value() const; + void set_value(Crypto::BigFraction); + void set_to_0(); String to_string() const; private: // Internal representation of the current decimal value. - bool m_negative { false }; - Checked<u64> m_int_value { 0 }; - Checked<u64> m_frac_value { 0 }; - u8 m_frac_length { 0 }; + // Those variables are only used when the user is entering a value. + // Otherwise, the BigFraction m_internal_value is used. + Crypto::UnsignedBigInteger m_int_value { 0 }; + Crypto::UnsignedBigInteger m_frac_value { 0 }; + Crypto::UnsignedBigInteger m_frac_length { 0 }; // E.g. for -35.004200, // m_negative = true // m_int_value = 35 // m_frac_value = 4200 // m_frac_length = 6 + mutable Crypto::BigFraction m_internal_value {}; + enum class State { External, TypingInteger, diff --git a/Userland/Applications/Calculator/KeypadValue.cpp b/Userland/Applications/Calculator/KeypadValue.cpp deleted file mode 100644 index 144e447ff6..0000000000 --- a/Userland/Applications/Calculator/KeypadValue.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (c) 2021, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "KeypadValue.h" -#include <AK/IntegralMath.h> -#include <AK/Math.h> -#include <AK/String.h> - -KeypadValue::KeypadValue(i64 value, u8 decimal_places) - : m_value(value) - , m_decimal_places(value == 0 ? 0 : decimal_places) -{ -} - -KeypadValue::KeypadValue(i64 value) - : m_value(value) -{ -} - -KeypadValue::KeypadValue(StringView sv) -{ - String str = sv.to_string(); // TODO: Once we have a StringView equivalent for this C API, we won't need to create a copy for this anymore. - size_t first_index = 0; - char* dot_ptr; - i64 int_part = strtoll(&str[first_index], &dot_ptr, 10); - size_t dot_index = dot_ptr - str.characters(); - if ((dot_index < str.length()) && (str[dot_index] == '.')) { - size_t second_index = dot_index + 1; - char* end_ptr; - i64 frac_part = strtoll(&str[second_index], &end_ptr, 10); - size_t end_index = end_ptr - str.characters(); - u8 frac_length = end_index - second_index; - *this = KeypadValue { int_part } + KeypadValue { frac_part, frac_length }; - } else { - *this = KeypadValue { int_part }; - } -}; - -KeypadValue KeypadValue::operator+(KeypadValue const& rhs) -{ - return operator_helper<KeypadValue>(*this, rhs, [](KeypadValue const&, KeypadValue const& more_decimal_places, i64 less_decimal_places_equalized, i64 more_decimal_places_equalized, bool) -> KeypadValue { - return { - more_decimal_places_equalized + less_decimal_places_equalized, - more_decimal_places.m_decimal_places - }; - }); -} - -KeypadValue KeypadValue::operator-(KeypadValue const& rhs) -{ - return *this + (-rhs); -} - -KeypadValue KeypadValue::operator*(KeypadValue const& rhs) -{ - return operator_helper<KeypadValue>(*this, rhs, [](KeypadValue const& less_decimal_places, KeypadValue const& more_decimal_places, i64, i64, bool) -> KeypadValue { - return { - less_decimal_places.m_value * more_decimal_places.m_value, - (u8)(less_decimal_places.m_decimal_places + more_decimal_places.m_decimal_places) - }; - }); -} - -KeypadValue KeypadValue::operator-(void) const -{ - return { -m_value, m_decimal_places }; -} - -KeypadValue KeypadValue::sqrt(void) const -{ - return KeypadValue { AK::sqrt((double)(*this)) }; -} - -KeypadValue KeypadValue::invert(void) const -{ - return KeypadValue { 1.0 / (double)(*this) }; -} - -KeypadValue KeypadValue::operator/(KeypadValue const& rhs) -{ - return KeypadValue { (double)(*this) / (double)rhs }; -} - -bool KeypadValue::operator<(KeypadValue const& rhs) -{ - return operator_helper<bool>(*this, rhs, [](KeypadValue const&, KeypadValue const&, i64 less_decimal_places_equalized, i64 more_decimal_places_equalized, bool lhs_is_less) { - if (lhs_is_less) - return (less_decimal_places_equalized < more_decimal_places_equalized); - else - return (more_decimal_places_equalized < less_decimal_places_equalized); - }); -} - -bool KeypadValue::operator==(KeypadValue const& rhs) -{ - return operator_helper<bool>(*this, rhs, [](KeypadValue const&, KeypadValue const&, i64 less_decimal_places_equalized, i64 more_decimal_places_equalized, bool) { - return less_decimal_places_equalized == more_decimal_places_equalized; - }); -} - -// This is a helper function for the operators. A lot of them need to do very similar calculations, so this function -// does the calculations for them and calls them on the result. In case they don't need the result of a particular -// calculation, they simply ignore that argument. -// The arguments to this function are the operands on the left- and right-hand sides and the callback to call on the -// values computed by this function. -// The first two KeypadValues it passes to the callback are the two original operands, but sorted by the amount of -// decimal places. -// The next two i64s it passes to the callback are these sorted KeypadValues, but normalized, which means that if -// you have for example 12.1 (represented as {121, 1}) and 54.23 (represented as {5423, 2}), you will get 1210 and -// 5423, so that you can compare these two i64s directly in order to compare the original KeypadValues. -// Unfortunately, not all operators are symmetric, so the last boolean tells the callback whether the left-hand side -// was the KeypadValue with less decimal places (true), or the one with more decimal places (false). -template<typename T, typename F> -ALWAYS_INLINE T KeypadValue::operator_helper(KeypadValue const& lhs, KeypadValue const& rhs, F callback) -{ - KeypadValue const& less_decimal_places = (lhs.m_decimal_places < rhs.m_decimal_places) ? lhs : rhs; - KeypadValue const& more_decimal_places = (lhs.m_decimal_places < rhs.m_decimal_places) ? rhs : lhs; - - i64 more_decimal_places_equalized = more_decimal_places.m_value; - i64 less_decimal_places_equalized = AK::pow<i64>(10, more_decimal_places.m_decimal_places - less_decimal_places.m_decimal_places) * less_decimal_places.m_value; - - bool lhs_is_less = (lhs.m_decimal_places < rhs.m_decimal_places); - - return callback(less_decimal_places, more_decimal_places, - less_decimal_places_equalized, more_decimal_places_equalized, - lhs_is_less); -} - -KeypadValue::KeypadValue(double d) -{ - bool negative = false; - if (d < 0) { - negative = true; - d = -d; - } - i8 current_pow = 0; - while (AK::pow(10.0, (double)current_pow) <= d) - current_pow += 1; - current_pow -= 1; - double epsilon = 1e-6; - while (d >= epsilon || current_pow >= 0) { - m_value *= 10; - i8 digit = (u64)(d * AK::pow(0.1, (double)current_pow)) % 10; - m_value += digit; - d -= digit * AK::pow(10.0, (double)current_pow); - if (current_pow < 0) - m_decimal_places += 1; - current_pow -= 1; - if (m_decimal_places > 6) - break; - } - m_value = negative ? (-m_value) : m_value; -} - -KeypadValue::operator double() const -{ - double res = (double)m_value / AK::pow(10.0, (double)m_decimal_places); - return res; -} diff --git a/Userland/Applications/Calculator/KeypadValue.h b/Userland/Applications/Calculator/KeypadValue.h deleted file mode 100644 index 3d63e0f27f..0000000000 --- a/Userland/Applications/Calculator/KeypadValue.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2021, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include <AK/Math.h> -#include <AK/String.h> -#include <AK/Types.h> - -class KeypadValue { - friend class Keypad; - friend class Calculator; - -public: - KeypadValue(i64, u8); - KeypadValue(i64); - - explicit KeypadValue(StringView); - - KeypadValue operator+(KeypadValue const&); - KeypadValue operator-(KeypadValue const&); - KeypadValue operator*(KeypadValue const&); - KeypadValue operator-(void) const; - bool operator<(KeypadValue const&); - bool operator==(KeypadValue const&); - - KeypadValue sqrt() const; - KeypadValue invert() const; - KeypadValue operator/(KeypadValue const&); - -private: - explicit KeypadValue(double); - explicit operator double() const; - - template<typename T, typename F> - T operator_helper(KeypadValue const& lhs, KeypadValue const& rhs, F callback); - - // This class represents a pair of a value together with the amount of decimal places that value is offset by. - // For example, if we were to represent the value -123.55 in this format, m_value would be -12355 and - // m_decimal_places would be 2, because when you shift -12355 2 digits to the right, you get -123.55. - // This way, most operations don't have to be performed on doubles, but can be performed without loss of - // precision on this class. - i64 m_value { 0 }; - u8 m_decimal_places { 0 }; -}; diff --git a/Userland/Applications/Calculator/main.cpp b/Userland/Applications/Calculator/main.cpp index 91035a66f5..0e6bf8c2f8 100644 --- a/Userland/Applications/Calculator/main.cpp +++ b/Userland/Applications/Calculator/main.cpp @@ -6,6 +6,7 @@ #include "CalculatorWidget.h" #include <LibCore/System.h> +#include <LibCrypto/NumberTheory/ModularFunctions.h> #include <LibGUI/Action.h> #include <LibGUI/Application.h> #include <LibGUI/Clipboard.h> @@ -51,20 +52,22 @@ ErrorOr<int> serenity_main(Main::Arguments arguments) auto clipboard = GUI::Clipboard::the().fetch_data_and_type(); if (clipboard.mime_type == "text/plain") { if (!clipboard.data.is_empty()) { - widget->set_entry(KeypadValue(StringView(clipboard.data))); + widget->set_entry(Crypto::BigFraction(StringView(clipboard.data))); } } })); auto& constants_menu = window->add_menu("&Constants"); + auto const power = Crypto::NumberTheory::Power("10"_bigint, "10"_bigint); + constants_menu.add_action(GUI::Action::create("&Pi", TRY(Gfx::Bitmap::try_load_from_file("/res/icons/calculator/pi.png"sv)), [&](auto&) { - widget->set_entry(KeypadValue { 31415926535, 10 }); + widget->set_entry(Crypto::BigFraction { Crypto::SignedBigInteger(31415926535), power }); })); constants_menu.add_action(GUI::Action::create("&Euler's Number", TRY(Gfx::Bitmap::try_load_from_file("/res/icons/calculator/eulers_number.png"sv)), [&](auto&) { - widget->set_entry(KeypadValue { 27182818284, 10 }); + widget->set_entry(Crypto::BigFraction { Crypto::SignedBigInteger(27182818284), power }); })); constants_menu.add_action(GUI::Action::create("&Phi", TRY(Gfx::Bitmap::try_load_from_file("/res/icons/calculator/phi.png"sv)), [&](auto&) { - widget->set_entry(KeypadValue { 16180339887, 10 }); + widget->set_entry(Crypto::BigFraction { Crypto::SignedBigInteger(16180339887), power }); })); auto& help_menu = window->add_menu("&Help"); |