1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 19:47:44 +00:00

LibCrypto+LibJS: Better bigint bitwise_or binop

Similar to the bitwise_and change, but we have to be careful to
sign-extend two's complement numbers only up to the highest set bit
in the positive number.
This commit is contained in:
Nico Weber 2022-01-18 08:46:42 -05:00 committed by Ali Mohammad Pur
parent 1f98639396
commit 013799a4dd
8 changed files with 77 additions and 23 deletions

View file

@ -184,12 +184,18 @@ FLATTEN SignedDivisionResult SignedBigInteger::divided_by(UnsignedBigInteger con
FLATTEN SignedBigInteger SignedBigInteger::bitwise_or(const SignedBigInteger& other) const
{
auto result = bitwise_or(other.unsigned_value());
// See bitwise_and() for derivations.
if (!is_negative() && !other.is_negative())
return { unsigned_value().bitwise_or(other.unsigned_value()), false };
// The sign bit will have to be OR'd manually.
result.m_sign = is_negative() || other.is_negative();
size_t index = max(unsigned_value().one_based_index_of_highest_set_bit(), other.unsigned_value().one_based_index_of_highest_set_bit());
if (is_negative() && !other.is_negative())
return { unsigned_value().bitwise_not_fill_to_one_based_index(index).plus(1).bitwise_or(other.unsigned_value()).bitwise_not_fill_to_one_based_index(index).plus(1), true };
return result;
if (!is_negative() && other.is_negative())
return { unsigned_value().bitwise_or(other.unsigned_value().bitwise_not_fill_to_one_based_index(index).plus(1)).bitwise_not_fill_to_one_based_index(index).plus(1), true };
return { unsigned_value().minus(1).bitwise_and(other.unsigned_value().minus(1)).plus(1), true };
}
FLATTEN SignedBigInteger SignedBigInteger::bitwise_and(const SignedBigInteger& other) const
@ -200,12 +206,16 @@ FLATTEN SignedBigInteger SignedBigInteger::bitwise_and(const SignedBigInteger& o
// These two just use that -x == ~x + 1 (see below).
// -A & B == (~A + 1) & B.
if (is_negative() && !other.is_negative())
return { unsigned_value().bitwise_not_fill_to_size(other.trimmed_length()).plus(1).bitwise_and(other.unsigned_value()), false };
if (is_negative() && !other.is_negative()) {
size_t index = other.unsigned_value().one_based_index_of_highest_set_bit();
return { unsigned_value().bitwise_not_fill_to_one_based_index(index).plus(1).bitwise_and(other.unsigned_value()), false };
}
// A & -B == A & (~B + 1).
if (!is_negative() && other.is_negative())
return { unsigned_value().bitwise_and(other.unsigned_value().bitwise_not_fill_to_size(trimmed_length()).plus(1)), false };
if (!is_negative() && other.is_negative()) {
size_t index = unsigned_value().one_based_index_of_highest_set_bit();
return { unsigned_value().bitwise_and(other.unsigned_value().bitwise_not_fill_to_one_based_index(index).plus(1)), false };
}
// Both numbers are negative.
// x + ~x == 0xff...ff, up to however many bits x is wide.