Skip to content

Commit

Permalink
ipow10 optimization as most usages are with 10 base
Browse files Browse the repository at this point in the history
  • Loading branch information
sjanel committed Oct 24, 2023
1 parent 0c50407 commit a3563d0
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 38 deletions.
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

0 comments on commit a3563d0

Please sign in to comment.