diff options
Diffstat (limited to 'Userland/Applications/Calculator/Keypad.cpp')
-rw-r--r-- | Userland/Applications/Calculator/Keypad.cpp | 122 |
1 files changed, 61 insertions, 61 deletions
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(); |