1
0
Fork 0
mirror of https://github.com/LadybirdBrowser/ladybird.git synced 2025-06-10 01:51:03 +09:00

Calculator: Use KeypadValue class instead of double

Calculator now uses the KeypadValue class instead of double in
its internal calculations. By not constantly converting to
double back-and-forth, we do not use precision simply by, for
example, negating a number. This fixes #7484.
This commit is contained in:
creator1creeper1 2021-08-01 13:08:53 +02:00 committed by Ali Mohammad Pur
parent 97d2a5799e
commit 8f552c9979
Notes: sideshowbarker 2024-07-18 07:32:33 +09:00
6 changed files with 43 additions and 57 deletions

View file

@ -5,6 +5,7 @@
*/ */
#include "Calculator.h" #include "Calculator.h"
#include "KeypadValue.h"
#include <AK/Assertions.h> #include <AK/Assertions.h>
#include <AK/Math.h> #include <AK/Math.h>
@ -16,9 +17,9 @@ Calculator::~Calculator()
{ {
} }
double Calculator::begin_operation(Operation operation, double argument) KeypadValue Calculator::begin_operation(Operation operation, KeypadValue argument)
{ {
double res = 0.0; KeypadValue res = 0;
switch (operation) { switch (operation) {
case Operation::None: case Operation::None:
@ -33,30 +34,30 @@ double Calculator::begin_operation(Operation operation, double argument)
return argument; return argument;
case Operation::Sqrt: case Operation::Sqrt:
if (argument < 0.0) { if (argument < 0) {
m_has_error = true; m_has_error = true;
return argument; return argument;
} }
res = AK::sqrt(argument); res = KeypadValue { AK::sqrt((double)argument) };
clear_operation(); clear_operation();
break; break;
case Operation::Inverse: case Operation::Inverse:
if (argument == 0.0) { if (argument == 0) {
m_has_error = true; m_has_error = true;
return argument; return argument;
} }
res = 1 / argument; res = KeypadValue { 1.0 / (double)argument };
clear_operation(); clear_operation();
break; break;
case Operation::Percent: case Operation::Percent:
res = argument * 0.01; res = argument * KeypadValue { 1, 2 }; // also known as `KeypadValue{0.01}`
break; break;
case Operation::ToggleSign: case Operation::ToggleSign:
res = -argument; res = -argument;
break; break;
case Operation::MemClear: case Operation::MemClear:
m_mem = 0.0; m_mem = 0;
res = argument; res = argument;
break; break;
case Operation::MemRecall: case Operation::MemRecall:
@ -67,7 +68,7 @@ double Calculator::begin_operation(Operation operation, double argument)
res = argument; res = argument;
break; break;
case Operation::MemAdd: case Operation::MemAdd:
m_mem += argument; m_mem = m_mem + argument; //avoids the need for operator+=()
res = m_mem; res = m_mem;
break; break;
} }
@ -75,9 +76,9 @@ double Calculator::begin_operation(Operation operation, double argument)
return res; return res;
} }
double Calculator::finish_operation(double argument) KeypadValue Calculator::finish_operation(KeypadValue argument)
{ {
double res = 0.0; KeypadValue res = 0;
switch (m_operation_in_progress) { switch (m_operation_in_progress) {
case Operation::None: case Operation::None:
@ -93,11 +94,11 @@ double Calculator::finish_operation(double argument)
res = m_saved_argument * argument; res = m_saved_argument * argument;
break; break;
case Operation::Divide: case Operation::Divide:
if (argument == 0.0) { if (argument == 0) {
m_has_error = true; m_has_error = true;
return argument; return argument;
} }
res = m_saved_argument / argument; res = KeypadValue { (double)m_saved_argument / (double)argument };
break; break;
case Operation::Sqrt: case Operation::Sqrt:
@ -118,6 +119,6 @@ double Calculator::finish_operation(double argument)
void Calculator::clear_operation() void Calculator::clear_operation()
{ {
m_operation_in_progress = Operation::None; m_operation_in_progress = Operation::None;
m_saved_argument = 0.0; m_saved_argument = 0;
clear_error(); clear_error();
} }

View file

@ -6,6 +6,8 @@
#pragma once #pragma once
#include "KeypadValue.h"
// This type implements the regular calculator // This type implements the regular calculator
// behavior, such as performing arithmetic // behavior, such as performing arithmetic
// operations and providing a memory cell. // operations and providing a memory cell.
@ -36,8 +38,8 @@ public:
MemAdd MemAdd
}; };
double begin_operation(Operation, double); KeypadValue begin_operation(Operation, KeypadValue);
double finish_operation(double); KeypadValue finish_operation(KeypadValue);
bool has_error() const { return m_has_error; } bool has_error() const { return m_has_error; }
@ -46,7 +48,7 @@ public:
private: private:
Operation m_operation_in_progress { Operation::None }; Operation m_operation_in_progress { Operation::None };
double m_saved_argument { 0.0 }; KeypadValue m_saved_argument { (i64)0 };
double m_mem { 0.0 }; KeypadValue m_mem { (i64)0 };
bool m_has_error { false }; bool m_has_error { false };
}; };

View file

@ -7,6 +7,7 @@
*/ */
#include "CalculatorWidget.h" #include "CalculatorWidget.h"
#include "KeypadValue.h"
#include <Applications/Calculator/CalculatorGML.h> #include <Applications/Calculator/CalculatorGML.h>
#include <LibGUI/Button.h> #include <LibGUI/Button.h>
#include <LibGUI/Label.h> #include <LibGUI/Label.h>
@ -96,8 +97,8 @@ CalculatorWidget::CalculatorWidget()
m_equals_button = *find_descendant_of_type_named<GUI::Button>("equal_button"); m_equals_button = *find_descendant_of_type_named<GUI::Button>("equal_button");
m_equals_button->on_click = [this](auto) { m_equals_button->on_click = [this](auto) {
double argument = m_keypad.value(); KeypadValue argument = m_keypad.value();
double res = m_calculator.finish_operation(argument); KeypadValue res = m_calculator.finish_operation(argument);
m_keypad.set_value(res); m_keypad.set_value(res);
update_display(); update_display();
}; };
@ -110,8 +111,8 @@ CalculatorWidget::~CalculatorWidget()
void CalculatorWidget::add_operation_button(GUI::Button& button, Calculator::Operation operation) void CalculatorWidget::add_operation_button(GUI::Button& button, Calculator::Operation operation)
{ {
button.on_click = [this, operation](auto) { button.on_click = [this, operation](auto) {
double argument = m_keypad.value(); KeypadValue argument = m_keypad.value();
double res = m_calculator.begin_operation(operation, argument); KeypadValue res = m_calculator.begin_operation(operation, argument);
m_keypad.set_value(res); m_keypad.set_value(res);
update_display(); update_display();
}; };
@ -130,7 +131,7 @@ String CalculatorWidget::get_entry()
return m_entry->text(); return m_entry->text();
} }
void CalculatorWidget::set_entry(double value) void CalculatorWidget::set_entry(KeypadValue value)
{ {
m_keypad.set_value(value); m_keypad.set_value(value);
update_display(); update_display();

View file

@ -9,6 +9,7 @@
#include "Calculator.h" #include "Calculator.h"
#include "Keypad.h" #include "Keypad.h"
#include "KeypadValue.h"
#include <AK/Vector.h> #include <AK/Vector.h>
#include <LibGUI/Widget.h> #include <LibGUI/Widget.h>
@ -17,7 +18,7 @@ class CalculatorWidget final : public GUI::Widget {
public: public:
virtual ~CalculatorWidget() override; virtual ~CalculatorWidget() override;
String get_entry(); String get_entry();
void set_entry(double); void set_entry(KeypadValue);
private: private:
CalculatorWidget(); CalculatorWidget();

View file

@ -6,6 +6,8 @@
*/ */
#include "Keypad.h" #include "Keypad.h"
#include "KeypadValue.h"
#include <AK/Math.h>
#include <AK/StringBuilder.h> #include <AK/StringBuilder.h>
Keypad::Keypad() Keypad::Keypad()
@ -97,51 +99,29 @@ void Keypad::type_backspace()
} }
} }
double Keypad::value() const KeypadValue Keypad::value() const
{ {
double res = 0.0; KeypadValue frac_part = { (i64)m_frac_value.value(), m_frac_length };
KeypadValue int_part = { (i64)m_int_value.value() };
u64 frac = m_frac_value.value(); KeypadValue res = int_part + frac_part;
for (int i = 0; i < m_frac_length; i++) {
u8 digit = frac % 10;
res += digit;
res /= 10.0;
frac /= 10;
}
res += m_int_value.value();
if (m_negative) if (m_negative)
res = -res; res = -res;
return res; return res;
} }
void Keypad::set_value(double value) void Keypad::set_value(KeypadValue value)
{ {
m_state = State::External; m_state = State::External;
if (value < 0.0) { if (value.m_value < 0) {
m_negative = true; m_negative = true;
value = -value; value = -value;
} else } else
m_negative = false; m_negative = false;
m_int_value = value; m_int_value = value.m_value / (u64)AK::pow(10.0, (double)value.m_decimal_places);
value -= m_int_value.value(); m_frac_value = value.m_value % (u64)AK::pow(10.0, (double)value.m_decimal_places);
m_frac_length = value.m_decimal_places;
m_frac_value = 0;
m_frac_length = 0;
while (value != 0) {
value *= 10.0;
int digit = value;
m_frac_value *= 10;
m_frac_value += digit;
m_frac_length++;
value -= digit;
if (m_frac_length > 6)
break;
}
} }
String Keypad::to_string() const String Keypad::to_string() const

View file

@ -6,6 +6,7 @@
#pragma once #pragma once
#include "KeypadValue.h"
#include <AK/String.h> #include <AK/String.h>
// This type implements number typing and // This type implements number typing and
@ -22,8 +23,8 @@ public:
void type_decimal_point(); void type_decimal_point();
void type_backspace(); void type_backspace();
double value() const; KeypadValue value() const;
void set_value(double); void set_value(KeypadValue);
String to_string() const; String to_string() const;