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-2026 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
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.
38inline constexpr std::int32_t operandA = 46340;
39//! @brief One of operands for arithmetic methods.
40inline constexpr 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
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.
83inline constexpr std::int32_t numberA = 2 * 2 * 3 * 3 * 5 * 5 * 7 * 7;
84//! @brief One of numbers for divisor methods.
85inline constexpr 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
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 AsExpression
169{
170public:
171 //! @brief Destroy the AsExpression object.
172 virtual ~AsExpression() = default;
173
174 //! @brief The operator (()) overloading of AsExpression class.
175 //! @param x - independent variable
176 //! @return dependent variable
177 virtual double operator()(const double x) const = 0;
178 //! @brief The operator (Expression) overloading of AsExpression class.
179 //! @return Expression object
180 virtual explicit operator Expression() const
181 {
182 return [this](const double x) { return operator()(x); };
183 }
184};
185
186//! @brief Set input parameters.
187namespace input
188{
189//! @brief Cylindrical Bessel.
190class CylindricalBessel : public AsExpression
191{
192public:
193 //! @brief The operator (()) overloading of CylindricalBessel class.
194 //! @param x - independent variable
195 //! @return dependent variable
196 double operator()(const double x) const override { return ::gsl_sf_bessel_J0(x); }
197
198 //! @brief Left endpoint.
199 static constexpr double range1{0.0};
200 //! @brief Right endpoint.
201 static constexpr double range2{20.0};
202 //! @brief Cylindrical Bessel function of the first kind.
203 static constexpr std::string_view exprDescr{"f(x)=J₀(x),x∈[0,20] (Cylindrical Bessel function of the first kind)"};
204};
205} // namespace input
206
207//! @brief Builder for the input.
208class InputBuilder
209{
210public:
211 //! @brief Construct a new Input Builder object.
212 //! @param expression - target expression
213 //! @param range1 - lower endpoint
214 //! @param range2 - upper endpoint
215 //! @param exprDescr - expression description
216 InputBuilder(
217 Expression expression,
218 const double range1,
219 const double range2,
220 [[maybe_unused]] const std::string_view exprDescr) :
221 expression{std::move(expression)}, range1{range1}, range2{range2}
222 {
223#ifdef _RUNTIME_PRINTING
224 std::cout << "\nIntegral expression:\n" << exprDescr << std::endl;
225#endif
226 }
227
228 //! @brief Get the target expression.
229 //! @return target expression
230 [[nodiscard]] Expression getExpression() const noexcept { return expression; }
231 //! @brief Get the pair of ranges.
232 //! @return pair of ranges
233 [[nodiscard]] std::pair<double, double> getRanges() const noexcept { return std::make_pair(x: range1, y: range2); }
234
235private:
236 //! @brief Target expression.
237 const Expression expression;
238 //! @brief Lower endpoint.
239 const double range1{0.0};
240 //! @brief Upper endpoint.
241 const double range2{0.0};
242};
243} // namespace integral
244extern void applyingIntegral(const std::vector<std::string>& candidates);
245
246//! @brief Apply prime.
247namespace prime
248{
249//! @brief The version used to apply.
250const char* const version = numeric::prime::version();
251
252//! @brief Set input parameters.
253namespace input
254{
255//! @brief Upper bound for prime methods.
256inline constexpr std::uint32_t upperBound = 997;
257} // namespace input
258
259//! @brief Maximum alignment length per element of printing.
260constexpr std::uint8_t maxAlignOfPrint = 16;
261//! @brief Maximum columns per row of printing.
262constexpr std::uint8_t maxColumnOfPrint = 10;
263
264//! @brief Builder for the input.
265class InputBuilder
266{
267public:
268 //! @brief Construct a new InputBuilder object.
269 //! @param upperBound - upper bound
270 explicit InputBuilder(const std::uint32_t upperBound) : upperBound{upperBound}
271 {
272#ifdef _RUNTIME_PRINTING
273 std::cout << "\nAll prime numbers smaller than " << upperBound << ':' << std::endl;
274#endif
275 }
276
277 //! @brief Get the upper bound.
278 //! @return upper bound
279 [[nodiscard]] std::uint32_t getUpperBound() const noexcept { return upperBound; }
280 //! @brief Splice all integers for printing.
281 //! @tparam Elem - type of element in container
282 //! @param container - integer container
283 //! @param fmtBuffer - buffer for printing
284 //! @param bufferSize - size of the buffer
285 //! @return buffer after splicing
286 template <std::integral Elem>
287 static char* spliceAllIntegers(
288 const std::vector<Elem>& container, char* const fmtBuffer, const std::uint32_t bufferSize)
289 {
290 if (container.empty() || !fmtBuffer || (bufferSize == 0))
291 {
292 return fmtBuffer;
293 }
294
295 const std::uint32_t align = std::reduce(
296 container.cbegin(),
297 container.cend(),
298 0,
299 [](const auto max, const auto elem)
300 { return std::max<std::uint32_t>(std::to_string(elem).length(), max); });
301 for (std::uint32_t i = 0, offset = 0; i < container.size(); ++i)
302 {
303 const char sep = (((i + 1) % maxColumnOfPrint == 0) && ((i + 1) != container.size())) ? '\n' : ' ';
304 const int written =
305 std::snprintf(s: fmtBuffer + offset, maxlen: bufferSize - offset, format: "%*d%c", align + 1, container.at(i), sep);
306 if ((written < 0) || (written >= static_cast<int>(bufferSize - offset)))
307 {
308 break;
309 }
310 offset += written;
311 }
312 return fmtBuffer;
313 }
314
315private:
316 //! @brief Upper bound.
317 const std::uint32_t upperBound{0};
318};
319} // namespace prime
320extern void applyingPrime(const std::vector<std::string>& candidates);
321} // namespace app_num
322} // namespace application
323