Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ipow10 optimization as most usages are with 10 base #465

Merged
merged 1 commit into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/api/common/src/ssl_sha.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ std::string_view GetOpenSSLVersion() { return OPENSSL_VERSION_TEXT; }

Md ShaBin(ShaType shaType, std::string_view data, std::string_view secret) {
unsigned int len = ShaDigestLen(shaType);
Md binData(len, 0);
Md binData(static_cast<Md::size_type>(len), 0);

HMAC(GetEVPMD(shaType), secret.data(), static_cast<int>(secret.size()),
reinterpret_cast<const unsigned char*>(data.data()), data.size(),
Expand Down
25 changes: 12 additions & 13 deletions src/engine/src/exchangesorchestrator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -378,29 +378,28 @@ ExchangeAmountMarketsPathVector FilterConversionPaths(const ExchangeAmountPairVe
const TradeOptions &tradeOptions) {
ExchangeAmountMarketsPathVector ret;

int nbExchanges = static_cast<int>(exchangeAmountPairVector.size());
int publicExchangePos = -1;
constexpr bool considerStableCoinsAsFiats = false;
api::ExchangePublic *pExchangePublic = nullptr;
for (int exchangePos = 0; exchangePos < nbExchanges; ++exchangePos) {
const auto &exchangeAmountPair = exchangeAmountPairVector[exchangePos];
if (pExchangePublic != &exchangeAmountPair.first->apiPublic()) {
pExchangePublic = &exchangeAmountPair.first->apiPublic();
for (const auto &[exchangePtr, exchangeAmount] : exchangeAmountPairVector) {
if (pExchangePublic != &exchangePtr->apiPublic()) {
pExchangePublic = &exchangePtr->apiPublic();
++publicExchangePos;
}
api::ExchangePublic &exchangePublic = *pExchangePublic;

MarketSet &markets = marketsPerPublicExchange[publicExchangePos];
MarketsPath marketsPath =
pExchangePublic->findMarketsPath(fromCurrency, toCurrency, markets, fiats, considerStableCoinsAsFiats);
exchangePublic.findMarketsPath(fromCurrency, toCurrency, markets, fiats, considerStableCoinsAsFiats);
const int nbMarketsInPath = static_cast<int>(marketsPath.size());
if (nbMarketsInPath == 1 ||
(nbMarketsInPath > 1 &&
tradeOptions.isMultiTradeAllowed(pExchangePublic->exchangeInfo().multiTradeAllowedByDefault()))) {
ret.emplace_back(exchangeAmountPair.first, exchangeAmountPair.second, std::move(marketsPath));
tradeOptions.isMultiTradeAllowed(exchangePublic.exchangeInfo().multiTradeAllowedByDefault()))) {
ret.emplace_back(exchangePtr, exchangeAmount, std::move(marketsPath));
} else {
log::warn("{} is not convertible{} to {} on {}", fromCurrency,
nbMarketsInPath == 0 ? "" : "directly (and multi trade is not allowed)", toCurrency,
pExchangePublic->name());
exchangePublic.name());
}
}
return ret;
Expand All @@ -411,10 +410,10 @@ ExchangeAmountPairVector ComputeExchangeAmountPairVector(CurrencyCode fromCurren
// Retrieve amount per start amount currency for each exchange
ExchangeAmountPairVector exchangeAmountPairVector;

for (const auto &exchangeBalancePair : balancePerExchange) {
MonetaryAmount avAmount = exchangeBalancePair.second.get(fromCurrency);
for (const auto &[exchangePtr, balancePortfolio] : balancePerExchange) {
MonetaryAmount avAmount = balancePortfolio.get(fromCurrency);
if (avAmount > 0) {
exchangeAmountPairVector.emplace_back(exchangeBalancePair.first, avAmount);
exchangeAmountPairVector.emplace_back(exchangePtr, avAmount);
}
}

Expand Down Expand Up @@ -547,7 +546,7 @@ TradedAmountsPerExchange ExchangesOrchestrator::smartBuy(MonetaryAmount endAmoun
constexpr bool considerStableCoinsAsFiats = false;
for (int nbSteps = 1;; ++nbSteps) {
bool continuingHigherStepsPossible = false;
const int nbTrades = trades.size();
const int nbTrades = static_cast<int>(trades.size());
int publicExchangePos = -1;
api::ExchangePublic *pExchangePublic = nullptr;
for (auto &[pExchange, balance] : balancePerExchange) {
Expand Down
12 changes: 6 additions & 6 deletions src/objects/include/monetaryamount.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class MonetaryAmount {

/// Get the integer part of the amount of this MonetaryAmount.
[[nodiscard]] constexpr AmountType integerPart() const {
return _amount / ipow(10, static_cast<uint8_t>(nbDecimals()));
return _amount / ipow10(static_cast<uint8_t>(nbDecimals()));
}

/// Get the decimal part of the amount of this MonetaryAmount.
Expand All @@ -116,7 +116,7 @@ class MonetaryAmount {

/// Get the amount of this MonetaryAmount in double format.
[[nodiscard]] constexpr double toDouble() const {
return static_cast<double>(_amount) / ipow(10, static_cast<uint8_t>(nbDecimals()));
return static_cast<double>(_amount) / ipow10(static_cast<uint8_t>(nbDecimals()));
}

/// Check if given amount is close to this amount.
Expand Down Expand Up @@ -168,11 +168,11 @@ class MonetaryAmount {
friend constexpr bool operator==(AmountType amount, MonetaryAmount rhs) { return rhs == amount; }

[[nodiscard]] constexpr auto operator<=>(AmountType amount) const {
return _amount <=> amount * ipow(10, static_cast<uint8_t>(nbDecimals()));
return _amount <=> amount * ipow10(static_cast<uint8_t>(nbDecimals()));
}

[[nodiscard]] friend constexpr auto operator<=>(AmountType amount, MonetaryAmount other) {
return amount * ipow(10, static_cast<uint8_t>(other.nbDecimals())) <=> other._amount;
return amount * ipow10(static_cast<uint8_t>(other.nbDecimals())) <=> other._amount;
}

[[nodiscard]] constexpr MonetaryAmount abs() const noexcept {
Expand Down Expand Up @@ -337,7 +337,7 @@ class MonetaryAmount {
private:
using UnsignedAmountType = uint64_t;

static constexpr AmountType kMaxAmountFullNDigits = ipow(10, std::numeric_limits<AmountType>::digits10);
static constexpr AmountType kMaxAmountFullNDigits = ipow10(std::numeric_limits<AmountType>::digits10);
static constexpr std::size_t kMaxNbCharsAmount = std::numeric_limits<AmountType>::digits10 + 3;

void appendCurrencyStr(string &str) const {
Expand All @@ -354,7 +354,7 @@ class MonetaryAmount {
constexpr void sanitizeDecimals(int8_t nowNbDecimals, int8_t maxNbDecimals) noexcept {
const int8_t nbDecimalsToTruncate = nowNbDecimals - maxNbDecimals;
if (nbDecimalsToTruncate > 0) {
_amount /= ipow(10, static_cast<uint8_t>(nbDecimalsToTruncate));
_amount /= ipow10(static_cast<uint8_t>(nbDecimalsToTruncate));
nowNbDecimals -= nbDecimalsToTruncate;
}
simplifyDecimals(nowNbDecimals);
Expand Down
27 changes: 13 additions & 14 deletions src/objects/src/monetaryamount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ inline std::pair<MonetaryAmount::AmountType, int8_t> AmountIntegralFromStr(std::
}
}

ret.first = integerPart * ipow(10, ret.second) + decPart + roundingUpNinesDouble;
ret.first = integerPart * ipow10(ret.second) + decPart + roundingUpNinesDouble;
return ret;
}

Expand Down Expand Up @@ -200,7 +200,7 @@ std::optional<MonetaryAmount::AmountType> MonetaryAmount::amount(int8_t nbDecima
}

constexpr MonetaryAmount::AmountType MonetaryAmount::decimalPart() const {
auto div = ipow(10, static_cast<uint8_t>(nbDecimals()));
auto div = ipow10(static_cast<uint8_t>(nbDecimals()));
return _amount - (_amount / div) * div;
}

Expand Down Expand Up @@ -271,7 +271,7 @@ void MonetaryAmount::round(int8_t nbDecimals, RoundType roundType) {
_amount *= 10;
}
if (nbDecimals < currentNbDecimals) {
const AmountType epsilon = ipow(10, currentNbDecimals - nbDecimals);
const AmountType epsilon = ipow10(currentNbDecimals - nbDecimals);
if (_amount < 0) {
if (roundType != RoundType::kUp) {
const AmountType rem = epsilon + (_amount % epsilon);
Expand Down Expand Up @@ -360,22 +360,21 @@ MonetaryAmount MonetaryAmount::operator+(MonetaryAmount other) const {

MonetaryAmount MonetaryAmount::operator*(AmountType mult) const {
AmountType amount = _amount;
int8_t nbDecs = nbDecimals();
auto nbDecs = nbDecimals();
if (mult < -1 || mult > 1) { // for * -1, * 0 and * -1 result is trivial without overflow
// Beware of overflows, they can come faster than we think with multiplications.
int nbDigitsMult = ndigits(mult);
int nbDigitsAmount = ndigits(_amount);
int nbDigitsToTruncate = nbDigitsAmount + nbDigitsMult - std::numeric_limits<AmountType>::digits10;
const auto nbDigitsMult = ndigits(mult);
const auto nbDigitsAmount = ndigits(_amount);
const auto nbDigitsToTruncate = nbDigitsAmount + nbDigitsMult - std::numeric_limits<AmountType>::digits10;
if (nbDigitsToTruncate > 0) {
log::trace("Reaching numeric limits of MonetaryAmount for {} * {}, truncate {} digits", _amount, mult,
nbDigitsToTruncate);
amount /= ipow(10, static_cast<uint8_t>(nbDigitsToTruncate));
if (nbDecs >= nbDigitsToTruncate) {
nbDecs -= nbDigitsToTruncate;
amount /= ipow10(static_cast<uint8_t>(nbDigitsToTruncate));
if (static_cast<decltype(nbDigitsToTruncate)>(nbDecs) >= nbDigitsToTruncate) {
nbDecs -= static_cast<decltype(nbDecs)>(nbDigitsToTruncate);
} else {
log::warn("Cannot truncate decimal part, I need to truncate integral part");
}
nbDigitsToTruncate = 0;
}
}
return {amount * mult, _curWithDecimals, nbDecs};
Expand Down Expand Up @@ -444,7 +443,7 @@ MonetaryAmount MonetaryAmount::operator/(MonetaryAmount div) const {
int8_t lhsNbDigits = static_cast<int8_t>(ndigits(_amount));
const int8_t lhsNbDigitsToAdd = std::numeric_limits<UnsignedAmountType>::digits10 - lhsNbDigits;
UnsignedAmountType lhs =
static_cast<UnsignedAmountType>(std::abs(lhsAmount)) * ipow(10, static_cast<uint8_t>(lhsNbDigitsToAdd));
static_cast<UnsignedAmountType>(std::abs(lhsAmount)) * ipow10(static_cast<uint8_t>(lhsNbDigitsToAdd));
UnsignedAmountType rhs = static_cast<UnsignedAmountType>(std::abs(rhsAmount));

int8_t lhsNbDecimals = nbDecimals() + lhsNbDigitsToAdd;
Expand All @@ -464,7 +463,7 @@ MonetaryAmount MonetaryAmount::operator/(MonetaryAmount div) const {
if (nbDigitsToAdd == 0) {
break;
}
const auto multPower = ipow(10, static_cast<uint8_t>(nbDigitsToAdd));
const auto multPower = ipow10(static_cast<uint8_t>(nbDigitsToAdd));
totalIntPart *= multPower;
lhs *= multPower;
nbDecs += nbDigitsToAdd;
Expand All @@ -479,7 +478,7 @@ MonetaryAmount MonetaryAmount::operator/(MonetaryAmount div) const {
if (nbDecs < nbDigitsTruncate) {
throw exception("Overflow during divide");
}
totalIntPart /= ipow(10, static_cast<uint8_t>(nbDigitsTruncate));
totalIntPart /= ipow10(static_cast<uint8_t>(nbDigitsTruncate));
nbDecs -= nbDigitsTruncate;
}

Expand Down
8 changes: 4 additions & 4 deletions src/objects/test/monetaryamount_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -546,12 +546,12 @@ TEST(MonetaryAmountTest, Truncate) {

ma = MonetaryAmount(std::numeric_limits<MonetaryAmount::AmountType>::max(), CurrencyCode(), 18);
ma.round(MonetaryAmount(1, CurrencyCode(), 4), MonetaryAmount::RoundType::kNearest);
EXPECT_EQ(ma, MonetaryAmount(std::numeric_limits<MonetaryAmount::AmountType>::max() / ipow(10, 14) + 1L,
CurrencyCode(), 4));
EXPECT_EQ(
ma, MonetaryAmount(std::numeric_limits<MonetaryAmount::AmountType>::max() / ipow10(14) + 1L, CurrencyCode(), 4));
ma = MonetaryAmount(std::numeric_limits<MonetaryAmount::AmountType>::min(), CurrencyCode(), 18);
ma.round(MonetaryAmount(1, CurrencyCode(), 4), MonetaryAmount::RoundType::kDown);
EXPECT_EQ(ma, MonetaryAmount(std::numeric_limits<MonetaryAmount::AmountType>::min() / ipow(10, 14) - 1L,
CurrencyCode(), 4));
EXPECT_EQ(
ma, MonetaryAmount(std::numeric_limits<MonetaryAmount::AmountType>::min() / ipow10(14) - 1L, CurrencyCode(), 4));
}

TEST(MonetaryAmountTest, PositiveAmountStr) {
Expand Down
25 changes: 25 additions & 0 deletions src/tech/include/mathhelpers.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <array>
#include <concepts>
#include <cstdint>
#include <limits>
Expand Down Expand Up @@ -68,6 +69,30 @@ constexpr int64_t ipow(int64_t base, uint8_t exp) noexcept {
}
}

/// Optimization of ipow10( exp)
constexpr int64_t ipow10(uint8_t exp) noexcept {
constexpr const int64_t kPow10Table[] = {1LL,
10LL,
100LL,
1000LL,
10000LL,
100000LL,
1000000LL,
10000000LL,
100000000LL,
1000000000LL,
10000000000LL,
100000000000LL,
1000000000000LL,
10000000000000LL,
100000000000000LL,
1000000000000000LL,
10000000000000000LL,
100000000000000000LL,
1000000000000000000LL};
return exp < std::size(kPow10Table) ? kPow10Table[exp] : std::numeric_limits<int64_t>::max();
}

/// Return the number of digits of given integral.
/// The minus sign is not counted.
/// Uses dichotomy for highest performance as possible.
Expand Down
8 changes: 8 additions & 0 deletions src/tech/test/mathhelpers_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ TEST(MathHelpers, Power) {
static_assert(ipow(-7, 0) == 1);
}

TEST(MathHelpers, Power10) {
EXPECT_EQ(ipow10(0), 1);
EXPECT_EQ(ipow10(1), 10);
EXPECT_EQ(ipow10(2), 100);
EXPECT_EQ(ipow10(10), 10000000000);
static_assert(ipow10(3) == 1000);
}

TEST(MathHelpers, NDigitsS8) {
EXPECT_EQ(ndigits(static_cast<int8_t>(0)), 1);
EXPECT_EQ(ndigits(static_cast<int8_t>(3)), 1);
Expand Down
Loading