SignedBigInteger.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. /*
  2. * Copyright (c) 2020, the SerenityOS developers.
  3. * Copyright (c) 2022, David Tuin <davidot@serenityos.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include "SignedBigInteger.h"
  8. #include <AK/StringBuilder.h>
  9. #include <math.h>
  10. namespace Crypto {
  11. SignedBigInteger::SignedBigInteger(double value)
  12. : m_sign(value < 0.0)
  13. , m_unsigned_data(fabs(value))
  14. {
  15. }
  16. SignedBigInteger SignedBigInteger::import_data(u8 const* ptr, size_t length)
  17. {
  18. bool sign = *ptr;
  19. auto unsigned_data = UnsignedBigInteger::import_data(ptr + 1, length - 1);
  20. return { move(unsigned_data), sign };
  21. }
  22. size_t SignedBigInteger::export_data(Bytes data, bool remove_leading_zeros) const
  23. {
  24. // FIXME: Support this:
  25. // m <0XX> -> m <XX> (if remove_leading_zeros)
  26. VERIFY(!remove_leading_zeros);
  27. data[0] = m_sign;
  28. auto bytes_view = data.slice(1, data.size() - 1);
  29. return m_unsigned_data.export_data(bytes_view, remove_leading_zeros) + 1;
  30. }
  31. ErrorOr<SignedBigInteger> SignedBigInteger::from_base(u16 N, StringView str)
  32. {
  33. auto sign = false;
  34. if (str.length() > 1) {
  35. auto maybe_sign = str[0];
  36. if (maybe_sign == '-') {
  37. str = str.substring_view(1);
  38. sign = true;
  39. }
  40. if (maybe_sign == '+')
  41. str = str.substring_view(1);
  42. }
  43. auto unsigned_data = TRY(UnsignedBigInteger::from_base(N, str));
  44. return SignedBigInteger { move(unsigned_data), sign };
  45. }
  46. ErrorOr<String> SignedBigInteger::to_base(u16 N) const
  47. {
  48. StringBuilder builder;
  49. if (m_sign)
  50. TRY(builder.try_append('-'));
  51. auto unsigned_as_base = TRY(m_unsigned_data.to_base(N));
  52. TRY(builder.try_append(unsigned_as_base.bytes_as_string_view()));
  53. return builder.to_string();
  54. }
  55. ByteString SignedBigInteger::to_base_deprecated(u16 N) const
  56. {
  57. return MUST(to_base(N)).to_byte_string();
  58. }
  59. u64 SignedBigInteger::to_u64() const
  60. {
  61. u64 unsigned_value = m_unsigned_data.to_u64();
  62. if (!m_sign)
  63. return unsigned_value;
  64. return ~(unsigned_value - 1); // equivalent to `-unsigned_value`, but doesn't trigger UBSAN
  65. }
  66. double SignedBigInteger::to_double(UnsignedBigInteger::RoundingMode rounding_mode) const
  67. {
  68. double unsigned_value = m_unsigned_data.to_double(rounding_mode);
  69. if (!m_sign)
  70. return unsigned_value;
  71. VERIFY(!is_zero());
  72. return -unsigned_value;
  73. }
  74. FLATTEN SignedBigInteger SignedBigInteger::plus(SignedBigInteger const& other) const
  75. {
  76. // If both are of the same sign, just add the unsigned data and return.
  77. if (m_sign == other.m_sign)
  78. return { other.m_unsigned_data.plus(m_unsigned_data), m_sign };
  79. // One value is signed while the other is not.
  80. return m_sign ? other.minus(this->m_unsigned_data) : minus(other.m_unsigned_data);
  81. }
  82. FLATTEN SignedBigInteger SignedBigInteger::minus(SignedBigInteger const& other) const
  83. {
  84. // If the signs are different, convert the op to an addition.
  85. if (m_sign != other.m_sign) {
  86. // -x - y = - (x + y)
  87. // x - -y = (x + y)
  88. SignedBigInteger result { other.m_unsigned_data.plus(this->m_unsigned_data) };
  89. if (m_sign)
  90. result.negate();
  91. return result;
  92. }
  93. if (!m_sign) {
  94. // Both operands are positive.
  95. // x - y = - (y - x)
  96. if (m_unsigned_data < other.m_unsigned_data) {
  97. // The result will be negative.
  98. return { other.m_unsigned_data.minus(m_unsigned_data), true };
  99. }
  100. // The result will be either zero, or positive.
  101. return SignedBigInteger { m_unsigned_data.minus(other.m_unsigned_data) };
  102. }
  103. // Both operands are negative.
  104. // -x - -y = y - x
  105. if (m_unsigned_data < other.m_unsigned_data) {
  106. // The result will be positive.
  107. return SignedBigInteger { other.m_unsigned_data.minus(m_unsigned_data) };
  108. }
  109. // y - x = - (x - y)
  110. if (m_unsigned_data > other.m_unsigned_data) {
  111. // The result will be negative.
  112. return SignedBigInteger { m_unsigned_data.minus(other.m_unsigned_data), true };
  113. }
  114. // Both operands have the same magnitude, the result is positive zero.
  115. return SignedBigInteger { 0 };
  116. }
  117. FLATTEN SignedBigInteger SignedBigInteger::plus(UnsignedBigInteger const& other) const
  118. {
  119. if (m_sign) {
  120. if (other < m_unsigned_data)
  121. return { m_unsigned_data.minus(other), true };
  122. return { other.minus(m_unsigned_data), false };
  123. }
  124. return { m_unsigned_data.plus(other), false };
  125. }
  126. FLATTEN SignedBigInteger SignedBigInteger::minus(UnsignedBigInteger const& other) const
  127. {
  128. if (m_sign)
  129. return { m_unsigned_data.plus(m_unsigned_data), true };
  130. if (other < m_unsigned_data)
  131. return { m_unsigned_data.minus(other), false };
  132. return { other.minus(m_unsigned_data), true };
  133. }
  134. FLATTEN SignedBigInteger SignedBigInteger::bitwise_not() const
  135. {
  136. // Bitwise operators assume two's complement, while SignedBigInteger uses sign-magnitude.
  137. // In two's complement, -x := ~x + 1.
  138. // Hence, ~x == -x -1 == -(x + 1).
  139. SignedBigInteger result = plus(SignedBigInteger { 1 });
  140. result.negate();
  141. return result;
  142. }
  143. FLATTEN SignedBigInteger SignedBigInteger::multiplied_by(UnsignedBigInteger const& other) const
  144. {
  145. return { unsigned_value().multiplied_by(other), m_sign };
  146. }
  147. FLATTEN SignedDivisionResult SignedBigInteger::divided_by(UnsignedBigInteger const& divisor) const
  148. {
  149. auto division_result = unsigned_value().divided_by(divisor);
  150. return {
  151. { move(division_result.quotient), m_sign },
  152. { move(division_result.remainder), m_sign },
  153. };
  154. }
  155. FLATTEN SignedBigInteger SignedBigInteger::bitwise_or(SignedBigInteger const& other) const
  156. {
  157. // See bitwise_and() for derivations.
  158. if (!is_negative() && !other.is_negative())
  159. return { unsigned_value().bitwise_or(other.unsigned_value()), false };
  160. // -A | B == (~A + 1) | B == ~(A - 1) | B. The result is negative, so need to two's complement at the end to move the sign into the m_sign field.
  161. // That can be simplified to:
  162. // -(-A | B) == ~(~(A - 1) | B) + 1 = (A - 1) & ~B + 1
  163. // This saves one ~.
  164. if (is_negative() && !other.is_negative()) {
  165. size_t index = unsigned_value().one_based_index_of_highest_set_bit();
  166. return { unsigned_value().minus(1).bitwise_and(other.unsigned_value().bitwise_not_fill_to_one_based_index(index)).plus(1), true };
  167. }
  168. // -(A | -B) == ~A & (B - 1) + 1
  169. if (!is_negative() && other.is_negative()) {
  170. size_t index = other.unsigned_value().one_based_index_of_highest_set_bit();
  171. return { unsigned_value().bitwise_not_fill_to_one_based_index(index).bitwise_and(other.unsigned_value().minus(1)).plus(1), true };
  172. }
  173. return { unsigned_value().minus(1).bitwise_and(other.unsigned_value().minus(1)).plus(1), true };
  174. }
  175. FLATTEN SignedBigInteger SignedBigInteger::bitwise_and(SignedBigInteger const& other) const
  176. {
  177. if (!is_negative() && !other.is_negative())
  178. return { unsigned_value().bitwise_and(other.unsigned_value()), false };
  179. // These two just use that -x == ~x + 1 (see below).
  180. // -A & B == (~A + 1) & B.
  181. if (is_negative() && !other.is_negative()) {
  182. size_t index = other.unsigned_value().one_based_index_of_highest_set_bit();
  183. return { unsigned_value().bitwise_not_fill_to_one_based_index(index).plus(1).bitwise_and(other.unsigned_value()), false };
  184. }
  185. // A & -B == A & (~B + 1).
  186. if (!is_negative() && other.is_negative()) {
  187. size_t index = unsigned_value().one_based_index_of_highest_set_bit();
  188. return { unsigned_value().bitwise_and(other.unsigned_value().bitwise_not_fill_to_one_based_index(index).plus(1)), false };
  189. }
  190. // Both numbers are negative.
  191. // x + ~x == 0xff...ff, up to however many bits x is wide.
  192. // In two's complement, x + ~x + 1 == 0 since the 1 in the overflowing bit position is masked out.
  193. // Rearranging terms, ~x = -x - 1 (eq1).
  194. // Substituting x = y - 1, ~(y - 1) == -(y - 1) - 1 == -y +1 -1 == -y, or ~(y - 1) == -y (eq2).
  195. // Since both numbers are negative, we want to compute -A & -B.
  196. // Per (eq2):
  197. // -A & -B == ~(A - 1) & ~(B - 1)
  198. // Inverting both sides:
  199. // ~(-A & -B) == ~(~(A - 1) & ~(B - 1)) == ~~(A - 1) | ~~(B - 1) == (A - 1) | (B - 1).
  200. // Applying (q1) on the LHS:
  201. // -(-A & -B) - 1 == (A - 1) | (B - 1)
  202. // Adding 1 on both sides and then multiplying both sides by -1:
  203. // -A & -B == -( (A - 1) | (B - 1) + 1)
  204. // So we can compute the bitwise and by returning a negative number with magnitude (A - 1) | (B - 1) + 1.
  205. // This is better than the naive (~A + 1) & (~B + 1) because it needs just one O(n) scan for the or instead of 2 for the ~s.
  206. return { unsigned_value().minus(1).bitwise_or(other.unsigned_value().minus(1)).plus(1), true };
  207. }
  208. FLATTEN SignedBigInteger SignedBigInteger::bitwise_xor(SignedBigInteger const& other) const
  209. {
  210. return bitwise_or(other).minus(bitwise_and(other));
  211. }
  212. bool SignedBigInteger::operator==(UnsignedBigInteger const& other) const
  213. {
  214. if (m_sign && m_unsigned_data != 0)
  215. return false;
  216. return m_unsigned_data == other;
  217. }
  218. bool SignedBigInteger::operator!=(UnsignedBigInteger const& other) const
  219. {
  220. if (m_sign)
  221. return true;
  222. return m_unsigned_data != other;
  223. }
  224. bool SignedBigInteger::operator<(UnsignedBigInteger const& other) const
  225. {
  226. if (m_sign)
  227. return true;
  228. return m_unsigned_data < other;
  229. }
  230. bool SignedBigInteger::operator>(UnsignedBigInteger const& other) const
  231. {
  232. return *this != other && !(*this < other);
  233. }
  234. FLATTEN SignedBigInteger SignedBigInteger::shift_left(size_t num_bits) const
  235. {
  236. return SignedBigInteger { m_unsigned_data.shift_left(num_bits), m_sign };
  237. }
  238. FLATTEN SignedBigInteger SignedBigInteger::multiplied_by(SignedBigInteger const& other) const
  239. {
  240. bool result_sign = m_sign ^ other.m_sign;
  241. return { m_unsigned_data.multiplied_by(other.m_unsigned_data), result_sign };
  242. }
  243. FLATTEN SignedDivisionResult SignedBigInteger::divided_by(SignedBigInteger const& divisor) const
  244. {
  245. // Aa / Bb -> (A^B)q, Ar
  246. bool result_sign = m_sign ^ divisor.m_sign;
  247. auto unsigned_division_result = m_unsigned_data.divided_by(divisor.m_unsigned_data);
  248. return {
  249. { move(unsigned_division_result.quotient), result_sign },
  250. { move(unsigned_division_result.remainder), m_sign }
  251. };
  252. }
  253. FLATTEN SignedBigInteger SignedBigInteger::negated_value() const
  254. {
  255. auto result { *this };
  256. result.negate();
  257. return result;
  258. }
  259. u32 SignedBigInteger::hash() const
  260. {
  261. return m_unsigned_data.hash() * (1 - (2 * m_sign));
  262. }
  263. void SignedBigInteger::set_bit_inplace(size_t bit_index)
  264. {
  265. m_unsigned_data.set_bit_inplace(bit_index);
  266. }
  267. bool SignedBigInteger::operator==(SignedBigInteger const& other) const
  268. {
  269. if (is_invalid() != other.is_invalid())
  270. return false;
  271. if (m_unsigned_data == 0 && other.m_unsigned_data == 0)
  272. return true;
  273. return m_sign == other.m_sign && m_unsigned_data == other.m_unsigned_data;
  274. }
  275. bool SignedBigInteger::operator!=(SignedBigInteger const& other) const
  276. {
  277. return !(*this == other);
  278. }
  279. bool SignedBigInteger::operator<(SignedBigInteger const& other) const
  280. {
  281. if (m_sign ^ other.m_sign)
  282. return m_sign;
  283. if (m_sign)
  284. return other.m_unsigned_data < m_unsigned_data;
  285. return m_unsigned_data < other.m_unsigned_data;
  286. }
  287. bool SignedBigInteger::operator<=(SignedBigInteger const& other) const
  288. {
  289. return *this < other || *this == other;
  290. }
  291. bool SignedBigInteger::operator>(SignedBigInteger const& other) const
  292. {
  293. return *this != other && !(*this < other);
  294. }
  295. bool SignedBigInteger::operator>=(SignedBigInteger const& other) const
  296. {
  297. return !(*this < other);
  298. }
  299. UnsignedBigInteger::CompareResult SignedBigInteger::compare_to_double(double value) const
  300. {
  301. bool bigint_is_negative = m_sign;
  302. bool value_is_negative = value < 0;
  303. if (value_is_negative != bigint_is_negative)
  304. return bigint_is_negative ? UnsignedBigInteger::CompareResult::DoubleGreaterThanBigInt : UnsignedBigInteger::CompareResult::DoubleLessThanBigInt;
  305. // Now both bigint and value have the same sign, so let's compare our magnitudes.
  306. auto magnitudes_compare_result = m_unsigned_data.compare_to_double(fabs(value));
  307. // If our mangnitudes are euqal, then we're equal.
  308. if (magnitudes_compare_result == UnsignedBigInteger::CompareResult::DoubleEqualsBigInt)
  309. return UnsignedBigInteger::CompareResult::DoubleEqualsBigInt;
  310. // If we're negative, revert the comparison result, otherwise return the same result.
  311. if (value_is_negative) {
  312. if (magnitudes_compare_result == UnsignedBigInteger::CompareResult::DoubleLessThanBigInt)
  313. return UnsignedBigInteger::CompareResult::DoubleGreaterThanBigInt;
  314. else
  315. return UnsignedBigInteger::CompareResult::DoubleLessThanBigInt;
  316. } else {
  317. return magnitudes_compare_result;
  318. }
  319. }
  320. }
  321. ErrorOr<void> AK::Formatter<Crypto::SignedBigInteger>::format(FormatBuilder& fmtbuilder, Crypto::SignedBigInteger const& value)
  322. {
  323. if (value.is_negative())
  324. TRY(fmtbuilder.put_string("-"sv));
  325. return Formatter<Crypto::UnsignedBigInteger>::format(fmtbuilder, value.unsigned_value());
  326. }