1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 07:47:37 +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; res = argument;
break; break;
case Operation::MemAdd: 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; res = m_mem;
break; break;
} }
if (should_be_rounded(res))
round(res);
return res; return res;
} }
@ -112,6 +115,9 @@ KeypadValue Calculator::finish_operation(KeypadValue argument)
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
} }
if (should_be_rounded(res))
round(res);
clear_operation(); clear_operation();
return res; return res;
} }
@ -122,3 +128,29 @@ void Calculator::clear_operation()
m_saved_argument = 0; m_saved_argument = 0;
clear_error(); 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; } void clear_error() { m_has_error = false; }
private: 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 }; Operation m_operation_in_progress { Operation::None };
KeypadValue m_saved_argument { (i64)0 }; KeypadValue m_saved_argument { (i64)0 };
KeypadValue m_mem { (i64)0 }; KeypadValue m_mem { (i64)0 };

View file

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