|
| 1 | + |
| 2 | +// Copyright John McFarlane 2019. |
| 3 | +// Distributed under the Boost Software License, Version 1.0. |
| 4 | +// (See accompanying file ../LICENSE_1_0.txt or copy at |
| 5 | +// http://www.boost.org/LICENSE_1_0.txt) |
| 6 | + |
| 7 | +#if !defined(CNL_IMPL_SCALED_CONVERT_OPERATOR_H) |
| 8 | +#define CNL_IMPL_SCALED_CONVERT_OPERATOR_H |
| 9 | + |
| 10 | +#include "../../floating_point.h" |
| 11 | +#include "../../fraction.h" |
| 12 | +#include "../../integer.h" |
| 13 | +#include "../custom_operator/native_tag.h" |
| 14 | +#include "../num_traits/fixed_width_scale.h" |
| 15 | +#include "../num_traits/scale.h" |
| 16 | +#include "../power_value.h" |
| 17 | +#include "../scaled_integer/definition.h" |
| 18 | +#include "is_scaled_tag.h" |
| 19 | + |
| 20 | +/// compositional numeric library |
| 21 | +namespace cnl { |
| 22 | + // integer -> floating |
| 23 | + template<integer Src, scaled_tag SrcScale, floating_point Dest, scaled_tag DestScale> |
| 24 | + requires(_impl::radix_v<SrcScale> == _impl::radix_v<DestScale>) struct custom_operator< |
| 25 | + _impl::convert_op, |
| 26 | + op_value<Src, SrcScale>, |
| 27 | + op_value<Dest, DestScale>> { |
| 28 | + [[nodiscard]] constexpr auto operator()(Src const& from) const |
| 29 | + { |
| 30 | + return Dest(from) |
| 31 | + * _impl::power_value<Dest, _impl::exponent_v<SrcScale> - _impl::exponent_v<DestScale>, _impl::radix_v<SrcScale>>(); |
| 32 | + } |
| 33 | + }; |
| 34 | + |
| 35 | + // floating -> integer |
| 36 | + template<floating_point Input, scaled_tag SrcScale, integer Result, scaled_tag DestScale> |
| 37 | + requires(_impl::radix_v<SrcScale> == _impl::radix_v<DestScale>) struct custom_operator< |
| 38 | + _impl::convert_op, |
| 39 | + op_value<Input, SrcScale>, |
| 40 | + op_value<Result, DestScale>> { |
| 41 | + [[nodiscard]] constexpr auto operator()(Input const& from) const |
| 42 | + { |
| 43 | + return static_cast<Result>( |
| 44 | + from * _impl::power_value<Input, _impl::exponent_v<SrcScale> - _impl::exponent_v<DestScale>, _impl::radix_v<SrcScale>>()); |
| 45 | + } |
| 46 | + }; |
| 47 | + |
| 48 | + // integer -> integer (same Radix) |
| 49 | + template<integer Input, scaled_tag SrcScale, integer Result, scaled_tag DestScale> |
| 50 | + requires(_impl::radix_v<SrcScale> == _impl::radix_v<DestScale>) struct custom_operator< |
| 51 | + _impl::convert_op, |
| 52 | + op_value<Input, SrcScale>, op_value<Result, DestScale>> { |
| 53 | + [[nodiscard]] constexpr auto operator()(Input const& from) const |
| 54 | + { |
| 55 | + // when converting *from* scaled_integer |
| 56 | + return static_cast<Result>(_impl::scale<_impl::exponent_v<SrcScale> - _impl::exponent_v<DestScale>, _impl::radix_v<SrcScale>>( |
| 57 | + _impl::from_value<Result>(from))); |
| 58 | + } |
| 59 | + }; |
| 60 | + |
| 61 | + // integer -> integer (different Ridixes) |
| 62 | + template< |
| 63 | + integer Input, scaled_tag SrcScale, |
| 64 | + integer Result, scaled_tag DestScale> |
| 65 | + struct custom_operator< |
| 66 | + _impl::convert_op, |
| 67 | + op_value<Input, SrcScale>, |
| 68 | + op_value<Result, DestScale>> { |
| 69 | + [[nodiscard]] constexpr auto operator()(Input const& from) const |
| 70 | + { |
| 71 | + constexpr auto src_exponent{_impl::exponent_v<SrcScale>}; |
| 72 | + constexpr auto src_radix{_impl::radix_v<SrcScale>}; |
| 73 | + constexpr auto dest_exponent{_impl::exponent_v<DestScale>}; |
| 74 | + constexpr auto dest_radix{_impl::radix_v<DestScale>}; |
| 75 | + |
| 76 | + auto result{_impl::from_value<Result>(from)}; |
| 77 | + if constexpr (src_exponent > 0) { |
| 78 | + result = _impl::scale<src_exponent, src_radix>(result); |
| 79 | + } |
| 80 | + if constexpr (dest_exponent < 0) { |
| 81 | + result = _impl::scale<-dest_exponent, dest_radix>(result); |
| 82 | + } |
| 83 | + if constexpr (src_exponent < 0) { |
| 84 | + result = _impl::scale<src_exponent, src_radix>(result); |
| 85 | + } |
| 86 | + if constexpr (dest_exponent > 0) { |
| 87 | + result = _impl::scale<-dest_exponent, dest_radix>(result); |
| 88 | + } |
| 89 | + return result; |
| 90 | + } |
| 91 | + }; |
| 92 | + |
| 93 | + // shims between equivalent tags |
| 94 | + template<typename Input, typename Result, scaled_tag DestScale> |
| 95 | + struct custom_operator<_impl::convert_op, op_value<Input>, op_value<Result, DestScale>> |
| 96 | + : custom_operator< |
| 97 | + _impl::convert_op, |
| 98 | + op_value<Input, power<0, _impl::radix_v<DestScale>>>, |
| 99 | + op_value<Result, DestScale>> { |
| 100 | + }; |
| 101 | + |
| 102 | + template<typename Input, scaled_tag SrcScale, typename Result> |
| 103 | + struct custom_operator<_impl::convert_op, op_value<Input, SrcScale>, op_value<Result>> |
| 104 | + : custom_operator<_impl::convert_op, op_value<Input, SrcScale>, op_value<Result, power<0, _impl::radix_v<SrcScale>>>> { |
| 105 | + }; |
| 106 | + |
| 107 | + //////////////////////////////////////////////////////////////////////////////// |
| 108 | + // conversion from fraction |
| 109 | + |
| 110 | + namespace _impl { |
| 111 | + // template<integer Rep, scaled_tag Scale> |
| 112 | + // [[nodiscard]] constexpr auto not_scaled_integer( |
| 113 | + // scaled_integer<Rep, Scale> const& f) |
| 114 | + // { |
| 115 | + // return _impl::to_rep(f); |
| 116 | + // } |
| 117 | + |
| 118 | + // template<integer Rep, scaled_tag Scale> |
| 119 | + // inline constexpr auto exponent_v<scaled_integer<Rep, Scale>> = Exponent; |
| 120 | + |
| 121 | + template<class Quotient, class Dividend, class Divisor> |
| 122 | + struct exponent_shift |
| 123 | + : std::integral_constant< |
| 124 | + int, |
| 125 | + _impl::exponent_v<Dividend> - _impl::exponent_v<Divisor> - _impl::exponent_v<Quotient>> { |
| 126 | + }; |
| 127 | + } |
| 128 | + |
| 129 | + template< |
| 130 | + typename SrcNumerator, typename SrcDenominator, |
| 131 | + typename Dest, scaled_tag DestScale> |
| 132 | + struct custom_operator< |
| 133 | + _impl::convert_op, |
| 134 | + op_value<cnl::fraction<SrcNumerator, SrcDenominator>, typename DestScale::identity>, |
| 135 | + op_value<Dest, DestScale>> { |
| 136 | + [[nodiscard]] constexpr auto operator()( |
| 137 | + cnl::fraction<SrcNumerator, SrcDenominator> const& from) const |
| 138 | + { |
| 139 | + static_assert(_impl::exponent_v<Dest> == 0, "TODO"); |
| 140 | + |
| 141 | + return static_cast<Dest>( |
| 142 | + _impl::fixed_width_scale< |
| 143 | + _impl::exponent_v<SrcNumerator> - _impl::exponent_v<SrcDenominator> - _impl::exponent_v<DestScale>, |
| 144 | + _impl::radix_v<DestScale>>(static_cast<Dest>(_impl::not_scaled_integer(from.numerator))) |
| 145 | + / _impl::not_scaled_integer(from.denominator)); |
| 146 | + } |
| 147 | + }; |
| 148 | +} |
| 149 | + |
| 150 | +#endif // CNL_IMPL_SCALED_CONVERT_OPERATOR_H |
0 commit comments