123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- #pragma once
- #include "il2cpp-config.h"
- #include <cmath>
- #include <limits>
- #include <stdint.h>
- namespace il2cpp
- {
- namespace utils
- {
- namespace MathUtils
- {
-
-
- inline int64_t A_Times_B_DividedBy_C(int64_t multiplicand, int64_t multiplier, int64_t divisor)
- {
- IL2CPP_ASSERT((llabs(divisor) & (1LL << 62)) == 0 && "Can't divide by numbers with absolute value larger than 2^62 - 1.");
- bool resultIsNegative = static_cast<uint64_t>(multiplicand ^ multiplier ^ divisor) >> 63;
- multiplicand = llabs(multiplicand);
- IL2CPP_ASSERT(multiplicand > 0 && "Can't multiply by -2^63.");
- multiplier = llabs(multiplier);
- IL2CPP_ASSERT(multiplier > 0 && "Can't multiply by -2^63.");
- divisor = llabs(divisor);
- uint64_t multiplicand_low = multiplicand & 0xFFFFFFFF;
- uint64_t multiplicand_high = multiplicand >> 32;
- uint64_t multiplier_low = multiplier & 0xFFFFFFFF;
- uint64_t multiplier_high = multiplier >> 32;
-
-
-
-
-
- uint64_t dividends[2] =
- {
- multiplicand_low * multiplier_low,
- multiplicand_high * multiplier_high
- };
- uint64_t resultMid1 = multiplicand_high * multiplier_low + multiplicand_low * multiplier_high;
- dividends[1] += resultMid1 >> 32;
- resultMid1 = (resultMid1 & 0xFFFFFFFF) << 32;
-
-
- if (dividends[0] > std::numeric_limits<uint64_t>::max() - resultMid1)
- dividends[1]++;
- dividends[0] += resultMid1;
-
- uint64_t workValue = 0;
- uint64_t result = 0;
- const uint64_t kOne = 1;
- int bitIndex = 127;
-
-
-
- while (workValue < static_cast<uint64_t>(divisor))
- {
- workValue <<= 1;
- if (bitIndex > -1)
- {
- workValue |= (dividends[bitIndex / 64] & (kOne << (bitIndex % 64))) != 0;
- }
- else
- {
- return 0;
- }
- bitIndex--;
- }
-
- for (; bitIndex > -2 || workValue >= static_cast<uint64_t>(divisor); bitIndex--)
- {
- result <<= 1;
-
-
- if (workValue >= static_cast<uint64_t>(divisor))
- {
- workValue -= static_cast<uint64_t>(divisor);
- result++;
- }
-
- IL2CPP_ASSERT((workValue & (1LL << 63)) == 0 && "overflow!");
- if (bitIndex > -1)
- {
- workValue <<= 1;
- workValue |= (dividends[bitIndex / 64] & (kOne << (bitIndex % 64))) != 0;
- }
- }
-
- if (resultIsNegative)
- return -static_cast<int64_t>(result);
- return result;
- }
- }
- }
- }
|