MathUtils.h 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. #pragma once
  2. #include "il2cpp-config.h"
  3. #include <assert.h>
  4. #include <cmath>
  5. #include <limits>
  6. #include <stdint.h>
  7. namespace il2cpp
  8. {
  9. namespace utils
  10. {
  11. namespace MathUtils
  12. {
  13. // Do math on low/high part separately as 64-bit integers because otherwise
  14. // we might easily overflow during initial multiplication
  15. inline int64_t A_Times_B_DividedBy_C(int64_t multiplicand, int64_t multiplier, int64_t divisor)
  16. {
  17. IL2CPP_ASSERT((llabs(divisor) & (1LL << 62)) == 0 && "Can't divide by numbers with absolute value larger than 2^62 - 1.");
  18. bool resultIsNegative = static_cast<uint64_t>(multiplicand ^ multiplier ^ divisor) >> 63; // Result is negative if odd number of operands are negative
  19. multiplicand = llabs(multiplicand);
  20. IL2CPP_ASSERT(multiplicand > 0 && "Can't multiply by -2^63.");
  21. multiplier = llabs(multiplier);
  22. IL2CPP_ASSERT(multiplier > 0 && "Can't multiply by -2^63.");
  23. divisor = llabs(divisor); // We already asserted on divisor size
  24. uint64_t multiplicand_low = multiplicand & 0xFFFFFFFF;
  25. uint64_t multiplicand_high = multiplicand >> 32;
  26. uint64_t multiplier_low = multiplier & 0xFFFFFFFF;
  27. uint64_t multiplier_high = multiplier >> 32;
  28. // We're gonna assume our multiplicated value is 128-bit integer
  29. // so we're gonna compose it of two uint64_t's
  30. // a * b =
  31. // (a_high * 2^32 + a_low) * (b_high * 2^32 + b_low) =
  32. // a_high * b_high * 2^64 + (a_high * b_low + a_low * b_high) * 2^32 + a_low * b_low
  33. uint64_t dividends[2] =
  34. {
  35. multiplicand_low * multiplier_low, // low part, bits [0, 63]
  36. multiplicand_high * multiplier_high // high part, bits [64, 127]
  37. };
  38. uint64_t resultMid1 = multiplicand_high * multiplier_low + multiplicand_low * multiplier_high; // mid part, bits [32, 95]
  39. dividends[1] += resultMid1 >> 32; // add the higher bits of mid part ([64, 95]) to high part
  40. resultMid1 = (resultMid1 & 0xFFFFFFFF) << 32; // Now this contains the lower bits of mid part ([32, 63])
  41. // Check for lower part overflow below adding the lower bits of mid part to it
  42. // Add carry to high part if overflow occurs
  43. if (dividends[0] > std::numeric_limits<uint64_t>::max() - resultMid1)
  44. dividends[1]++;
  45. dividends[0] += resultMid1; // add the lower bits of mid part to low part
  46. // At this point, we got our whole divident 128-bit value inside 'dividends'
  47. uint64_t workValue = 0; // Value that we're gonna be dividing
  48. uint64_t result = 0; // The final result
  49. const uint64_t kOne = 1;
  50. int bitIndex = 127; // Current bit that we're gonna be add to the workValue
  51. // Let's find the starting point for our division
  52. // We'll keep adding bits from our divident to the workValue until it's higher than the divisor
  53. // We did divisor = llabs(divisor) earlier, so cast to unsigned is safe
  54. while (workValue < static_cast<uint64_t>(divisor))
  55. {
  56. workValue <<= 1;
  57. if (bitIndex > -1)
  58. {
  59. workValue |= (dividends[bitIndex / 64] & (kOne << (bitIndex % 64))) != 0;
  60. }
  61. else
  62. {
  63. return 0;
  64. }
  65. bitIndex--;
  66. }
  67. // Main division loop
  68. for (; bitIndex > -2 || workValue >= static_cast<uint64_t>(divisor); bitIndex--)
  69. {
  70. result <<= 1; // Shift result left
  71. // Since it's binary, the division result can be only 0 and 1
  72. // It's 1 if workValue is higher or equal to divisor
  73. if (workValue >= static_cast<uint64_t>(divisor))
  74. {
  75. workValue -= static_cast<uint64_t>(divisor);
  76. result++;
  77. }
  78. // Shift work value to the left and append the next bit of our dividend
  79. IL2CPP_ASSERT((workValue & (1LL << 63)) == 0 && "overflow!");
  80. if (bitIndex > -1)
  81. {
  82. workValue <<= 1;
  83. workValue |= (dividends[bitIndex / 64] & (kOne << (bitIndex % 64))) != 0;
  84. }
  85. }
  86. // Negate result if it's supposed to be negative
  87. if (resultIsNegative)
  88. return -static_cast<int64_t>(result);
  89. return result;
  90. }
  91. }
  92. }
  93. }