1
Fork 0
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:
Lucas CHOLLET 2022-01-01 21:49:30 +01:00 committed by Andreas Kling
parent 939bf3e864
commit 7532ef78ad
3 changed files with 50 additions and 1 deletions

View file

@ -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;
}
}
}

View file

@ -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 };

View file

@ -12,6 +12,7 @@
class KeypadValue {
friend class Keypad;
friend class Calculator;
public:
KeypadValue(i64, u8);