1
0
Fork 0
mirror of https://github.com/LadybirdBrowser/ladybird.git synced 2025-06-09 17:44:56 +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 "KeypadValue.h"
#include <AK/Assertions.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) {
case Operation::None:
@ -33,30 +34,30 @@ double Calculator::begin_operation(Operation operation, double argument)
return argument;
case Operation::Sqrt:
if (argument < 0.0) {
if (argument < 0) {
m_has_error = true;
return argument;
}
res = AK::sqrt(argument);
res = KeypadValue { AK::sqrt((double)argument) };
clear_operation();
break;
case Operation::Inverse:
if (argument == 0.0) {
if (argument == 0) {
m_has_error = true;
return argument;
}
res = 1 / argument;
res = KeypadValue { 1.0 / (double)argument };
clear_operation();
break;
case Operation::Percent:
res = argument * 0.01;
res = argument * KeypadValue { 1, 2 }; // also known as `KeypadValue{0.01}`
break;
case Operation::ToggleSign:
res = -argument;
break;
case Operation::MemClear:
m_mem = 0.0;
m_mem = 0;
res = argument;
break;
case Operation::MemRecall:
@ -67,7 +68,7 @@ double Calculator::begin_operation(Operation operation, double argument)
res = argument;
break;
case Operation::MemAdd:
m_mem += argument;
m_mem = m_mem + argument; //avoids the need for operator+=()
res = m_mem;
break;
}
@ -75,9 +76,9 @@ double Calculator::begin_operation(Operation operation, double argument)
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) {
case Operation::None:
@ -93,11 +94,11 @@ double Calculator::finish_operation(double argument)
res = m_saved_argument * argument;
break;
case Operation::Divide:
if (argument == 0.0) {
if (argument == 0) {
m_has_error = true;
return argument;
}
res = m_saved_argument / argument;
res = KeypadValue { (double)m_saved_argument / (double)argument };
break;
case Operation::Sqrt:
@ -118,6 +119,6 @@ double Calculator::finish_operation(double argument)
void Calculator::clear_operation()
{
m_operation_in_progress = Operation::None;
m_saved_argument = 0.0;
m_saved_argument = 0;
clear_error();
}

View file

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

View file

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

View file

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

View file

@ -6,6 +6,8 @@
*/
#include "Keypad.h"
#include "KeypadValue.h"
#include <AK/Math.h>
#include <AK/StringBuilder.h>
Keypad::Keypad()
@ -97,51 +99,29 @@ void Keypad::type_backspace()
}
}
double Keypad::value() const
KeypadValue Keypad::value() const
{
double res = 0.0;
u64 frac = m_frac_value.value();
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();
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;
}
void Keypad::set_value(double value)
void Keypad::set_value(KeypadValue value)
{
m_state = State::External;
if (value < 0.0) {
if (value.m_value < 0) {
m_negative = true;
value = -value;
} else
m_negative = false;
m_int_value = value;
value -= m_int_value.value();
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;
}
m_int_value = value.m_value / (u64)AK::pow(10.0, (double)value.m_decimal_places);
m_frac_value = value.m_value % (u64)AK::pow(10.0, (double)value.m_decimal_places);
m_frac_length = value.m_decimal_places;
}
String Keypad::to_string() const

View file

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