1//! @file apply_numeric.hpp
2//! @author ryftchen
3//! @brief The declarations (apply_numeric) in the application module.
4//! @version 0.1.0
5//! @copyright Copyright (c) 2022-2025 ryftchen. All rights reserved.
6
7#pragma once
8
9#ifndef _PRECOMPILED_HEADER
10#include <gsl/gsl_sf.h>
11#include <iostream>
12#include <numeric>
13#else
14#include "application/pch/precompiled_header.hpp"
15#endif // _PRECOMPILED_HEADER
16
17#include "numeric/include/arithmetic.hpp"
18#include "numeric/include/divisor.hpp"
19#include "numeric/include/integral.hpp"
20#include "numeric/include/prime.hpp"
21
22//! @brief The application module.
23namespace application // NOLINT(modernize-concat-nested-namespaces)
24{
25//! @brief Numeric-applying-related functions in the application module.
26namespace app_num
27{
28//! @brief Apply arithmetic.
29namespace arithmetic
30{
31//! @brief The version used to apply.
32const char* const version = numeric::arithmetic::version();
33
34//! @brief Set input parameters.
35namespace input
36{
37//! @brief One of operands for arithmetic methods.
38constexpr std::int32_t operandA = 46340;
39//! @brief One of operands for arithmetic methods.
40constexpr std::int32_t operandB = -46340;
41} // namespace input
42
43//! @brief Builder for the input.
44class InputBuilder
45{
46public:
47 //! @brief Construct a new InputBuilder object.
48 //! @param operand1 - first operand for elementary arithmetic
49 //! @param operand2 - second operand for elementary arithmetic
50 InputBuilder(const std::int32_t operand1, const std::int32_t operand2) : operand1{operand1}, operand2{operand2}
51 {
52#ifdef _RUNTIME_PRINTING
53 std::cout << "\nElementary arithmetic of " << operand1 << " and " << operand2 << ':' << std::endl;
54#endif // _RUNTIME_PRINTING
55 }
56
57 //! @brief Get the pair of operands.
58 //! @return pair of operands
59 [[nodiscard]] std::pair<std::int32_t, std::int32_t> getOperands() const noexcept
60 {
61 return std::make_pair(x: operand1, y: operand2);
62 }
63
64private:
65 //! @brief First operand for elementary arithmetic.
66 const std::int32_t operand1 : 17 {0};
67 //! @brief Second operand for elementary arithmetic.
68 const std::int32_t operand2 : 17 {0};
69};
70} // namespace arithmetic
71extern void applyingArithmetic(const std::vector<std::string>& candidates);
72
73//! @brief Apply divisor.
74namespace divisor
75{
76//! @brief The version used to apply.
77const char* const version = numeric::divisor::version();
78
79//! @brief Set input parameters.
80namespace input
81{
82//! @brief One of numbers for divisor methods.
83constexpr std::int32_t numberA = 2 * 2 * 3 * 3 * 5 * 5 * 7 * 7;
84//! @brief One of numbers for divisor methods.
85constexpr std::int32_t numberB = 2 * 3 * 5 * 7 * 11 * 13 * 17;
86} // namespace input
87
88//! @brief Maximum alignment length per element of printing.
89constexpr std::uint8_t maxAlignOfPrint = 16;
90//! @brief Maximum columns per row of printing.
91constexpr std::uint8_t maxColumnOfPrint = 5;
92
93//! @brief Builder for the input.
94class InputBuilder
95{
96public:
97 //! @brief Construct a new InputBuilder object.
98 //! @param number1 - first number
99 //! @param number2 - second number
100 InputBuilder(const std::int32_t number1, const std::int32_t number2) : number1{number1}, number2{number2}
101 {
102#ifdef _RUNTIME_PRINTING
103 std::cout << "\nAll common divisors of " << number1 << " and " << number2 << ':' << std::endl;
104#endif // _RUNTIME_PRINTING
105 }
106
107 //! @brief Get the pair of numbers.
108 //! @return pair of numbers
109 [[nodiscard]] std::pair<std::int32_t, std::int32_t> getNumbers() const noexcept
110 {
111 return std::make_pair(x: number1, y: number2);
112 }
113 //! @brief Splice all integers for printing.
114 //! @tparam Elem - type of element in container
115 //! @param container - integer container
116 //! @param fmtBuffer - buffer for printing
117 //! @param bufferSize - size of the buffer
118 //! @return buffer after splicing
119 template <std::integral Elem>
120 static char* spliceAllIntegers(
121 const std::set<Elem>& container, char* const fmtBuffer, const std::uint32_t bufferSize)
122 {
123 if (container.empty() || !fmtBuffer || (bufferSize == 0))
124 {
125 return fmtBuffer;
126 }
127
128 const std::uint32_t align = std::reduce(
129 container.cbegin(),
130 container.cend(),
131 0,
132 [](const auto max, const auto elem)
133 { return std::max<std::uint32_t>(std::to_string(elem).length(), max); });
134 std::uint32_t offset = 0;
135 for (auto iterator = container.cbegin(); iterator != container.cend(); ++iterator)
136 {
137 const std::uint32_t nextIdx = std::distance(container.cbegin(), iterator) + 1;
138 const char sep = ((nextIdx % maxColumnOfPrint == 0) && (nextIdx != container.size())) ? '\n' : ' ';
139 const int written =
140 std::snprintf(s: fmtBuffer + offset, maxlen: bufferSize - offset, format: "%*d%c", align + 1, *iterator, sep);
141 if ((written < 0) || (written >= static_cast<int>(bufferSize - offset)))
142 {
143 break;
144 }
145 offset += written;
146 }
147 return fmtBuffer;
148 }
149
150private:
151 //! @brief First number.
152 const std::int32_t number1{0};
153 //! @brief Second number.
154 const std::int32_t number2{0};
155};
156} // namespace divisor
157extern void applyingDivisor(const std::vector<std::string>& candidates);
158
159//! @brief Apply integral.
160namespace integral
161{
162//! @brief The version used to apply.
163const char* const version = numeric::integral::version();
164
165//! @brief Alias for the target expression.
166using Expression = std::function<double(const double)>;
167//! @brief Wrapper for the target expression.
168class ExprIntf
169{
170public:
171 //! @brief Construct a new ExprIntf object.
172 ExprIntf() = default;
173 //! @brief Destroy the ExprIntf object.
174 virtual ~ExprIntf() = default;
175 //! @brief Construct a new ExprIntf object.
176 ExprIntf(const ExprIntf&) = default;
177 //! @brief Construct a new ExprIntf object.
178 ExprIntf(ExprIntf&&) noexcept = default;
179 //! @brief The operator (=) overloading of ExprIntf class.
180 //! @return reference of the ExprIntf object
181 ExprIntf& operator=(const ExprIntf&) = default;
182 //! @brief The operator (=) overloading of ExprIntf class.
183 //! @return reference of the ExprIntf object
184 ExprIntf& operator=(ExprIntf&&) noexcept = default;
185
186 //! @brief The operator (()) overloading of ExprIntf class.
187 //! @param x - independent variable
188 //! @return dependent variable
189 virtual double operator()(const double x) const = 0;
190 //! @brief The operator (Expression) overloading of ExprIntf class.
191 //! @return Expression object
192 virtual explicit operator Expression() const
193 {
194 return [this](const double x) { return operator()(x); };
195 }
196};
197
198//! @brief Set input parameters.
199namespace input
200{
201//! @brief Cylindrical Bessel.
202class CylindricalBessel : public ExprIntf
203{
204public:
205 //! @brief The operator (()) overloading of CylindricalBessel class.
206 //! @param x - independent variable
207 //! @return dependent variable
208 double operator()(const double x) const override { return ::gsl_sf_bessel_J0(x); }
209
210 //! @brief Left endpoint.
211 static constexpr double range1{0.0};
212 //! @brief Right endpoint.
213 static constexpr double range2{20.0};
214 //! @brief Cylindrical Bessel function of the first kind.
215 static constexpr std::string_view exprDescr{"f(x)=J₀(x),x∈[0,20] (Cylindrical Bessel function of the first kind)"};
216};
217} // namespace input
218
219//! @brief Builder for the input.
220class InputBuilder
221{
222public:
223 //! @brief Construct a new Input Builder object.
224 //! @param expression - target expression
225 //! @param range1 - lower endpoint
226 //! @param range2 - upper endpoint
227 //! @param exprDescr - expression description
228 InputBuilder(
229 Expression expression,
230 const double range1,
231 const double range2,
232 [[maybe_unused]] const std::string_view exprDescr) :
233 expression{std::move(expression)}, range1{range1}, range2{range2}
234 {
235#ifdef _RUNTIME_PRINTING
236 std::cout << "\nIntegral expression:\n" << exprDescr << std::endl;
237#endif // _RUNTIME_PRINTING
238 }
239
240 //! @brief Get the target expression.
241 //! @return target expression
242 [[nodiscard]] Expression getExpression() const noexcept { return expression; }
243 //! @brief Get the pair of ranges.
244 //! @return pair of ranges
245 [[nodiscard]] std::pair<double, double> getRanges() const noexcept { return std::make_pair(x: range1, y: range2); }
246
247private:
248 //! @brief Target expression.
249 const Expression expression;
250 //! @brief Lower endpoint.
251 const double range1{0.0};
252 //! @brief Upper endpoint.
253 const double range2{0.0};
254};
255} // namespace integral
256extern void applyingIntegral(const std::vector<std::string>& candidates);
257
258//! @brief Apply prime.
259namespace prime
260{
261//! @brief The version used to apply.
262const char* const version = numeric::prime::version();
263
264//! @brief Set input parameters.
265namespace input
266{
267//! @brief Upper bound for prime methods.
268constexpr std::uint32_t upperBound = 997;
269} // namespace input
270
271//! @brief Maximum alignment length per element of printing.
272constexpr std::uint8_t maxAlignOfPrint = 16;
273//! @brief Maximum columns per row of printing.
274constexpr std::uint8_t maxColumnOfPrint = 10;
275
276//! @brief Builder for the input.
277class InputBuilder
278{
279public:
280 //! @brief Construct a new InputBuilder object.
281 //! @param upperBound - upper bound
282 explicit InputBuilder(const std::uint32_t upperBound) : upperBound{upperBound}
283 {
284#ifdef _RUNTIME_PRINTING
285 std::cout << "\nAll prime numbers smaller than " << upperBound << ':' << std::endl;
286#endif // _RUNTIME_PRINTING
287 }
288
289 //! @brief Get the upper bound.
290 //! @return upper bound
291 [[nodiscard]] std::uint32_t getUpperBound() const noexcept { return upperBound; }
292 //! @brief Splice all integers for printing.
293 //! @tparam Elem - type of element in container
294 //! @param container - integer container
295 //! @param fmtBuffer - buffer for printing
296 //! @param bufferSize - size of the buffer
297 //! @return buffer after splicing
298 template <std::integral Elem>
299 static char* spliceAllIntegers(
300 const std::vector<Elem>& container, char* const fmtBuffer, const std::uint32_t bufferSize)
301 {
302 if (container.empty() || !fmtBuffer || (bufferSize == 0))
303 {
304 return fmtBuffer;
305 }
306
307 const std::uint32_t align = std::reduce(
308 container.cbegin(),
309 container.cend(),
310 0,
311 [](const auto max, const auto elem)
312 { return std::max<std::uint32_t>(std::to_string(elem).length(), max); });
313 for (std::uint32_t i = 0, offset = 0; i < container.size(); ++i)
314 {
315 const char sep = (((i + 1) % maxColumnOfPrint == 0) && ((i + 1) != container.size())) ? '\n' : ' ';
316 const int written =
317 std::snprintf(s: fmtBuffer + offset, maxlen: bufferSize - offset, format: "%*d%c", align + 1, container.at(i), sep);
318 if ((written < 0) || (written >= static_cast<int>(bufferSize - offset)))
319 {
320 break;
321 }
322 offset += written;
323 }
324 return fmtBuffer;
325 }
326
327private:
328 //! @brief Upper bound.
329 const std::uint32_t upperBound{0};
330};
331} // namespace prime
332extern void applyingPrime(const std::vector<std::string>& candidates);
333} // namespace app_num
334} // namespace application
335