mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 14:07:46 +00:00
Calculator: Round small number to prevent crash
Small numbers (smaller than 1e-19) can't be displayed in the calculator. They provoke a division by zero in Keypad::set_value(), as 10^20 overflows.
This commit is contained in:
parent
939bf3e864
commit
7532ef78ad
3 changed files with 50 additions and 1 deletions
|
@ -68,11 +68,14 @@ KeypadValue Calculator::begin_operation(Operation operation, KeypadValue argumen
|
|||
res = argument;
|
||||
break;
|
||||
case Operation::MemAdd:
|
||||
m_mem = m_mem + argument; //avoids the need for operator+=()
|
||||
m_mem = m_mem + argument; // avoids the need for operator+=()
|
||||
res = m_mem;
|
||||
break;
|
||||
}
|
||||
|
||||
if (should_be_rounded(res))
|
||||
round(res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -112,6 +115,9 @@ KeypadValue Calculator::finish_operation(KeypadValue argument)
|
|||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
if (should_be_rounded(res))
|
||||
round(res);
|
||||
|
||||
clear_operation();
|
||||
return res;
|
||||
}
|
||||
|
@ -122,3 +128,29 @@ void Calculator::clear_operation()
|
|||
m_saved_argument = 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,22 @@ 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 };
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
class KeypadValue {
|
||||
friend class Keypad;
|
||||
friend class Calculator;
|
||||
|
||||
public:
|
||||
KeypadValue(i64, u8);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue