summaryrefslogtreecommitdiff
path: root/Userland/Applications/Calculator
diff options
context:
space:
mode:
Diffstat (limited to 'Userland/Applications/Calculator')
-rw-r--r--Userland/Applications/Calculator/CMakeLists.txt1
-rw-r--r--Userland/Applications/Calculator/Calculator.cpp54
-rw-r--r--Userland/Applications/Calculator/Calculator.h26
-rw-r--r--Userland/Applications/Calculator/CalculatorWidget.cpp24
-rw-r--r--Userland/Applications/Calculator/CalculatorWidget.h4
-rw-r--r--Userland/Applications/Calculator/Keypad.cpp122
-rw-r--r--Userland/Applications/Calculator/Keypad.h19
-rw-r--r--Userland/Applications/Calculator/KeypadValue.cpp162
-rw-r--r--Userland/Applications/Calculator/KeypadValue.h48
-rw-r--r--Userland/Applications/Calculator/main.cpp11
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");