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

Sync sdks 6 #318

Merged
merged 2 commits into from
Sep 12, 2024
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/library/yql_common/decimal/yql_decimal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ TInt128 FromString(const std::string_view& str, ui8 precision, ui8 scale) {
if (IsInf(s))
return neg ? -Inf() : Inf();
if (IsNan(s))
return neg ? -Nan() : Nan();
return Nan();
}

TUint128 v = 0U;
Expand Down
182 changes: 182 additions & 0 deletions src/library/yql_common/decimal/yql_decimal.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,5 +156,187 @@ TInt128 MulAndDivNormalDivider(TInt128 a, TInt128 b, TInt128 c);
// a*b/c Only for non zero normal positive multiplier.
TInt128 MulAndDivNormalMultiplier(TInt128 a, TInt128 b, TInt128 c);

struct TDecimal {
TInt128 Value = 0;

TDecimal() = default;

template<typename T>
TDecimal(T t): Value(t) { }

explicit operator TInt128() const {
return Value;
}

TDecimal& operator+=(TDecimal right) {
const auto l = Value;
const auto r = right.Value;
const auto a = l + r;
if (IsNormal(l) && IsNormal(r) && IsNormal(a)) {
Value = a;
} else if (IsNan(l) || IsNan(r) || !a /* inf - inf*/) {
Value = Nan();
} else {
Value = a > 0
? +Inf()
: -Inf();
}
return *this;
}

TDecimal& operator*=(TDecimal right) {
Value = Mul(Value, right.Value);
return *this;
}

TDecimal& operator/=(TDecimal right) {
Value = Div(Value, right.Value);
return *this;
}

friend TDecimal operator+(TDecimal left, TDecimal right) {
left += right;
return left;
}

friend TDecimal operator*(TDecimal left, TDecimal right) {
left *= right;
return left;
}

friend TDecimal operator/(TDecimal left, TDecimal right) {
left /= right;
return left;
}
};

template<typename TRight>
class TDecimalMultiplicator {
protected:
const TInt128 Bound;

public:
TDecimalMultiplicator(
ui8 precision,
[[maybe_unused]] ui8 scale = 0)
: Bound(GetDivider(precision))
{
}

TInt128 Do(TInt128 left, TRight right) const {
TInt128 mul = Mul(left, right);

if (mul > -Bound && mul < +Bound)
return mul;

return IsNan(mul) ? Nan() : (mul > 0 ? +Inf() : -Inf());
}
};

template<>
class TDecimalMultiplicator<TInt128> {
protected:
const TInt128 Bound;
const TInt128 Divider;

public:
TDecimalMultiplicator(
ui8 precision,
ui8 scale)
: Bound(GetDivider(precision))
, Divider(GetDivider(scale))
{ }

TInt128 Do(TInt128 left, TInt128 right) const {
TInt128 mul = Divider > 1 ?
MulAndDivNormalDivider(left, right, Divider):
Mul(left, right);

if (mul > -Bound && mul < +Bound)
return mul;

return IsNan(mul) ? Nan() : (mul > 0 ? +Inf() : -Inf());
}
};

template<typename TRight>
class TDecimalDivisor {
public:
TDecimalDivisor(
[[maybe_unused]] ui8 precision = 0,
[[maybe_unused]] ui8 scale = 0)
{
}

TInt128 Do(TInt128 left, TRight right) const {
return Div(left, right);
}
};

template<>
class TDecimalDivisor<TInt128> {
protected:
const TInt128 Bound;
const TInt128 Divider;

public:
TDecimalDivisor(
ui8 precision,
ui8 scale)
: Bound(GetDivider(precision))
, Divider(GetDivider(scale))
{ }

TInt128 Do(TInt128 left, TInt128 right) const {
TInt128 div = MulAndDivNormalMultiplier(left, Divider, right);
if (div > -Bound && div < +Bound) {
return div;
}

return IsNan(div) ? Nan() : (div > 0 ? +Inf() : -Inf());
}
};

template<typename TRight>
class TDecimalRemainder {
protected:
const TInt128 Bound;
const TInt128 Divider;

public:
TDecimalRemainder(
ui8 precision,
ui8 scale)
: Bound(NYql::NDecimal::GetDivider(precision - scale))
, Divider(NYql::NDecimal::GetDivider(scale))
{ }

TInt128 Do(TInt128 left, TRight right) const {
if constexpr (std::is_signed<TRight>::value) {
if (right >= +Bound || right <= -Bound)
return left;
} else {
if (right >= Bound)
return left;
}

return Mod(left, Mul(Divider, right));
}
};

template<>
class TDecimalRemainder<TInt128> {
public:
TDecimalRemainder(
[[maybe_unused]] ui8 precision = 0,
[[maybe_unused]] ui8 scale = 0)
{
}

TInt128 Do(TInt128 left, TInt128 right) const {
return NYql::NDecimal::Mod(left, right);
}
};

}
}
Loading