Skip to content
Open
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
20 changes: 11 additions & 9 deletions include/cnl/_impl/charconv/descale.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
#include "../../integer.h"
#include "../../numeric_limits.h"
#include "../cstdint/types.h"
#include "../narrow_cast.h"
#include "../numbers/signedness.h"
#include "../scaled/declaration.h"
#include "../scaled/is_scaled_tag.h"
#include "../scaled/power/declaration.h"
#include "../unreachable.h"

/// compositional numeric library
Expand All @@ -26,9 +28,9 @@ namespace cnl::_impl {
template<
integer Significand = int64, int OutRadix = 10,
bool Precise = false,
int InExponent = 0, int InRadix = 2,
scaled_tag InScale = power<>,
integer Rep = int>
[[nodiscard]] constexpr auto descale(Rep const& input, power<InExponent, InRadix>)
[[nodiscard]] constexpr auto descale(Rep const& input, InScale)
{
descaled<Significand, OutRadix> output{static_cast<Significand>(input), 0};

Expand All @@ -49,10 +51,10 @@ namespace cnl::_impl {
return n > Significand{numeric_limits<Significand>::max() / OutRadix};
}};

if constexpr (InExponent < 0) {
for (int in_exponent = InExponent;
if constexpr (exponent_v<InScale> < 0) {
for (int in_exponent = exponent_v<InScale>;
in_exponent != 0 || (Precise && !(output.significand % OutRadix));) {
if (output.significand % InRadix) {
if (output.significand % radix_v<InScale>) {
if (oob(output.significand)) {
if (Precise) {
return unreachable<descaled<Significand, OutRadix>>("number cannot be represented in this form");
Expand All @@ -64,11 +66,11 @@ namespace cnl::_impl {
}
}

output.significand /= InRadix;
output.significand = narrow_cast<Significand>(output.significand / radix_v<InScale>);
in_exponent++;
}
} else {
for (int in_exponent = InExponent;
for (int in_exponent = exponent_v<InScale>;
in_exponent != 0 || !(output.significand % OutRadix);) {
if (!(output.significand % OutRadix)) {
output.significand /= OutRadix;
Expand All @@ -77,7 +79,7 @@ namespace cnl::_impl {
}

if (!oob(output.significand)) {
output.significand *= InRadix;
output.significand *= radix_v<InScale>;
in_exponent--;
}
}
Expand Down
64 changes: 37 additions & 27 deletions include/cnl/_impl/scaled/binary_operator.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,22 @@
// (See accompanying file ../LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#if !defined(CNL_IMPL_SCALED_BINARY_OPERATOR_H)
#define CNL_IMPL_SCALED_BINARY_OPERATOR_H
#if !defined(CNL_IMPL_SCALED_POWER_BINARY_OPERATOR_H)
#define CNL_IMPL_SCALED_POWER_BINARY_OPERATOR_H

#include "../custom_operator/definition.h"
#include "../custom_operator/tagged.h"
#include "../num_traits/scale.h"
#include "definition.h"
// #include "definition.h"
#include "is_scaled_tag.h"

#include <algorithm>

/// compositional numeric library
namespace cnl {
template<_impl::binary_op Operator, typename Lhs, typename Rhs, int Exponent, int Radix>
struct custom_operator<Operator, op_value<Lhs, power<Exponent, Radix>>, op_value<Rhs, power<Exponent, Radix>>>
template<_impl::binary_op Operator, integer LhsRep, integer RhsRep, scaled_tag Scale>
// requires(!std::is_same_v<Operator, _impl::divide_op>)
struct custom_operator<Operator, op_value<LhsRep, Scale>, op_value<RhsRep, Scale>>
: Operator {
};

Expand All @@ -37,44 +38,53 @@ namespace cnl {
};
}

template<_impl::binary_op Operator, typename Lhs, int LhsExponent, int RhsExponent, typename Rhs, int Radix>
requires(LhsExponent != RhsExponent && _impl::is_zero_degree<Operator>::value) struct custom_operator<
template<
_impl::binary_op Operator,
integer LhsRep, scaled_tag LhsScale,
integer RhsRep, scaled_tag RhsScale>
requires(_impl::is_zero_degree<Operator>::value&& _impl::exponent_v<LhsScale> != _impl::exponent_v<RhsScale> && _impl::radix_v<LhsScale> == _impl::radix_v<RhsScale>) struct custom_operator<
Operator,
op_value<Lhs, power<LhsExponent, Radix>>,
op_value<Rhs, power<RhsExponent, Radix>>> {
op_value<LhsRep, LhsScale>,
op_value<RhsRep, RhsScale>> {
private:
static constexpr int _common_exponent = std::min(LhsExponent, RhsExponent);
using common_power = power<_common_exponent, Radix>;
static constexpr int _lhs_left_shift = LhsExponent - _common_exponent;
static constexpr int _rhs_left_shift = RhsExponent - _common_exponent;

public:
[[nodiscard]] constexpr auto operator()(Lhs const& lhs, Rhs const& rhs) const
[[nodiscard]] constexpr auto operator()(LhsRep const& lhs, RhsRep const& rhs) const
{
return _impl::operate<Operator, common_power>{}(
_impl::scale<_lhs_left_shift, Radix>(lhs),
_impl::scale<_rhs_left_shift, Radix>(rhs));
constexpr auto lhs_exponent = _impl::exponent_v<LhsScale>;
constexpr auto rhs_exponent = _impl::exponent_v<RhsScale>;
constexpr auto common_exponent = std::min(lhs_exponent, rhs_exponent);
using common_scale = std::conditional_t<(lhs_exponent < rhs_exponent), LhsScale, RhsScale>;
constexpr auto common_radix = _impl::radix_v<common_scale>;
constexpr int lhs_left_shift = lhs_exponent - common_exponent;
constexpr int rhs_left_shift = rhs_exponent - common_exponent;

return _impl::operate<Operator, common_scale>{}(
_impl::scale<lhs_left_shift, common_radix>(lhs),
_impl::scale<rhs_left_shift, common_radix>(rhs));
}
};

template<_impl::binary_op Operator, typename Lhs, int LhsExponent, typename Rhs, int RhsExponent, int Radix>
requires(LhsExponent != RhsExponent && !_impl::is_zero_degree<Operator>::value) struct custom_operator<
template<
_impl::binary_op Operator,
integer LhsRep, scaled_tag LhsScale,
integer RhsRep, scaled_tag RhsScale>
requires(!_impl::is_zero_degree<Operator>::value && _impl::exponent_v<LhsScale> != _impl::exponent_v<RhsScale> && _impl::radix_v<LhsScale> == _impl::radix_v<RhsScale>) struct custom_operator<
Operator,
op_value<Lhs, power<LhsExponent, Radix>>,
op_value<Rhs, power<RhsExponent, Radix>>>
op_value<LhsRep, LhsScale>,
op_value<RhsRep, RhsScale>>
: Operator {
};

template<_impl::shift_op Operator, typename LhsRep, scaled_tag LhsTag, typename Rhs>
requires(!_impl::is_constant<Rhs>::value) struct custom_operator<
template<_impl::shift_op Operator, integer LhsRep, scaled_tag LhsTag, integer RhsRep>
requires(!_impl::is_constant<RhsRep>::value) struct custom_operator<
Operator,
op_value<LhsRep, LhsTag>,
op_value<Rhs>> {
[[nodiscard]] constexpr auto operator()(LhsRep const& lhs, Rhs const& rhs) const
op_value<RhsRep>> {
[[nodiscard]] constexpr auto operator()(LhsRep const& lhs, RhsRep const& rhs) const
{
return Operator{}(lhs, rhs);
}
};
}

#endif // CNL_IMPL_SCALED_BINARY_OPERATOR_H
#endif // CNL_IMPL_SCALED_POWER_BINARY_OPERATOR_H
119 changes: 56 additions & 63 deletions include/cnl/_impl/scaled/convert_operator.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,140 +15,133 @@
#include "../num_traits/scale.h"
#include "../power_value.h"
#include "../scaled_integer/definition.h"
#include "is_same_tag_family.h"
#include "power.h"
#include "is_scaled_tag.h"

/// compositional numeric library
namespace cnl {
// integer -> floating
template<integer Src, int SrcExponent, floating_point Dest, int DestExponent, int Radix>
struct custom_operator<
template<integer Src, scaled_tag SrcScale, floating_point Dest, scaled_tag DestScale>
requires(_impl::radix_v<SrcScale> == _impl::radix_v<DestScale>) struct custom_operator<
_impl::convert_op,
op_value<Src, power<SrcExponent, Radix>>,
op_value<Dest, power<DestExponent, Radix>>> {
op_value<Src, SrcScale>,
op_value<Dest, DestScale>> {
[[nodiscard]] constexpr auto operator()(Src const& from) const
{
return Dest(from) * _impl::power_value<Dest, SrcExponent - DestExponent, Radix>();
return Dest(from)
* _impl::power_value<Dest, _impl::exponent_v<SrcScale> - _impl::exponent_v<DestScale>, _impl::radix_v<SrcScale>>();
}
};

// floating -> integer
template<floating_point Input, int SrcExponent, integer Result, int DestExponent, int Radix>
struct custom_operator<
template<floating_point Input, scaled_tag SrcScale, integer Result, scaled_tag DestScale>
requires(_impl::radix_v<SrcScale> == _impl::radix_v<DestScale>) struct custom_operator<
_impl::convert_op,
op_value<Input, power<SrcExponent, Radix>>,
op_value<Result, power<DestExponent, Radix>>> {
op_value<Input, SrcScale>,
op_value<Result, DestScale>> {
[[nodiscard]] constexpr auto operator()(Input const& from) const
{
return static_cast<Result>(
from * _impl::power_value<Input, SrcExponent - DestExponent, Radix>());
from * _impl::power_value<Input, _impl::exponent_v<SrcScale> - _impl::exponent_v<DestScale>, _impl::radix_v<SrcScale>>());
}
};

// integer -> integer (same Radix)
template<integer Input, int SrcExponent, integer Result, int DestExponent, int Radix>
struct custom_operator<
template<integer Input, scaled_tag SrcScale, integer Result, scaled_tag DestScale>
requires(_impl::radix_v<SrcScale> == _impl::radix_v<DestScale>) struct custom_operator<
_impl::convert_op,
op_value<Input, power<SrcExponent, Radix>>, op_value<Result, power<DestExponent, Radix>>> {
op_value<Input, SrcScale>, op_value<Result, DestScale>> {
[[nodiscard]] constexpr auto operator()(Input const& from) const
{
// when converting *from* scaled_integer
return static_cast<Result>(_impl::scale<SrcExponent - DestExponent, Radix>(
return static_cast<Result>(_impl::scale<_impl::exponent_v<SrcScale> - _impl::exponent_v<DestScale>, _impl::radix_v<SrcScale>>(
_impl::from_value<Result>(from)));
}
};

// integer -> integer (different Ridixes)
template<
integer Input, int SrcExponent, int SrcRadix,
integer Result, int DestExponent, int DestRadix>
integer Input, scaled_tag SrcScale,
integer Result, scaled_tag DestScale>
struct custom_operator<
_impl::convert_op,
op_value<Input, power<SrcExponent, SrcRadix>>,
op_value<Result, power<DestExponent, DestRadix>>> {
op_value<Input, SrcScale>,
op_value<Result, DestScale>> {
[[nodiscard]] constexpr auto operator()(Input const& from) const
{
constexpr auto src_exponent{_impl::exponent_v<SrcScale>};
constexpr auto src_radix{_impl::radix_v<SrcScale>};
constexpr auto dest_exponent{_impl::exponent_v<DestScale>};
constexpr auto dest_radix{_impl::radix_v<DestScale>};

auto result{_impl::from_value<Result>(from)};
if constexpr (SrcExponent > 0) {
result = _impl::scale<SrcExponent, SrcRadix>(result);
if constexpr (src_exponent > 0) {
result = _impl::scale<src_exponent, src_radix>(result);
}
if constexpr (DestExponent < 0) {
result = _impl::scale<-DestExponent, DestRadix>(result);
if constexpr (dest_exponent < 0) {
result = _impl::scale<-dest_exponent, dest_radix>(result);
}
if constexpr (SrcExponent < 0) {
result = _impl::scale<SrcExponent, SrcRadix>(result);
if constexpr (src_exponent < 0) {
result = _impl::scale<src_exponent, src_radix>(result);
}
if constexpr (DestExponent > 0) {
result = _impl::scale<-DestExponent, DestRadix>(result);
if constexpr (dest_exponent > 0) {
result = _impl::scale<-dest_exponent, dest_radix>(result);
}
return result;
}
};

// shims between equivalent tags
template<typename Input, typename Result, int DestExponent, int DestRadix>
struct custom_operator<_impl::convert_op, op_value<Input>, op_value<Result, power<DestExponent, DestRadix>>>
template<typename Input, typename Result, scaled_tag DestScale>
struct custom_operator<_impl::convert_op, op_value<Input>, op_value<Result, DestScale>>
: custom_operator<
_impl::convert_op,
op_value<Input, power<0, DestRadix>>,
op_value<Result, power<DestExponent, DestRadix>>> {
op_value<Input, power<0, _impl::radix_v<DestScale>>>,
op_value<Result, DestScale>> {
};

template<typename Input, int SrcExponent, int SrcRadix, typename Result>
struct custom_operator<_impl::convert_op, op_value<Input, power<SrcExponent, SrcRadix>>, op_value<Result>>
: custom_operator<_impl::convert_op, op_value<Input, power<SrcExponent, SrcRadix>>, op_value<Result, power<0, SrcRadix>>> {
template<typename Input, scaled_tag SrcScale, typename Result>
struct custom_operator<_impl::convert_op, op_value<Input, SrcScale>, op_value<Result>>
: custom_operator<_impl::convert_op, op_value<Input, SrcScale>, op_value<Result, power<0, _impl::radix_v<SrcScale>>>> {
};

////////////////////////////////////////////////////////////////////////////////
// conversion from fraction

namespace _impl {
template<typename Number>
[[nodiscard]] constexpr auto not_scaled_integer(Number const& n)
{
return n;
}
// template<integer Rep, scaled_tag Scale>
// [[nodiscard]] constexpr auto not_scaled_integer(
// scaled_integer<Rep, Scale> const& f)
// {
// return _impl::to_rep(f);
// }

template<typename Rep, int Exponent, int Radix>
[[nodiscard]] constexpr auto not_scaled_integer(
scaled_integer<Rep, power<Exponent, Radix>> const& f)
{
return _impl::to_rep(f);
}

template<typename Number>
struct exponent : constant<0> {
};

template<typename Rep, int Exponent, int Radix>
struct exponent<scaled_integer<Rep, power<Exponent, Radix>>> : constant<Exponent> {
};
// template<integer Rep, scaled_tag Scale>
// inline constexpr auto exponent_v<scaled_integer<Rep, Scale>> = Exponent;

template<class Quotient, class Dividend, class Divisor>
struct exponent_shift
: std::integral_constant<
int, _impl::exponent<Dividend>::value - _impl::exponent<Divisor>::value
- _impl::exponent<Quotient>::value> {
int,
_impl::exponent_v<Dividend> - _impl::exponent_v<Divisor> - _impl::exponent_v<Quotient>> {
};
}

template<
typename SrcNumerator, typename SrcDenominator,
typename Dest, int DestExponent, int Radix>
typename Dest, scaled_tag DestScale>
struct custom_operator<
_impl::convert_op,
op_value<cnl::fraction<SrcNumerator, SrcDenominator>, cnl::power<0, Radix>>,
op_value<Dest, cnl::power<DestExponent, Radix>>> {
op_value<cnl::fraction<SrcNumerator, SrcDenominator>, typename DestScale::identity>,
op_value<Dest, DestScale>> {
[[nodiscard]] constexpr auto operator()(
cnl::fraction<SrcNumerator, SrcDenominator> const& from) const
{
static_assert(_impl::exponent<Dest>::value == 0, "TODO");
static_assert(_impl::exponent_v<Dest> == 0, "TODO");

return static_cast<Dest>(
_impl::fixed_width_scale<
_impl::exponent<SrcNumerator>::value
- _impl::exponent<SrcDenominator>::value - DestExponent,
Radix>(static_cast<Dest>(_impl::not_scaled_integer(from.numerator)))
_impl::exponent_v<SrcNumerator> - _impl::exponent_v<SrcDenominator> - _impl::exponent_v<DestScale>,
_impl::radix_v<DestScale>>(static_cast<Dest>(_impl::not_scaled_integer(from.numerator)))
/ _impl::not_scaled_integer(from.denominator));
}
};
Expand Down
10 changes: 5 additions & 5 deletions include/cnl/_impl/scaled/is_same_tag_family.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
// (See accompanying file ../LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#if !defined(CNL_IMPL_SCALED_IS_SAME_TAG_FAMILY_H)
#define CNL_IMPL_SCALED_IS_SAME_TAG_FAMILY_H
#if !defined(CNL_IMPL_SCALED_POWER_IS_SAME_TAG_FAMILY_H)
#define CNL_IMPL_SCALED_POWER_IS_SAME_TAG_FAMILY_H

#include "../custom_operator/is_same_tag_family.h"
#include "is_scaled_tag.h"
Expand All @@ -15,11 +15,11 @@
/// compositional numeric library
namespace cnl {
namespace _impl {
template<int Exponent1, int Radix1, int Exponent2, int Radix2>
struct is_same_tag_family<power<Exponent1, Radix1>, power<Exponent2, Radix2>>
template<scaled_tag Tag1, scaled_tag Tag2>
struct is_same_tag_family<Tag1, Tag2>
: std::true_type {
};
}
}

#endif // CNL_IMPL_SCALED_IS_SAME_TAG_FAMILY_H
#endif // CNL_IMPL_SCALED_POWER_IS_SAME_TAG_FAMILY_H
Loading