diff --git a/.idea/editor.xml b/.idea/editor.xml
index bde9249e6..6e4282015 100644
--- a/.idea/editor.xml
+++ b/.idea/editor.xml
@@ -1,7 +1,6 @@
-
@@ -120,8 +119,11 @@
-
-
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index 8e10ee14e..e4bdb3203 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -5,6 +5,7 @@
+
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 148151638..3e8841d96 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -8,8 +8,5 @@
-
-
-
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a258e0685..957beba96 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -25,6 +25,7 @@ PROJECT(Steppable)
# Ensure that Python is available to run the development scripts, and build with bindings.
SET(Python_FIND_VIRTUALENV FIRST)
+SET(Python3_FIND_VIRTUALENV FIRST)
FIND_PACKAGE(
Python
diff --git a/include/constants.hpp b/include/constants.hpp
index e017dca8d..6e548187a 100644
--- a/include/constants.hpp
+++ b/include/constants.hpp
@@ -31,7 +31,8 @@
namespace steppable::constants
{
/// @brief 100 digits of pi.
- extern const std::string_view& PI;
+ constexpr const std::string_view PI =
+ "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679";
/// @brief Pi multiplied by 2.
// Generated using Python:
@@ -43,7 +44,7 @@ namespace steppable::constants
// 5 | 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
// 6 | ) * Decimal(2)
// -------------------------------------------------------
- extern const std::string_view& TWO_PI;
+ constexpr const std::string_view TWO_PI = "6.283185307179586231995926937088370323181152343750";
/// @brief Pi divided by 2.
// Generated using Python:
@@ -55,7 +56,8 @@ namespace steppable::constants
// 5 | 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
// 6 | ) / Decimal(2)
// -------------------------------------------------------
- extern const std::string_view& PI_OVER_2;
+ constexpr const std::string_view PI_OVER_2 =
+ "1.570796326794896619231321691639751442098584699687552910487472296153908203143104499314017412835292542";
/// @brief Pi divided by 180 (to convert degrees to radians), correct to 100 decimal places.
// Generated using Python:
@@ -67,7 +69,8 @@ namespace steppable::constants
// 5 | 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
// 6 | ) / Decimal(180)
// -------------------------------------------------------
- extern const std::string_view& PI_OVER_180;
+ constexpr const std::string_view PI_OVER_180 =
+ "0.01745329251994329508887757482524547311994764539930555555555555555555555555555555555555555555555555556";
/// @brief Pi divided by 200 (to convert grads to radians), correct to 100 decimal places.
// Generated using Python:
@@ -79,7 +82,8 @@ namespace steppable::constants
// 5 | 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
// 6 | ) / Decimal(200)
// -------------------------------------------------------
- extern const std::string_view& PI_OVER_200;
+ constexpr const std::string_view PI_OVER_200 =
+ "0.01570796326794896619231321691639716312084074699687552942986246296153903203140449499314017412671058534";
- extern const std::string_view& E;
+ constexpr const std::string_view E = "2.718281828459045090795598298427648842334747314453125";
} // namespace steppable::constants
diff --git a/include/factors.hpp b/include/factors.hpp
index 39ffe4816..8caa81b74 100644
--- a/include/factors.hpp
+++ b/include/factors.hpp
@@ -46,7 +46,7 @@ namespace steppable::__internals::numUtils
* @param[in] base The base of the root.
* @return A result object containing the largest root factor of the number.
*/
- ResultBool getRootFactor(const std::string& _number, const std::string& base = "2");
+ ResultBool getRootFactor(const std::string& _number, const std::string& base = "2");
/**
* @brief Get the greatest root number less than or equal to the given number.
@@ -73,5 +73,5 @@ namespace steppable::__internals::numUtils
* @return StatusBool::CALCULATED_SIMPLIFIED_YES if the number is a root number,
* StatusBool::CALCULATED_SIMPLIFIED_NO otherwise.
*/
- ResultBool isRoot(const std::string& _number, const std::string& base);
+ ResultBool isRoot(const std::string& _number, const std::string& base);
} // namespace steppable::__internals::numUtils
diff --git a/include/fn/calc.hpp b/include/fn/calc.hpp
index 230ce309f..3d0302bcb 100644
--- a/include/fn/calc.hpp
+++ b/include/fn/calc.hpp
@@ -39,6 +39,7 @@
#include "output.hpp"
#include
+#include
using namespace std::literals;
@@ -46,7 +47,7 @@ using namespace std::literals;
* @namespace steppable::__internals
* @brief The namespace containing internal functions for the Steppable library.
*/
-namespace steppable::__internals::arithmetic
+namespace steppable::__internals::calc
{
/**
* @brief Represents the quotient and remainder of a division operation.
@@ -154,7 +155,7 @@ namespace steppable::__internals::arithmetic
* @param[in] steps The number of steps to perform the multiplication.
* @return The product of the two numbers as a string.
*/
- std::string multiply(const std::string& a, const std::string& b, int steps = 2);
+ std::string multiply(const std::string& a, const std::string& b, int steps = 2, int decimals = MAX_DECIMALS);
/**
* @brief Raises a string representation of a number to a power.
@@ -162,9 +163,10 @@ namespace steppable::__internals::arithmetic
* @param[in] _number The string representation of the number.
* @param[in] raiseTo The string representation of the power to raise the number to.
* @param[in] steps The number of steps to perform the power operation.
+ * @param[in] decimals The number of decimals to output from the power operation.
* @return The result of the power operation as a string.
*/
- std::string power(const std::string& _number, const std::string& raiseTo, int steps = 2);
+ std::string power(const std::string& _number, const std::string& raiseTo, int steps = 2, int decimals = 8);
/**
* @brief Calculates e^x. Shorthand of power(x, E, 0);
@@ -572,4 +574,4 @@ namespace steppable::__internals::arithmetic
}
}
-} // namespace steppable::__internals::arithmetic
+} // namespace steppable::__internals::calc
diff --git a/include/fn/root.hpp b/include/fn/root.hpp
index 82e65557b..062be5e49 100644
--- a/include/fn/root.hpp
+++ b/include/fn/root.hpp
@@ -24,7 +24,7 @@
#include
-namespace steppable::__internals::arithmetic
+namespace steppable::__internals::calc
{
/**
* @brief A struct to represent a surd.
@@ -38,4 +38,4 @@ namespace steppable::__internals::arithmetic
/// @brief The multiplier of the surd.
std::string multiplier;
};
-} // namespace steppable::__internals::arithmetic
+} // namespace steppable::__internals::calc
diff --git a/include/testing.hpp b/include/testing.hpp
index 2a8a80a69..e85934fee 100644
--- a/include/testing.hpp
+++ b/include/testing.hpp
@@ -112,7 +112,7 @@ namespace steppable::testing
* @brief Constructs a new TestCase object with the given name.
* @param[in] testCaseName The name of the test case.
*/
- explicit TestCase(const std::string& testCaseName);
+ explicit TestCase(std::string testCaseName);
/**
* @brief Asserts that two strings are equal.
diff --git a/include/types/data.hpp b/include/types/data.hpp
new file mode 100644
index 000000000..724656aee
--- /dev/null
+++ b/include/types/data.hpp
@@ -0,0 +1,64 @@
+/**************************************************************************************************
+ * Copyright (c) 2023-2025 NWSOFT *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy *
+ * of this software and associated documentation files (the "Software"), to deal *
+ * in the Software without restriction, including without limitation the rights *
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in all *
+ * copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, *
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE *
+ * SOFTWARE. *
+ **************************************************************************************************/
+
+#pragma once
+
+#include
+
+#include "util.hpp"
+
+using namespace std::literals;
+using namespace steppable::__internals::utils;
+
+namespace steppable
+{
+ template
+ class Data
+ {
+ BaseT value;
+
+ public:
+ std::string getDataType() { return BaseTName.value; }
+
+ Data(const BaseT object) : value(object) {} // NOLINT(*-explicit-constructor)
+ Data() : value() {}
+
+ Data& operator=(const BaseT& object)
+ {
+ value = object;
+ return *this;
+ }
+ };
+
+ enum class _Weekday : std::uint8_t
+ {
+ Sunday = 0,
+ Monday = 1,
+ Tuesday = 2,
+ Wednesday = 3,
+ Thursday = 4,
+ Friday = 5,
+ Saturday = 6,
+ };
+
+ using Weekday = Data<_Weekday, StringLiteral{"Weekday"}>;
+} // namespace steppable
\ No newline at end of file
diff --git a/include/types/result.hpp b/include/types/result.hpp
index 029e664bc..28112c430 100644
--- a/include/types/result.hpp
+++ b/include/types/result.hpp
@@ -22,10 +22,16 @@
#pragma once
+#include
+#include
#include
+#include
#include
#include
+using namespace std::literals;
+using namespace steppable::__internals::utils;
+
/**
* @namespace steppable::types
* @brief The namespace containing types used in the steppable calculator.
@@ -35,7 +41,7 @@ namespace steppable::types
/**
* @brief The status of the calculation.
*/
- enum class Status
+ enum class Status : std::uint8_t
{
CALCULATED_SIMPLIFIED,
CALCULATED_UNSIMPLIFIED,
@@ -45,7 +51,7 @@ namespace steppable::types
/**
* @brief The status of a boolean calculation.
*/
- enum class StatusBool
+ enum class StatusBool : std::uint8_t
{
CALCULATED_SIMPLIFIED_YES,
CALCULATED_SIMPLIFIED_NO,
@@ -60,10 +66,9 @@ namespace steppable::types
*
* @tparam StatusType The type of the status of the calculation.
*/
- template
+ template
class ResultBase
{
- private:
/// @brief Whether the calculation is done.
StatusType done;
@@ -71,7 +76,11 @@ namespace steppable::types
std::vector inputs;
/// @brief The output of the calculation.
- std::string out;
+ std::vector outputs;
+
+ /// @brief The result of the calculation
+ /// @attention This is different from `inputs`, as it stores only the result of the operation.
+ ResultT result;
public:
ResultBase() = delete;
@@ -81,26 +90,42 @@ namespace steppable::types
*
* @param[in] _inputs The inputs to the calculation.
* @param[in] _out The output of the calculation.
+ * @param result The result of the calculation.
* @param[in] _done A flag indicating how the calculation is done.
*/
- ResultBase(const std::vector& _inputs, std::string _out, StatusType _done) :
- done(_done), inputs(_inputs), out(std::move(_out))
+ ResultBase(const std::vector& _inputs,
+ std::vector _out,
+ ResultT result,
+ StatusType _done) :
+ done(_done), inputs(_inputs), outputs(std::move(_out)), result(result)
{
}
/// @brief Gets how the calculation is done.
StatusType getStatus() const { return done; }
+ [[nodiscard("Result should be used")]] ResultT getResult() const { return result; }
+
/// @brief Gets the output of the calculation.
- std::string getOutput() const { return out; }
+ [[nodiscard("Output should be used")]] std::string getOutput(size_t idx = 0) const
+ {
+ if (idx >= outputs.size())
+ {
+ output::error("getOutput"s, "Output index out of range"s);
+ programSafeExit(1);
+ }
+ return outputs[idx];
+ }
/// @brief Gets the inputs to the calculation.
- std::vector getInputs() const { return inputs; }
+ [[nodiscard("Inputs should be used")]] std::vector getInputs() const { return inputs; }
};
/// @brief An alias for a result of a calculation. This represents a calculation with a `Status` status.
- using Result = ResultBase;
+ template
+ using Result = ResultBase;
/// @brief An alias for a result of a boolean calculation.
- using ResultBool = ResultBase;
+ template
+ using ResultBool = ResultBase;
} // namespace steppable::types
diff --git a/include/util.hpp b/include/util.hpp
index 665b4ae45..b3bb8226f 100644
--- a/include/util.hpp
+++ b/include/util.hpp
@@ -213,6 +213,28 @@ namespace steppable::__internals::utils
programSafeExit(1);
}
}
+
+ /**
+ * @brief String literal workaround for templates.
+ * @tparam N The length of the string
+ */
+ template
+ struct StringLiteral
+ {
+ /**
+ * @brief Initializes the wrapper class.
+ * @param str The string literal for the template.
+ */
+ constexpr StringLiteral(const char (&str)[N]) // NOLINT(*-pro-type-member-init, *-explicit-constructor)
+ { // NOLINT(*-avoid-c-arrays)
+ std::copy_n(str, N, value);
+ }
+
+ /**
+ * @brief The value of the wrapper class. Stores the string object.
+ */
+ char value[N]; // NOLINT(*-avoid-c-arrays)
+ };
} // namespace steppable::__internals::utils
/**
@@ -372,6 +394,22 @@ namespace steppable::__internals::numUtils
* @return True if it is a power of 10, false otherwise.
*/
bool isPowerOfTen(const std::string& number);
+
+ /**
+ * @brief Checks if a number is odd.
+ *
+ * @param number The number to be checked.
+ * @return True if the number is odd, false otherwise.
+ */
+ bool isOdd(const std::string& number);
+
+ /**
+ * @brief Checks if a number is even.
+ *
+ * @param number The number to be checked.
+ * @return True if the number is even, false otherwise.
+ */
+ bool isEven(const std::string& number);
} // namespace steppable::__internals::numUtils
/**
@@ -550,4 +588,18 @@ namespace steppable::__internals::stringUtils
* @return A vector of strings containing the duplicates.
*/
std::vector duplicates(const std::vector& vector);
+
+ template
+ std::string vectorToString(const std::vector& vector)
+ {
+ std::ostringstream out;
+ out << "[";
+ for (size_t i = 0; i < vector.size(); ++i)
+ {
+ out << vector[i];
+ if (i != vector.size() - 1)
+ out << ", ";
+ }
+ return out.str();
+ }
} // namespace steppable::__internals::stringUtils
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 4e00e0522..53b737e06 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -25,7 +25,7 @@ if(NOT ${STP_NO_BINDINGS}) # Only create the bindings if needed
# Detect the installed nanobind package and import it into CMake
execute_process(
- COMMAND "${Python_EXECUTABLE}" -m nanobind --cmake_dir
+ COMMAND "${Python3_EXECUTABLE}" -m nanobind --cmake_dir
OUTPUT_STRIP_TRAILING_WHITESPACE
OUTPUT_VARIABLE NB_DIR)
message(TRACE "Found nanobind: ${NB_DIR}")
diff --git a/lib/bindings.cpp b/lib/bindings.cpp
index 83fffe876..3525f844e 100644
--- a/lib/bindings.cpp
+++ b/lib/bindings.cpp
@@ -31,7 +31,7 @@
#include
namespace nb = nanobind;
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
using namespace nb::literals;
NB_MODULE(steppyble, mod) // NOLINT
@@ -91,7 +91,7 @@ NB_MODULE(steppyble, mod) // NOLINT
mod.doc() = "The Python bindings for Steppable.";
internals.def("abs",
- &steppable::__internals::arithmetic::abs,
+ &steppable::__internals::calc::abs,
"a"_a,
"steps"_a = 2,
"Internal function that takes the absolute value of a number.");
@@ -111,15 +111,18 @@ NB_MODULE(steppyble, mod) // NOLINT
"Internal function that subtracts two numbers.");
internals.def(
"multiply",
- [](const std::string& a, const std::string& b, const int steps) { return multiply(a, b, steps); },
+ [](const std::string& a, const std::string& b, const int steps, const int decimals) {
+ return multiply(a, b, steps, decimals);
+ },
"a"_a,
"b"_a,
"steps"_a = 2,
+ "decimals"_a = 8,
"Internal function that multiplies two numbers.");
internals.def(
"divide",
[](const std::string& a, const std::string& b, const int steps, const int decimals) {
- return divide(a, b, steps);
+ return divide(a, b, steps, decimals);
},
"a"_a,
"b"_a,
@@ -129,5 +132,11 @@ NB_MODULE(steppyble, mod) // NOLINT
internals.def("divideWithQuotient",
÷WithQuotient,
"Internal function that divides two numbers, but separating the quotient and remainder.");
- internals.def("power", &power, "a"_a, "raiseTo"_a, "steps"_a = 2, "Internal function raises a number to a power.");
+ internals.def("power",
+ &power,
+ "a"_a,
+ "raiseTo"_a,
+ "steps"_a = 2,
+ "decimals"_a = 8,
+ "Internal function raises a number to a power.");
}
diff --git a/lib/test.py b/lib/test.py
new file mode 100644
index 000000000..869ef9950
--- /dev/null
+++ b/lib/test.py
@@ -0,0 +1,25 @@
+#####################################################################################################
+# Copyright (c) 2023-2025 NWSOFT #
+# #
+# Permission is hereby granted, free of charge, to any person obtaining a copy #
+# of this software and associated documentation files (the "Software"), to deal #
+# in the Software without restriction, including without limitation the rights #
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell #
+# copies of the Software, and to permit persons to whom the Software is #
+# furnished to do so, subject to the following conditions: #
+# #
+# The above copyright notice and this permission notice shall be included in all #
+# copies or substantial portions of the Software. #
+# #
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, #
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, #
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE #
+# SOFTWARE. #
+#####################################################################################################
+
+import steppyble
+
+steppyble.Number()
diff --git a/questions b/questions
deleted file mode 100644
index d7b9f1f89..000000000
--- a/questions
+++ /dev/null
@@ -1,30 +0,0 @@
-1. why you guys decide to do this
-2. how long have you been working on this
-3. what are your goals / objectives
-4. what can i benefit from sponsoring you
-5. why is it meaningful for me to sponsor
-6. how do you handle failure of this competition
-7. what risks are there for me
-8. how much do i need to provide
-9. how do you spend my money
-10. what is so special about your car design and why do you think it will win
-11. what are your other sponsors
-12. who are your competitors? how much is your advantage?
-13. introduce yourself (should be the first, i forgot)
-14. why isn’t there a co-founder (yes this is a real question)
-15. can i see your finished product?
-16. what are your biggest weaknesses
-17. what are your biggest strengths
-18. how do you describe your product to other sponsors?
-19. how do i give you money (answer is to give that to my bank account)
-20. if everything goes right, where do you see your team in a year?
-21. what if you’re forced to stop doing this?
-22. do you have passion and determination?
-23. what if you run out of money
-24. how do you handle unexpected situations
-25. what do you need that you don’t have
-26. Do you need regulatory approval or any accreditation?
-27. what are the problems you’re facing?
-28. why the name “pandurance”
-29. how can i find more about you
-30. what are you doing to attract more sponsors?
\ No newline at end of file
diff --git a/res/translations/en-US/multiply.stp_localized b/res/translations/en-US/multiply.stp_localized
index cf34d4723..33f493271 100644
--- a/res/translations/en-US/multiply.stp_localized
+++ b/res/translations/en-US/multiply.stp_localized
@@ -25,10 +25,11 @@
# eg: a491b7b2-1239-4acb-9045-0747d806b96f >> "Hello World!"
# Recommended syntax highlighting: Bash Script
9cdeff33-fefa-40ac-b867-a811f652d6e3 >> "Since any of a or b is zero, the result must be zero as well."
-36adc27f-07e8-4118-88ed-f148164044da >> "Since {0} is 1, the result is {2}."
+36adc27f-07e8-4118-88ed-f148164044da >> "Since {0} is 1, the result is {1}."
0e76c0f9-6d14-450d-abc4-f4a758787d06 >> "Since {0} is a power of 10, we can move the decimal places to obtain the result."
1d54da58-ec3c-4888-80a8-c40565efb603 >> "Number 1"
3db8b80f-9667-476a-b096-9323615dd461 >> "Number 2"
5ed5291e-6269-4d76-a8f8-db5eec807955 >> "Amount of steps while multiplying"
+02dc437f-814b-4fe3-9fbc-c2616b0c0f4a >> "Number of decimals to output"
eec47776-991b-40cc-9956-7227127d2c1f >> "profiling the program"
776a33fd-982a-4888-8b42-83b0f3797dc2 >> "Column Method Multiplication :"
\ No newline at end of file
diff --git a/res/translations/en-US/power.stp_localized b/res/translations/en-US/power.stp_localized
index 8ce70250e..c78bc40bb 100644
--- a/res/translations/en-US/power.stp_localized
+++ b/res/translations/en-US/power.stp_localized
@@ -32,4 +32,5 @@ cb935566-6125-49ce-9ebc-e157410a3005 >> "Amount of steps while raising the power
e5d48237-e161-494d-940b-e2457411fcfb >> "profiling the program"
2a9fd067-59a3-4a65-b1a6-2ca479e0f1a1 >> "Power :"
7b3b39ff-c3fa-4998-b9e2-8989fb6846f9 >> "The exponent {0} is a decimal. Therefore, the result is a root."
-261e4299-0132-4ab5-a37d-aa376efbdd5f >> "Since the number is 0, the result is 0."
\ No newline at end of file
+261e4299-0132-4ab5-a37d-aa376efbdd5f >> "Since the number is 0, the result is 0."
+03c15572-a5aa-4b1c-a705-105770999741 >> "Number of decimals in the output"
\ No newline at end of file
diff --git a/res/translations/multiply.stp_strings b/res/translations/multiply.stp_strings
index cef1d20a1..b4bf1389a 100644
--- a/res/translations/multiply.stp_strings
+++ b/res/translations/multiply.stp_strings
@@ -30,5 +30,6 @@
1d54da58-ec3c-4888-80a8-c40565efb603 >> "Number 1"
3db8b80f-9667-476a-b096-9323615dd461 >> "Number 2"
5ed5291e-6269-4d76-a8f8-db5eec807955 >> "Amount of steps while multiplying"
+02dc437f-814b-4fe3-9fbc-c2616b0c0f4a >> "Number of decimals to output"
eec47776-991b-40cc-9956-7227127d2c1f >> "profiling the program"
776a33fd-982a-4888-8b42-83b0f3797dc2 >> "Column Method Multiplication :"
diff --git a/res/translations/power.stp_strings b/res/translations/power.stp_strings
index ef17bc7be..4724927dd 100644
--- a/res/translations/power.stp_strings
+++ b/res/translations/power.stp_strings
@@ -33,3 +33,4 @@ e5d48237-e161-494d-940b-e2457411fcfb >> "profiling the program"
2a9fd067-59a3-4a65-b1a6-2ca479e0f1a1 >> "Power :"
7b3b39ff-c3fa-4998-b9e2-8989fb6846f9 >> "The exponent {0} is a decimal. Therefore, the result is a root."
261e4299-0132-4ab5-a37d-aa376efbdd5f >> "Since the number is 0, the result is 0."
+03c15572-a5aa-4b1c-a705-105770999741 >> "Number of decimals in the output"
diff --git a/res/translations/zh-HK/multiply.stp_localized b/res/translations/zh-HK/multiply.stp_localized
index b5c1de9d9..66193669b 100644
--- a/res/translations/zh-HK/multiply.stp_localized
+++ b/res/translations/zh-HK/multiply.stp_localized
@@ -30,5 +30,6 @@
1d54da58-ec3c-4888-80a8-c40565efb603 >> "數值一"
3db8b80f-9667-476a-b096-9323615dd461 >> "數值二"
5ed5291e-6269-4d76-a8f8-db5eec807955 >> "計算乘法時所顯示的步驟"
+02dc437f-814b-4fe3-9fbc-c2616b0c0f4a >> "所需輸出的小數位數"
eec47776-991b-40cc-9956-7227127d2c1f >> "分析程式"
-776a33fd-982a-4888-8b42-83b0f3797dc2 >> "直式乘法:"
\ No newline at end of file
+776a33fd-982a-4888-8b42-83b0f3797dc2 >> "直式乘法:"
diff --git a/res/translations/zh-HK/power.stp_localized b/res/translations/zh-HK/power.stp_localized
index 208a79e13..4ad17ad21 100644
--- a/res/translations/zh-HK/power.stp_localized
+++ b/res/translations/zh-HK/power.stp_localized
@@ -28,6 +28,7 @@
f8fdd5af-6450-4c19-97a9-9724493f76ab >> "由於指數為零,結果為一。"
4252ac37-a36b-4605-9ec1-d69e70b91b46 >> "數值"
1fefffaf-7731-430b-989f-42e74017a2eb >> "指數"
+03c15572-a5aa-4b1c-a705-105770999741 >> "計算指數(乘法)時所顯示的小數位數。"
cb935566-6125-49ce-9ebc-e157410a3005 >> "計算指數(乘法)時所顯示的步驟。0代表沒有步驟,2代表全部步驟。"
e5d48237-e161-494d-940b-e2457411fcfb >> "分析程式"
2a9fd067-59a3-4a65-b1a6-2ca479e0f1a1 >> "指數:"
diff --git a/setup.py b/setup.py
index ffb2ff205..462309b18 100644
--- a/setup.py
+++ b/setup.py
@@ -80,6 +80,7 @@ def build_extension(self, ext: CMakeExtension) -> None:
f"-DPython_EXECUTABLE={sys.executable}",
f"-DCMAKE_BUILD_TYPE={cfg}", # not used on MSVC, but no harm
f"-DSTP_BUILD_COMPONENT_EXECUTABLE=True", # not used on MSVC, but no harm
+ f"-DSTP_NO_BINDINGS=False", # Build bindings for Python
]
build_args = []
# Adding CMake arguments set as environment variable
@@ -188,6 +189,8 @@ def build_extension(self, ext: CMakeExtension) -> None:
long_description="Python bindings for Steppable, written using nanobind.",
ext_modules=[CMakeExtension("steppyble")],
include_package_data=True,
+ packages=["steppyble"],
+ package_data={"steppyble": ["__init__.pyi", "fraction.pyi", "number.pyi"]},
cmdclass={"build_ext": CMakeBuild},
zip_safe=False,
extras_require={"test": ["pytest>=6.0"]},
diff --git a/src/base/baseConvert/baseConvert.cpp b/src/base/baseConvert/baseConvert.cpp
index b3841848f..f69cee268 100644
--- a/src/base/baseConvert/baseConvert.cpp
+++ b/src/base/baseConvert/baseConvert.cpp
@@ -41,7 +41,7 @@
using namespace std::literals;
using namespace steppable::__internals::stringUtils;
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
using namespace steppable::__internals::symbols;
using namespace steppable::localization;
using namespace steppable::output;
@@ -55,14 +55,14 @@ namespace steppable::prettyPrint::printers
auto height = prettyPrint::getStringHeight(base) + 1; // +1 for the superscript
prettyPrint::ConsoleOutput output(height, width);
- prettyPrint::Position pos{ static_cast(width - subscriptWidth - 1), 1 };
+ prettyPrint::Position pos{ .x = static_cast(width - subscriptWidth - 1), .y = 1 };
output.write(subscript, pos, false);
- output.write(base, { 0, 0 }, false);
+ output.write(base, { .x = 0, .y = 0 }, false);
return output.asString();
}
} // namespace steppable::prettyPrint::printers
-namespace steppable::__internals::arithmetic
+namespace steppable::__internals::calc
{
/**
* @brief Represents a number using alphabets and numberals.
@@ -86,7 +86,7 @@ namespace steppable::__internals::arithmetic
std::string baseConvert(const std::string& _number, const std::string& baseStr, const int steps)
{
- const size_t base = std::stoll(static_cast(baseStr));
+ const size_t base = std::stoll(baseStr);
auto numberOrig = static_cast(_number);
auto number = static_cast(_number);
@@ -126,7 +126,7 @@ namespace steppable::__internals::arithmetic
return reportBaseConvert(numberOrig, static_cast(baseStr), digits, steps);
}
-} // namespace steppable::__internals::arithmetic
+} // namespace steppable::__internals::calc
#ifndef NO_MAIN
int main(const int _argc, const char* _argv[])
diff --git a/src/base/baseConvert/baseConvertReport.cpp b/src/base/baseConvert/baseConvertReport.cpp
index 2edec5f65..88b955ba6 100644
--- a/src/base/baseConvert/baseConvertReport.cpp
+++ b/src/base/baseConvert/baseConvertReport.cpp
@@ -67,7 +67,7 @@ std::string reportBaseConvert(const std::string& _number,
ss << _number << steppable::__internals::symbols::makeSubscript("10") << " = ";
// Output the result in reverse order
auto result = _result;
- std::reverse(result.begin(), result.end());
+ std::ranges::reverse(result);
for (const auto& item : result)
ss << item;
if (steps == 1)
diff --git a/src/base/decimalConvert/decimalConvert.cpp b/src/base/decimalConvert/decimalConvert.cpp
index 6663e1385..8a4621b4d 100644
--- a/src/base/decimalConvert/decimalConvert.cpp
+++ b/src/base/decimalConvert/decimalConvert.cpp
@@ -40,9 +40,9 @@ using namespace steppable::__internals::utils;
using namespace steppable::__internals::symbols;
using namespace steppable::output;
using namespace steppable::localization;
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
-namespace steppable::__internals::arithmetic
+namespace steppable::__internals::calc
{
/**
* @brief Converts a numeral character to a number string.
@@ -100,7 +100,7 @@ namespace steppable::__internals::arithmetic
ss << reportDecimalConvert(_inputString, baseString, converted, steps);
return ss.str();
}
-} // namespace steppable::__internals::arithmetic
+} // namespace steppable::__internals::calc
#ifndef NO_MAIN
diff --git a/src/calc/abs/abs.cpp b/src/calc/abs/abs.cpp
index a027616b1..d230271e5 100644
--- a/src/calc/abs/abs.cpp
+++ b/src/calc/abs/abs.cpp
@@ -35,20 +35,26 @@
#include
#include
+#include
#include
+#include
using namespace steppable::__internals::utils;
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
using namespace steppable::localization;
-namespace steppable::__internals::arithmetic
+namespace steppable::__internals::calc
{
- std::string abs(const std::string& _number, const int steps)
+ types::Result _abs(const std::string& _number)
{
- std::string number = static_cast(_number);
- return reportAbs(number, steps);
+ const auto result = reportAbs(_number, 0);
+ const std::vector outputs = { result, reportAbs(_number, 1), reportAbs(_number, 2) };
+ const std::vector inputs = { _number };
+ return { inputs, outputs, Number(result), types::Status::CALCULATED_UNSIMPLIFIED };
}
-} // namespace steppable::__internals::arithmetic
+
+ std::string abs(const std::string& _number, const int steps) { return _abs(_number).getOutput(steps); }
+} // namespace steppable::__internals::calc
#ifndef NO_MAIN
int main(const int _argc, const char* _argv[])
diff --git a/src/calc/add/add.cpp b/src/calc/add/add.cpp
index 32cfb5ab9..1b3a8a3fc 100644
--- a/src/calc/add/add.cpp
+++ b/src/calc/add/add.cpp
@@ -41,11 +41,11 @@
using namespace steppable::__internals::numUtils;
using namespace steppable::__internals::utils;
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
using namespace steppable::__internals::symbols;
using namespace steppable::localization;
-namespace steppable::__internals::arithmetic
+namespace steppable::__internals::calc
{
std::string add(const std::string& a,
const std::string& b,
@@ -120,8 +120,8 @@ namespace steppable::__internals::arithmetic
std::ranges::reverse(aStr);
std::ranges::reverse(bStr);
- std::vector sumDigits(aStr.length() + 1, 0);
- std::vector carries(aStr.length() + 1, false);
+ std::vector sumDigits(aStr.length() + 1, 0);
+ std::vector carries(aStr.length() + 1, 0);
for (size_t index = 0; index < aStr.length(); index++)
{
@@ -138,7 +138,7 @@ namespace steppable::__internals::arithmetic
{
sumDigits[index] -= 10;
sumDigits[index + 1] += 1;
- carries[index + 1] = true;
+ carries[index + 1] = 1;
}
}
@@ -150,10 +150,10 @@ namespace steppable::__internals::arithmetic
const auto& itCarries = carries.begin();
sumDigits.insert(itSumDigits + static_cast(decimalPos), -1); // -1 indicating a decimal point
- carries.insert(itCarries + static_cast(decimalPos), false); // Reserve the space
+ carries.insert(itCarries + static_cast(decimalPos), 0); // Reserve the space
}
- std::reverse(carries.begin(), carries.end());
+ std::ranges::reverse(carries);
std::ranges::reverse(sumDigits);
if (sumDigits.front() == 0 and properlyFormat)
sumDigits.erase(sumDigits.begin());
@@ -161,7 +161,7 @@ namespace steppable::__internals::arithmetic
return reportAdd(
aInteger, aDecimal, bInteger, bDecimal, sumDigits, carries, resultIsNegative, steps, properlyFormat);
}
-} // namespace steppable::__internals::arithmetic
+} // namespace steppable::__internals::calc
#ifndef NO_MAIN
int main(const int _argc, const char* _argv[])
diff --git a/src/calc/add/addReport.cpp b/src/calc/add/addReport.cpp
index d9c9f0406..bfd0f5ce1 100644
--- a/src/calc/add/addReport.cpp
+++ b/src/calc/add/addReport.cpp
@@ -47,7 +47,7 @@ std::string reportAdd(const std::string& aInteger,
const std::string& bInteger,
const std::string& bDecimal,
const std::vector& sumDigits,
- const std::vector& carries,
+ const std::vector& carries,
const bool resultIsNegative,
const int steps,
const bool properlyFormat)
@@ -60,12 +60,8 @@ std::string reportAdd(const std::string& aInteger,
std::string bOut = bInteger;
if (aIsDecimal)
aOut += '.' + aDecimal;
- else if (steps == 0)
- ; // Don't use the spaced formatting
if (bIsDecimal)
bOut += '.' + bDecimal;
- else if (steps == 0)
- ; // Don't use the spaced formatting
if (aIsDecimal and not bIsDecimal and (steps != 0))
bOut += std::string(aDecimal.length() + 1, ' ');
@@ -87,8 +83,8 @@ std::string reportAdd(const std::string& aInteger,
ss << bChar << " ";
ss << '\n' << " ";
- for (const bool c : carries)
- if (c)
+ for (const int c : carries)
+ if (c != 0)
ss << makeSubscript("1") << " ";
else
ss << " ";
diff --git a/src/calc/add/addReport.hpp b/src/calc/add/addReport.hpp
index 8da17cd89..195909d0f 100644
--- a/src/calc/add/addReport.hpp
+++ b/src/calc/add/addReport.hpp
@@ -54,7 +54,7 @@ std::string reportAdd(const std::string& aInteger,
const std::string& bInteger,
const std::string& bDecimal,
const std::vector& sumDigits,
- const std::vector& carries,
+ const std::vector& carries,
bool resultIsNegative,
int steps,
bool properlyFormat);
diff --git a/src/calc/atan2/atan2.cpp b/src/calc/atan2/atan2.cpp
index e38d14143..39462f020 100644
--- a/src/calc/atan2/atan2.cpp
+++ b/src/calc/atan2/atan2.cpp
@@ -41,12 +41,12 @@
#include
using namespace std::literals;
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
using namespace steppable::__internals::numUtils;
using namespace steppable::localization;
using namespace steppable::output;
-namespace steppable::__internals::arithmetic
+namespace steppable::__internals::calc
{
std::string atan2(const std::string& y, const std::string& x, const size_t decimals = 10)
{
@@ -107,7 +107,7 @@ namespace steppable::__internals::arithmetic
// Will never be executed. Just here for Clangd.
return "Impossible! How did you get here?";
}
-} // namespace steppable::__internals::arithmetic
+} // namespace steppable::__internals::calc
#ifndef NO_MAIN
int main(int _argc, const char* _argv[])
diff --git a/src/calc/comparison/comparison.cpp b/src/calc/comparison/comparison.cpp
index 5dfa0de61..959687a77 100644
--- a/src/calc/comparison/comparison.cpp
+++ b/src/calc/comparison/comparison.cpp
@@ -39,10 +39,10 @@
using namespace steppable::__internals::numUtils;
using namespace steppable::__internals::symbols;
using namespace steppable::__internals::utils;
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
using namespace steppable::localization;
-namespace steppable::__internals::arithmetic
+namespace steppable::__internals::calc
{
std::string compare(const std::string& _a, const std::string& _b, const int steps)
{
@@ -120,7 +120,7 @@ namespace steppable::__internals::arithmetic
}
return "2";
}
-} // namespace steppable::__internals::arithmetic
+} // namespace steppable::__internals::calc
#ifndef NO_MAIN
int main(int _argc, const char** _argv)
diff --git a/src/calc/division/division.cpp b/src/calc/division/division.cpp
index ef1a37aee..0a5f75444 100644
--- a/src/calc/division/division.cpp
+++ b/src/calc/division/division.cpp
@@ -38,7 +38,6 @@
#include
#include
-#include
#include
#include
@@ -46,9 +45,9 @@ using namespace steppable::__internals::numUtils;
using namespace steppable::__internals::stringUtils;
using namespace steppable::output;
using namespace steppable::localization;
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
-namespace steppable::__internals::arithmetic
+namespace steppable::__internals::calc
{
QuotientRemainder getQuotientRemainder(const auto& _currentRemainder, const auto& divisor)
{
@@ -56,7 +55,7 @@ namespace steppable::__internals::arithmetic
if (compare(currentRemainder, divisor, 0) == "0")
return { "0", currentRemainder };
if (compare(currentRemainder, divisor, 0) == "2")
- return { "1", "0" }; // Equal
+ return { .quotient = "1", .remainder = "0" }; // Equal
int out = 0;
while (compare(currentRemainder, divisor, 0) != "0")
@@ -279,7 +278,7 @@ namespace steppable::__internals::arithmetic
const auto nearestResult = multiply(divisor, quotient, 0);
const auto& remainder = removeLeadingZeros(subtract(number, nearestResult, 0));
- return { quotient, remainder };
+ return { .quotient = quotient, .remainder = remainder };
}
std::string getGCD(const std::string& _a, const std::string& _b)
@@ -305,7 +304,7 @@ namespace steppable::__internals::arithmetic
// The GCD is the absolute value of a
return abs(a, 0);
}
-} // namespace steppable::__internals::arithmetic
+} // namespace steppable::__internals::calc
#ifndef NO_MAIN
int main(const int _argc, const char* _argv[])
diff --git a/src/calc/division/divisionReport.cpp b/src/calc/division/divisionReport.cpp
index 99b9bdbb0..34ff77ff3 100644
--- a/src/calc/division/divisionReport.cpp
+++ b/src/calc/division/divisionReport.cpp
@@ -40,7 +40,7 @@
using namespace std::literals;
using namespace steppable::__internals::stringUtils;
using namespace steppable::__internals::symbols;
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
std::string reportDivision(std::stringstream& tempFormattedAns,
const std::string& temp,
@@ -58,8 +58,8 @@ std::string reportDivision(std::stringstream& tempFormattedAns,
{
tempFormattedAns << std::string(width - temp.length(), ' ') << makeWider(temp) << '\n';
formattedAns << std::string(width - ans.length(), ' ') << makeWider(ans) << '\n';
- formattedAns << std::string(divisor.length() * 3 - 1, ' ');
- formattedAns << std::string(width - divisor.length() * 2, '_') << '\n';
+ formattedAns << std::string((divisor.length() * 3) - 1, ' ');
+ formattedAns << std::string(width - (divisor.length() * 2), '_') << '\n';
formattedAns << tempFormattedAns.rdbuf();
formattedAns << THEREFORE << " ";
diff --git a/src/calc/factorial/factorial.cpp b/src/calc/factorial/factorial.cpp
index f1f19bf48..94bf65a64 100644
--- a/src/calc/factorial/factorial.cpp
+++ b/src/calc/factorial/factorial.cpp
@@ -40,13 +40,13 @@
using namespace steppable::__internals::numUtils;
using namespace steppable::__internals::utils;
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
using namespace steppable::__internals::symbols;
using namespace steppable::output;
using namespace steppable::localization;
using namespace std::literals;
-namespace steppable::__internals::arithmetic
+namespace steppable::__internals::calc
{
std::string factorial(const std::string& _number, const int steps)
{
@@ -84,7 +84,7 @@ namespace steppable::__internals::arithmetic
return reportFactorial(_number, result, steps);
}
-} // namespace steppable::__internals::arithmetic
+} // namespace steppable::__internals::calc
#ifndef NO_MAIN
int main(const int _argc, const char* _argv[])
diff --git a/src/calc/factorial/factorialReport.cpp b/src/calc/factorial/factorialReport.cpp
index ce324f6fa..9e5fbcf2b 100644
--- a/src/calc/factorial/factorialReport.cpp
+++ b/src/calc/factorial/factorialReport.cpp
@@ -28,7 +28,7 @@
#include
#include
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
using namespace steppable::__internals::symbols;
std::string reportFactorial(const std::string& number, const std::string& result, int steps)
diff --git a/src/calc/hyp/hyp.cpp b/src/calc/hyp/hyp.cpp
index 66479601e..b9571088f 100644
--- a/src/calc/hyp/hyp.cpp
+++ b/src/calc/hyp/hyp.cpp
@@ -47,18 +47,18 @@ using namespace steppable::localization;
using namespace steppable::__internals::utils;
using namespace steppable::__internals::numUtils;
-namespace steppable::__internals::arithmetic
+namespace steppable::__internals::calc
{
std::string sinh(const std::string& x, const int decimals)
{
checkDecimalArg(&decimals);
- const auto& twoX = multiply(x, "2", 0);
+ const auto& twoX = multiply(x, "2", 0, decimals + 2);
const auto& eTwoX = roundOff(power(static_cast(constants::E), twoX, 0), decimals + 2);
const auto& eX = roundOff(power(static_cast(constants::E), x, 0), decimals + 2);
const auto& numerator = subtract(eTwoX, "1", 0);
- const auto& denominator = multiply("2", eX, 0);
+ const auto& denominator = multiply("2", eX, 0, decimals + 2);
return divide(numerator, denominator, 0, decimals);
}
@@ -67,12 +67,12 @@ namespace steppable::__internals::arithmetic
{
checkDecimalArg(&decimals);
- const auto& twoX = multiply(x, "2", 0);
- const auto& eTwoX = roundOff(power(static_cast(constants::E), twoX, 0), decimals + 2);
- const auto& eX = roundOff(power(static_cast(constants::E), x, 0), decimals + 2);
+ const auto& twoX = multiply(x, "2", 0, decimals + 2);
+ const auto& eTwoX = exp(twoX, decimals + 2);
+ const auto& eX = exp(x, decimals + 2);
const auto& numerator = add(eTwoX, "1", 0);
- const auto& denominator = multiply("2", eX, 0);
+ const auto& denominator = multiply("2", eX, 0, decimals + 2);
return divide(numerator, denominator, 0, decimals);
}
@@ -81,8 +81,8 @@ namespace steppable::__internals::arithmetic
{
checkDecimalArg(&decimals);
- const auto& numerator = sinh(x, decimals);
- const auto& denominator = cosh(x, decimals);
+ const auto& numerator = sinh(x, decimals + 2);
+ const auto& denominator = cosh(x, decimals + 2);
return divide(numerator, denominator, 0, decimals);
}
@@ -91,7 +91,7 @@ namespace steppable::__internals::arithmetic
{
checkDecimalArg(&decimals);
- const auto& denominator = tanh(x, decimals);
+ const auto& denominator = tanh(x, decimals + 1);
if (isZeroString(denominator))
{
error("hyp::coth"s, $("hyp", "e1f6e8db-64cd-4882-b5b2-ddd1c79c1e57"));
@@ -229,7 +229,7 @@ namespace steppable::__internals::arithmetic
return ln(lnArg, decimals);
}
-} // namespace steppable::__internals::arithmetic
+} // namespace steppable::__internals::calc
#ifndef NO_MAIN
int main(int _argc, const char* _argv[])
@@ -253,31 +253,31 @@ int main(int _argc, const char* _argv[])
// Basic trigonometric functions
if (command == "sinh")
- function = arithmetic::sinh;
+ function = calc::sinh;
else if (command == "cosh")
- function = arithmetic::cosh;
+ function = calc::cosh;
else if (command == "tanh")
- function = arithmetic::tanh;
+ function = calc::tanh;
// Reciprocal trigonometric functions
else if (command == "csch")
- function = arithmetic::csch;
+ function = calc::csch;
else if (command == "sech")
- function = arithmetic::sech;
+ function = calc::sech;
else if (command == "coth")
- function = arithmetic::coth;
+ function = calc::coth;
// Inverse trigonometric functions
else if (command == "asinh")
- function = arithmetic::asinh;
+ function = calc::asinh;
else if (command == "acosh")
- function = arithmetic::acosh;
+ function = calc::acosh;
else if (command == "atanh")
- function = arithmetic::atanh;
+ function = calc::atanh;
else if (command == "acsch")
- function = arithmetic::acsch;
+ function = calc::acsch;
else if (command == "acoth")
- function = arithmetic::acoth;
+ function = calc::acoth;
else if (command == "asech")
- function = arithmetic::asech;
+ function = calc::asech;
// Invalid command
else
{
diff --git a/src/calc/log/log.cpp b/src/calc/log/log.cpp
index cb753dc73..cf7cfaf60 100644
--- a/src/calc/log/log.cpp
+++ b/src/calc/log/log.cpp
@@ -38,12 +38,12 @@
#include
#include
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
using namespace steppable::__internals::utils;
using namespace steppable::localization;
using namespace std::literals;
-namespace steppable::__internals::arithmetic
+namespace steppable::__internals::calc
{
std::string _log(const std::string& x, const size_t _decimals)
{
@@ -65,10 +65,10 @@ namespace steppable::__internals::arithmetic
// ln(x) = ----------------------- = --------------
// 2 2
// x + 4x + 1 x + 4x + 1
- const auto& x2 = power(x, "2", 0);
+ const auto& x2 = multiply(x, x, 0, static_cast(decimals) + 2);
const auto& x2Minus1 = subtract(x2, "1", 0);
- const auto& numerator = multiply("3", x2Minus1, 0);
- const auto& fourX = multiply(x, "4", 0);
+ const auto& numerator = multiply("3", x2Minus1, 0, static_cast(decimals) + 2);
+ const auto& fourX = multiply(x, "4", 0, static_cast(decimals) + 2);
auto denominator = add(x2, fourX, 0);
denominator = add(denominator, "1", 0);
@@ -84,7 +84,7 @@ namespace steppable::__internals::arithmetic
// n + 1
const auto& epsilon = "0." + std::string(_decimals + 1, '0') + "1";
- auto yn = divide(numerator, denominator, 0, static_cast(decimals));
+ auto yn = divide(numerator, denominator, 0, static_cast(decimals) + 2);
auto yn1 = yn;
auto error = abs(subtract(yn, yn1, 0), 0);
@@ -95,7 +95,7 @@ namespace steppable::__internals::arithmetic
auto xMinusExpYN = subtract(x, expYN, 0);
auto xPlusExpYN = add(x, expYN, 0);
auto fraction = divide(xMinusExpYN, xPlusExpYN, 0, static_cast(decimals));
- auto twoXFraction = multiply(fraction, "2", 0);
+ auto twoXFraction = multiply(fraction, "2", 0, static_cast(decimals));
yn1 = add(yn, twoXFraction, 0);
error = abs(subtract(yn, yn1, 0), 0);
} while (compare(error, epsilon, 0) == "1");
@@ -139,7 +139,7 @@ namespace steppable::__internals::arithmetic
checkDecimalArg(&_decimals);
return _log(_number, _decimals);
}
-} // namespace steppable::__internals::arithmetic
+} // namespace steppable::__internals::calc
#ifndef NO_MAIN
int main(int _argc, const char* _argv[])
@@ -163,13 +163,13 @@ int main(int _argc, const char* _argv[])
using namespace steppable::output;
if (command == "logb")
- std::cout << arithmetic::logb(arg, base, decimals) << "\n";
+ std::cout << calc::logb(arg, base, decimals) << "\n";
else if (command == "log10")
- std::cout << arithmetic::log10(arg, decimals) << "\n";
+ std::cout << calc::log10(arg, decimals) << "\n";
else if (command == "log2")
- std::cout << arithmetic::log2(arg, decimals) << "\n";
+ std::cout << calc::log2(arg, decimals) << "\n";
else if (command == "ln")
- std::cout << arithmetic::ln(arg, decimals) << "\n";
+ std::cout << calc::ln(arg, decimals) << "\n";
else
{
error("log"s, $("log", "0fc4245a-fee9-4e99-bbbd-378d091c5143", { command }));
diff --git a/src/calc/multiply/multiply.cpp b/src/calc/multiply/multiply.cpp
index 7a541cde8..cb79a98c1 100644
--- a/src/calc/multiply/multiply.cpp
+++ b/src/calc/multiply/multiply.cpp
@@ -43,11 +43,12 @@ using namespace steppable::__internals::numUtils;
using namespace steppable::__internals::stringUtils;
using namespace steppable::output;
using namespace steppable::localization;
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
-namespace steppable::__internals::arithmetic
+namespace steppable::__internals::calc
{
- std::string multiply(const std::string& _a, const std::string& _b, const int steps)
+ // NOLINTNEXTLINE(readability-function-cognitive-complexity)
+ std::string multiply(const std::string& _a, const std::string& _b, const int steps, const int decimals)
{
auto a = static_cast(_a);
auto b = static_cast(_b);
@@ -62,7 +63,7 @@ namespace steppable::__internals::arithmetic
else
resultIsNegative = false;
- const auto& [aInteger, aDecimal, bInteger, bDecimal] = splitNumberArray;
+ auto [aInteger, aDecimal, bInteger, bDecimal] = splitNumberArray;
std::stringstream out;
// Multiply by zero gives zero.
if (isZeroString(a) or isZeroString(b))
@@ -72,7 +73,7 @@ namespace steppable::__internals::arithmetic
out << "0"; // Since a or b is zero, the result must be zero as well
}
- // Multiplying by 1 gives the another number.
+ // Multiplying by 1 gives the other number.
if (a == "1")
{
if (steps == 2)
@@ -112,6 +113,13 @@ namespace steppable::__internals::arithmetic
return out.str();
}
+ // If the precision of a or b is higher than required, reduce it to simplify calculation
+ if (aDecimal.length() + bDecimal.length() > decimals)
+ {
+ aDecimal = aDecimal.substr(0, decimals);
+ bDecimal = bDecimal.substr(0, decimals);
+ }
+
const std::string& aStr = aInteger + aDecimal;
const std::string bStr = bInteger + bDecimal;
std::vector> prodDigits;
@@ -127,7 +135,7 @@ namespace steppable::__internals::arithmetic
for (long long indexA = static_cast(aStr.length()) - 1; indexA != -1; indexA--)
{
const int aDigit = aStr[indexA] - '0';
- int prodDigit = bDigit * aDigit + currentCarries[indexA + 1];
+ int prodDigit = (bDigit * aDigit) + currentCarries[indexA + 1];
currentCarries[indexA] = prodDigit / 10;
if (currentCarries[indexA] > 10)
{
@@ -190,7 +198,7 @@ namespace steppable::__internals::arithmetic
resultIsNegative,
steps);
}
-} // namespace steppable::__internals::arithmetic
+} // namespace steppable::__internals::calc
#ifndef NO_MAIN
int main(const int _argc, const char* _argv[])
@@ -200,10 +208,12 @@ int main(const int _argc, const char* _argv[])
program.addPosArg('a', $("multiply", "1d54da58-ec3c-4888-80a8-c40565efb603"));
program.addPosArg('b', $("multiply", "3db8b80f-9667-476a-b096-9323615dd461"));
program.addKeywordArg("steps", 2, $("multiply", "5ed5291e-6269-4d76-a8f8-db5eec807955"));
+ program.addKeywordArg("decimals", MAX_DECIMALS, $("multiply", "02dc437f-814b-4fe3-9fbc-c2616b0c0f4a"));
program.addSwitch("profile", false, $("multiply", "eec47776-991b-40cc-9956-7227127d2c1f"));
program.parseArgs();
int steps = program.getKeywordArgument("steps");
+ int decimals = program.getKeywordArgument("decimals");
bool profile = program.getSwitch("profile");
const auto& aStr = program.getPosArg(0);
const auto& bStr = program.getPosArg(1);
@@ -212,10 +222,10 @@ int main(const int _argc, const char* _argv[])
{
TIC(Column Method Multiplication)
std::cout << $("multiply", "776a33fd-982a-4888-8b42-83b0f3797dc2") << "\n"
- << multiply(aStr, bStr, steps) << '\n';
+ << multiply(aStr, bStr, steps, decimals) << '\n';
TOC()
}
else
- std::cout << multiply(aStr, bStr, steps) << '\n';
+ std::cout << multiply(aStr, bStr, steps, decimals) << '\n';
}
#endif
diff --git a/src/calc/multiply/multiplyReport.cpp b/src/calc/multiply/multiplyReport.cpp
index 7036c0c2a..9a1cb3c7f 100644
--- a/src/calc/multiply/multiplyReport.cpp
+++ b/src/calc/multiply/multiplyReport.cpp
@@ -61,7 +61,7 @@ std::string reportMultiply(const std::string& a,
if (steps == 2)
{
- const long long outputWidth = static_cast(prodDigitsOut[0].size()) * 3 - 2;
+ const long long outputWidth = (static_cast(prodDigitsOut[0].size()) * 3) - 2;
ss << std::right << std::setw(static_cast(outputWidth + 3)) << makeWider(aStr) << '\n';
ss << MULTIPLY << std::right << std::setw(static_cast(outputWidth + 2)) << makeWider(bStr) << '\n';
ss << std::string(outputWidth + 6, '_') << '\n';
@@ -70,7 +70,7 @@ std::string reportMultiply(const std::string& a,
{
auto subVector = replaceLeadingZeros(prodDigitsOut[indexProdDigits]);
- ss << std::string(indexProdDigits * 3 + 3, ' ');
+ ss << std::string((indexProdDigits * 3) + 3, ' ');
for (const int c : carries[indexProdDigits])
if (c != 0)
ss << makeSubscript(std::to_string(c)) << " ";
@@ -78,7 +78,7 @@ std::string reportMultiply(const std::string& a,
ss << " ";
ss << '\n';
- ss << std::string(indexProdDigits * 3 + 3, ' ');
+ ss << std::string((indexProdDigits * 3) + 3, ' ');
for (const int i : subVector)
if (i >= 0)
ss << i << " ";
diff --git a/src/calc/power/power.cpp b/src/calc/power/power.cpp
index fb5b29397..b67f58ca2 100644
--- a/src/calc/power/power.cpp
+++ b/src/calc/power/power.cpp
@@ -40,7 +40,7 @@
using namespace steppable::__internals::numUtils;
using namespace steppable::output;
using namespace steppable::localization;
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
namespace steppable::prettyPrint::printers
{
@@ -50,16 +50,16 @@ namespace steppable::prettyPrint::printers
auto height = prettyPrint::getStringHeight(base) + 1; // +1 for the superscript
prettyPrint::ConsoleOutput output(height, width);
- prettyPrint::Position pos{ static_cast(width - 1), 0 };
+ prettyPrint::Position pos{ .x = static_cast(width - 1), .y = 0 };
output.write(superscript, pos, false);
- output.write(base, { 0, 1 }, false);
+ output.write(base, { .x = 0, .y = 1 }, false);
return output.asString();
}
} // namespace steppable::prettyPrint::printers
-namespace steppable::__internals::arithmetic
+namespace steppable::__internals::calc
{
- std::string power(const std::string& _number, const std::string& _raiseTo, const int steps)
+ std::string power(const std::string& _number, const std::string& _raiseTo, const int steps, const int decimals)
{
std::string raiseTo = static_cast(_raiseTo);
std::string number = static_cast(_number);
@@ -67,15 +67,12 @@ namespace steppable::__internals::arithmetic
if (isDecimal(raiseTo))
{
// Raising to decimal power.
- // Steps:
- // 1. Convert the decimal to a fraction.
- // 2. Raise the number to the numerator of the fraction.
- // 3. Take the root of the number to the denominator of the fraction.
- const auto& fraction = Fraction(raiseTo);
- const auto& [top, bottom] = fraction.asArray();
- const auto& powerResult = power(_number, top, 0);
- const auto rootResult = root(powerResult, bottom, 8);
- return reportPowerRoot(number, raiseTo, fraction, rootResult, steps);
+ // b b ln(a)
+ // a = e
+ const auto lnNumber = ln(_number, decimals + 2);
+ const auto bLnNumber = multiply(lnNumber, raiseTo, 0, decimals + 2);
+ // return reportPowerRoot(number, raiseTo, fraction, rootResult, steps);
+ return exp(bLnNumber, decimals);
}
// Here, we attempt to give a quick answer, instead of doing pointless iterations.
@@ -98,9 +95,10 @@ namespace steppable::__internals::arithmetic
auto numberNoTrailingZeros = standardizeNumber(number);
size_t numberTrailingZeros = 0;
+ auto result = splitNumber(number, "0", false, false, true, true);
if (isInteger(number))
{
- number = splitNumber(number, "0", false, false, true).splitNumberArray[0];
+ number = result.splitNumberArray[0];
numberNoTrailingZeros = removeTrailingZeros(number);
numberTrailingZeros = number.length() - numberNoTrailingZeros.length();
}
@@ -109,35 +107,31 @@ namespace steppable::__internals::arithmetic
// Remove the zeros to reduce the workload.
number = numberNoTrailingZeros;
- bool negative = false;
+ bool negativePower = false;
+
if (compare(raiseTo, "0", 0) == "0")
{
// raiseTo is negative
raiseTo = raiseTo.substr(1);
- negative = true;
+ negativePower = true;
}
- return reportPower(number, raiseTo, numberTrailingZeros, negative, steps);
+ return reportPower(number, raiseTo, numberTrailingZeros, negativePower, steps, decimals);
}
std::string exp(const std::string& x, const size_t decimals)
{
- if (compare(x, "20", 0) == "0")
+ constexpr size_t iter = 50;
+ std::string sum = "1";
+ std::string term = "1";
+ for (size_t i = 1; i < iter; i++)
{
- constexpr size_t iter = 200;
- std::string sum = "1";
- std::string term = "1";
- for (size_t i = 1; i < iter; i++)
- {
- std::string frac = divide(x, std::to_string(i), 0, static_cast(decimals));
- term = multiply(term, frac, 0);
- sum = add(sum, term, 0);
- }
- return sum;
+ std::string frac = divide(x, std::to_string(i), 0, static_cast(decimals) + 2);
+ term = multiply(term, frac, 0, static_cast(decimals) + 2);
+ sum = add(sum, term, 0);
}
-
- return power(exp(divide(x, "4", 0, decimals)), "4", 0);
+ return roundOff(sum, decimals);
}
-} // namespace steppable::__internals::arithmetic
+} // namespace steppable::__internals::calc
#ifndef NO_MAIN
int main(const int _argc, const char* _argv[])
@@ -147,14 +141,24 @@ int main(const int _argc, const char* _argv[])
program.addPosArg('a', $("power", "4252ac37-a36b-4605-9ec1-d69e70b91b46"));
program.addPosArg('b', $("power", "1fefffaf-7731-430b-989f-42e74017a2eb"));
program.addKeywordArg("steps", 2, $("power", "cb935566-6125-49ce-9ebc-e157410a3005"));
+ program.addKeywordArg("decimals", 2, $("power", "03c15572-a5aa-4b1c-a705-105770999741"));
program.addSwitch("profile", false, $("power", "e5d48237-e161-494d-940b-e2457411fcfb"));
program.parseArgs();
int steps = program.getKeywordArgument("steps");
+ int decimals = program.getKeywordArgument("decimals");
bool profile = program.getSwitch("profile");
const auto& aStr = program.getPosArg(0);
const auto& bStr = program.getPosArg(1);
+ #if DEBUG
+ if (steps == 475)
+ {
+ std::cout << steppable::__internals::calc::exp(aStr, decimals) << '\n';
+ return 0;
+ }
+ #endif
+
if (profile)
{
TIC(Power)
diff --git a/src/calc/power/powerReport.cpp b/src/calc/power/powerReport.cpp
index 70183765f..53dc20dbb 100644
--- a/src/calc/power/powerReport.cpp
+++ b/src/calc/power/powerReport.cpp
@@ -34,6 +34,7 @@
#include "fn/calc.hpp"
#include "fraction.hpp"
#include "getString.hpp"
+#include "rounding.hpp"
#include "symbols.hpp"
#include "util.hpp"
@@ -44,7 +45,7 @@ using namespace steppable::output;
using namespace steppable::localization;
using namespace steppable::prettyPrint;
using namespace steppable::__internals::symbols;
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
std::string reportPowerRoot(const std::string& _number,
const std::string& raiseTo,
@@ -70,18 +71,17 @@ std::string reportPowerRoot(const std::string& _number,
std::string reportPower(const std::string& _number,
const std::string& raiseTo,
const size_t numberTrailingZeros,
- const bool negative,
- const int steps)
+ const bool negativePower,
+ const int steps,
+ const int decimals)
{
std::stringstream ss;
- const auto numberOrig = static_cast(_number);
-
- auto number = "1"s;
+ auto result = "1"s;
// Here, we attempt to give a quick answer, instead of doing pointless iterations.
- if (numberOrig == "1")
+ if (_number == "1")
goto finish; // NOLINT(cppcoreguidelines-avoid-goto)
- if (numberOrig == "0")
+ if (_number == "0")
{
if (steps == 2)
// The number is 0, so the result is 0.
@@ -92,47 +92,48 @@ std::string reportPower(const std::string& _number,
}
loop(raiseTo, [&](const auto& i) {
- if (not negative)
- number = multiply(number, numberOrig, 0);
+ if (not negativePower)
+ result = multiply(result, _number, 0, decimals + 1);
else
- number = divide("1", number, 0);
+ result = divide("1", result, 0, decimals + 1);
auto currentPower = add(i, "1", 0);
if (steps == 2)
{
- if (not negative)
- ss << BECAUSE << " " << multiply(number, numberOrig, 1) << '\n';
+ if (not negativePower)
+ ss << BECAUSE << " " << multiply(result, _number, 1) << '\n';
else
- ss << BECAUSE << " " << divide("1", number, 1) << '\n';
- if (negative)
+ ss << BECAUSE << " " << divide("1", result, 1) << '\n';
+ if (negativePower)
currentPower = "-" + currentPower;
- ss << printers::ppSuperscript(numberOrig, currentPower) << " = " << number << '\n';
+ ss << printers::ppSuperscript(_number, currentPower) << " = " << result << '\n';
}
});
finish:
- number = numUtils::standardizeNumber(number);
+ result = numUtils::standardizeNumber(result);
+ result = numUtils::roundOff(result, decimals);
- if (negative)
+ if (negativePower)
{
if (steps == 2)
- ss << BECAUSE << " " << divide("1", number, 1) << '\n';
+ ss << BECAUSE << " " << divide("1", result, 1, decimals) << '\n';
else if (steps == 1)
{
- const auto& divisionResult = divide("1", number, 0);
- ss << numberOrig << makeSuperscript('-') << makeSuperscript(static_cast(raiseTo)) << " = "
+ const auto& divisionResult = divide("1", result, 0, decimals);
+ ss << _number << makeSuperscript('-') << makeSuperscript(static_cast(raiseTo)) << " = "
<< divisionResult;
}
else
- ss << number;
+ ss << result;
}
if (steps >= 1)
- ss << numberOrig << makeSuperscript(static_cast(raiseTo)) << " = " << number;
+ ss << _number << makeSuperscript(raiseTo) << " = " << result;
else if (steps == 0)
- ss << number;
+ ss << result;
- loop(multiply(raiseTo, std::to_string(numberTrailingZeros), 0), [&](const auto& _) { ss << "0"; });
+ loop(multiply(raiseTo, std::to_string(numberTrailingZeros), 0, 0), [&](const auto& _) { ss << "0"; });
return ss.str();
}
diff --git a/src/calc/power/powerReport.hpp b/src/calc/power/powerReport.hpp
index bbb20001a..b2dc42a23 100644
--- a/src/calc/power/powerReport.hpp
+++ b/src/calc/power/powerReport.hpp
@@ -53,7 +53,7 @@ std::string reportPowerRoot(const std::string& _number,
*
* @param[in] _number The number to raise to.
* @param[in] raiseTo The power of the number.
- * @param[in] negative Whether the result should be negative.
+ * @param[in] negativePower Whether the result should be divided by 1.
* @param[in] steps The steps to show.
*
* @return The formatted power report.
@@ -61,5 +61,6 @@ std::string reportPowerRoot(const std::string& _number,
std::string reportPower(const std::string& _number,
const std::string& raiseTo,
size_t numberTrailingZeros,
- bool negative,
- int steps);
+ bool negativePower,
+ int steps,
+ int decimals);
diff --git a/src/calc/root/root.cpp b/src/calc/root/root.cpp
index 652cbba0b..8887758e2 100644
--- a/src/calc/root/root.cpp
+++ b/src/calc/root/root.cpp
@@ -47,7 +47,7 @@
#undef min
#endif
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
using namespace steppable::__internals::utils;
using namespace steppable::__internals::stringUtils;
using namespace steppable::__internals::numUtils;
@@ -73,7 +73,7 @@ namespace steppable::prettyPrint::printers
prettyPrint::ConsoleOutput output(height, width);
prettyPrint::Position pos;
- output.write(spacing + index + '/' + topBar + '\n', { 0, 0 }, false);
+ output.write(spacing + index + '/' + topBar + '\n', { .x = 0, .y = 0 }, false);
for (size_t i = 0; i < lines.size(); i++)
{
const auto& line = lines[i];
@@ -81,13 +81,13 @@ namespace steppable::prettyPrint::printers
pos.x = static_cast(spacingWidth - i - 1);
output.write('/' + line, pos, true);
}
- output.write("\\/"s, { pos.x - 1, pos.y }, true);
+ output.write("\\/"s, { .x = pos.x - 1, .y = pos.y }, true);
return output.asString();
}
} // namespace steppable::prettyPrint::printers
-namespace steppable::__internals::arithmetic
+namespace steppable::__internals::calc
{
std::string rootIntPart(const std::string& _number, const std::string& base)
{
@@ -122,7 +122,7 @@ namespace steppable::__internals::arithmetic
auto radicand = roundDown(divide(_number, largestRootFactor.getOutput(), 0, 1));
auto multiplier = largestRootFactor.getInputs()[2];
- return { radicand, multiplier };
+ return { .radicand = radicand, .multiplier = multiplier };
}
std::string _root(const std::string& _number, const std::string& base, const size_t _decimals, const int steps)
@@ -146,7 +146,7 @@ namespace steppable::__internals::arithmetic
std::string number = static_cast(_number);
while (compare(number, "1", 0) == "0")
{
- number = multiply(number, power("10", base, 0), 0);
+ number = multiply(number, power("10", base, 0), 0, static_cast(decimals));
raisedTimes++;
}
@@ -196,12 +196,12 @@ namespace steppable::__internals::arithmetic
{
auto result = rootSurd(_number, base);
auto rootResult = _root(result.radicand, base, _decimals, 0);
- return multiply(rootResult, result.multiplier, 0);
+ return multiply(rootResult, result.multiplier, 0, static_cast(_decimals));
}
return _root(_number, base, _decimals, steps);
}
-} // namespace steppable::__internals::arithmetic
+} // namespace steppable::__internals::calc
#ifndef NO_MAIN
// NOLINTNEXTLINE(bugprone-exception-escape)
diff --git a/src/calc/subtract/subtract.cpp b/src/calc/subtract/subtract.cpp
index 6d98c57e8..910028423 100644
--- a/src/calc/subtract/subtract.cpp
+++ b/src/calc/subtract/subtract.cpp
@@ -45,9 +45,9 @@
using namespace steppable::__internals::numUtils;
using namespace steppable::output;
using namespace steppable::localization;
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
-namespace steppable::__internals::arithmetic
+namespace steppable::__internals::calc
{
std::string subtract(const std::string& a, const std::string& b, const int steps, const bool noMinus)
{
@@ -69,11 +69,9 @@ namespace steppable::__internals::arithmetic
// Scenario 3: Both a and b are negative
// Polarity : Negative
// Action : Subtract positive b from positive a
- resultIsNegative = aIsNegative and bIsNegative or compare(a, b, 0) == "0";
if (aIsNegative and not bIsNegative)
{
- resultIsNegative = true;
if (steps == 2)
// Adding {0} and {1} since {0} is negative
std::cout << $("subtract", "063f0bd2-a4ca-4433-97c0-8baa73cd0e7c", { a.substr(1), b }) << "\n";
@@ -187,7 +185,7 @@ namespace steppable::__internals::arithmetic
resultIsNegative,
noMinus);
}
-} // namespace steppable::__internals::arithmetic
+} // namespace steppable::__internals::calc
#ifndef NO_MAIN
int main(int _argc, const char* _argv[])
diff --git a/src/calc/subtract/subtractReport.cpp b/src/calc/subtract/subtractReport.cpp
index f8fa73569..d9472b0a7 100644
--- a/src/calc/subtract/subtractReport.cpp
+++ b/src/calc/subtract/subtractReport.cpp
@@ -95,7 +95,7 @@ std::string reportSubtract(const std::string& aInteger,
ss << std::string(aOut.length() - bOut.length(), ' ');
for (char bChar : bOut)
ss << bChar << " ";
- ss << '\n' << std::string(diffDigits.size() * 3 + 2, '_') << '\n' << " ";
+ ss << '\n' << std::string((diffDigits.size() * 3) + 2, '_') << '\n' << " ";
for (int outputDigit : diffDigits)
{
diff --git a/src/calc/trig/trig.cpp b/src/calc/trig/trig.cpp
index 3aa51d10e..e4cd2ff77 100644
--- a/src/calc/trig/trig.cpp
+++ b/src/calc/trig/trig.cpp
@@ -47,7 +47,7 @@ using namespace steppable::localization;
using namespace steppable::__internals::utils;
using namespace steppable::__internals::numUtils;
-namespace steppable::__internals::arithmetic
+namespace steppable::__internals::calc
{
std::string degToRad(const std::string& _deg)
{
@@ -65,24 +65,24 @@ namespace steppable::__internals::arithmetic
return rad;
}
- std::string radToDeg(const std::string& _rad)
+ std::string radToDeg(const std::string& _rad, const int decimals)
{
// deg = rad * (180 / pi)
auto rad = _rad;
rad = divideWithQuotient(rad, static_cast(constants::TWO_PI)).remainder;
rad = standardizeNumber(rad);
- auto deg = divide(rad, static_cast(constants::PI_OVER_180), 0);
+ auto deg = divide(rad, static_cast(constants::PI_OVER_180), 0, decimals);
deg = standardizeNumber(deg);
deg = divideWithQuotient(deg, "90").remainder;
return standardizeNumber(deg);
}
- std::string radToGrad(const std::string& _rad)
+ std::string radToGrad(const std::string& _rad, const int decimals)
{
// grad = rad * (200 / pi)
auto rad = divideWithQuotient(_rad, static_cast(constants::TWO_PI)).remainder;
rad = standardizeNumber(rad);
- auto grad = divide(rad, static_cast(constants::PI_OVER_200), 0);
+ auto grad = divide(rad, static_cast(constants::PI_OVER_200), 0, decimals);
grad = standardizeNumber(grad);
grad = divideWithQuotient(grad, "100").remainder;
return standardizeNumber(grad);
@@ -95,9 +95,10 @@ namespace steppable::__internals::arithmetic
return deg;
}
- std::string _cos(const std::string& x, const int decimals)
+ std::string _cos(const std::string& x, const int _decimals)
{
- checkDecimalArg(&decimals);
+ int decimals = _decimals;
+ checkDecimalArg(&_decimals);
// .,,. ., /=====================================================================\
// //%, .( | NOTE: DO NOT CALL THIS METHOD DIRECTLY IN PRODUCTION CODE! |
@@ -115,24 +116,25 @@ namespace steppable::__internals::arithmetic
if (compare(abs(x, 0), "0.001", 0) == "0") // If small, use polynomial approximant
{
// double x2 = x * x;
- auto x2 = multiply(x, x, 0);
- auto x4 = multiply(x2, x2, 0);
+ auto x2 = multiply(x, x, 0, decimals);
+ auto x4 = multiply(x2, x2, 0, decimals);
// (313*x^4 - 6900*x^2 + 15120)/(13*x^4 + 660*x^2 + 15120) // Padé approximant
// 4 2
// 313x - 6900x + 15120
// ------------------------
// 4 2
// 13x + 660x + 15120
- auto a = add(subtract(multiply("313", x4, 0), multiply("6900", x2, 0), 0), "15120", 0);
- auto b = add(add(multiply("13", x4, 0), multiply("660", x2, 0), 0), "15120", 0);
+ auto a = add(subtract(multiply("313", x4, 0, decimals), multiply("6900", x2, 0, decimals), 0), "15120", 0);
+ auto b = add(add(multiply("13", x4, 0, decimals), multiply("660", x2, 0, decimals), 0), "15120", 0);
return standardizeNumber(divide(a, b, 0, decimals + 2));
}
// otherwise use recursion
// double C = cos(x / 4);
auto result = _cos(standardizeNumber(divide(x, "4", 0, decimals + 1)), decimals + 2);
- auto result2 = roundOff(multiply(result, result, 0), static_cast(decimals) + 2);
+ auto result2 = roundOff(multiply(result, result, 0, decimals + 2), static_cast(decimals) + 2);
// return 8 * C2 * (C2 - 1) + 1;
- return standardizeNumber(add(multiply("8", multiply(result2, subtract(result2, "1", 0), 0), 0), "1", 0));
+ return standardizeNumber(
+ add(multiply("8", multiply(result2, subtract(result2, "1", 0), 0, decimals), 0), "1", 0));
}
std::string cos(const std::string& x, const int decimals, const int mode)
@@ -148,23 +150,23 @@ namespace steppable::__internals::arithmetic
{
case 0:
{
- result = _cos(divideWithQuotient(x, static_cast(constants::TWO_PI)).remainder, decimals);
+ result = _cos(divideWithQuotient(x, static_cast(constants::TWO_PI)).remainder, decimals + 2);
break;
}
case 1:
{
- result = _cos(degToRad(x), decimals);
+ result = _cos(degToRad(x), decimals + 2);
break;
}
case 2:
{
- result = _cos(gradToRad(x), decimals);
+ result = _cos(gradToRad(x), decimals + 2);
break;
}
default:
{
error("trig::cos"s, "Invalid mode. Defaulting to radians."s);
- result = _cos(x, decimals);
+ result = _cos(x, decimals + 2);
}
}
@@ -319,7 +321,7 @@ namespace steppable::__internals::arithmetic
{
isReduced = true;
// Reduce x to a small number
- x = divide("1", x, 0, decimals * 2);
+ x = divide("1", x, 0, decimals + 2);
}
// Otherwise, use integration.
// 1 / x
@@ -328,11 +330,11 @@ namespace steppable::__internals::arithmetic
// dx x + 1 | 2
// / 0 t + 1
auto fx = [&](const std::string& y) {
- const auto& y2 = power(y, "2", 0);
+ const auto& y2 = multiply(y, y, 0);
const auto& denominator = add(y2, "1", 0);
- return divide("1", denominator, 0, decimals + 1);
+ return divide("1", denominator, 0, decimals * 2);
};
- auto result = calculus::romberg(fx, "0", x, 10, decimals + 1);
+ auto result = calculus::romberg(fx, "0", x, 10, decimals + 2);
if (isReduced)
{
// If x was reduced, use the identity
@@ -346,10 +348,10 @@ namespace steppable::__internals::arithmetic
switch (mode)
{
case 1:
- result = radToDeg(result);
+ result = radToDeg(result, decimals + 1);
break;
case 2:
- result = radToGrad(result);
+ result = radToGrad(result, decimals + 1);
break;
default:
break;
@@ -382,18 +384,18 @@ namespace steppable::__internals::arithmetic
auto integrand = [&](const std::string& y) {
auto y2 = power(y, "2", 0);
auto oneMinusY2 = subtract("1", y2, 0);
- auto denominator = root(oneMinusY2, "2", decimals + 1);
- return divide("1", denominator, 0, decimals + 1);
+ auto denominator = root(oneMinusY2, "2", decimals + 2);
+ return divide("1", denominator, 0, decimals + 2);
};
auto result = calculus::romberg(integrand, "0", x, 10, decimals + 2);
switch (mode)
{
case 1:
- result = radToDeg(result);
+ result = radToDeg(result, decimals + 1);
break;
case 2:
- result = radToGrad(result);
+ result = radToGrad(result, decimals + 1);
break;
default:
break;
@@ -424,7 +426,7 @@ namespace steppable::__internals::arithmetic
// pi
// acos(x) = ----- - asin(x)
// 2
- auto result = subtract(circleAngle, asin(x, decimals, mode), 0);
+ auto result = subtract(circleAngle, asin(x, decimals + 2, mode), 0);
return roundOff(result, decimals);
}
@@ -475,7 +477,7 @@ namespace steppable::__internals::arithmetic
// x
return atan(divide("1", x, 0, decimals), decimals, mode);
}
-} // namespace steppable::__internals::arithmetic
+} // namespace steppable::__internals::calc
#ifndef NO_MAIN
int main(int _argc, const char* _argv[])
@@ -501,31 +503,31 @@ int main(int _argc, const char* _argv[])
// Basic trigonometric functions
if (command == "sin")
- function = arithmetic::sin;
+ function = calc::sin;
else if (command == "cos")
- function = arithmetic::cos;
+ function = calc::cos;
else if (command == "tan")
- function = arithmetic::tan;
+ function = calc::tan;
// Reciprocal trigonometric functions
else if (command == "csc")
- function = arithmetic::csc;
+ function = calc::csc;
else if (command == "sec")
- function = arithmetic::sec;
+ function = calc::sec;
else if (command == "cot")
- function = arithmetic::cot;
+ function = calc::cot;
// Inverse trigonometric functions
else if (command == "atan")
- function = arithmetic::atan;
+ function = calc::atan;
else if (command == "asin")
- function = arithmetic::asin;
+ function = calc::asin;
else if (command == "acos")
- function = arithmetic::acos;
+ function = calc::acos;
else if (command == "asec")
- function = arithmetic::asec;
+ function = calc::asec;
else if (command == "acsc")
- function = arithmetic::acsc;
+ function = calc::acsc;
else if (command == "acot")
- function = arithmetic::acot;
+ function = calc::acot;
// Invalid command
else
{
diff --git a/src/calculus/nInt/nInt.cpp b/src/calculus/nInt/nInt.cpp
index 78613351d..913d9ddff 100644
--- a/src/calculus/nInt/nInt.cpp
+++ b/src/calculus/nInt/nInt.cpp
@@ -31,7 +31,7 @@
#include
#include
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
using namespace steppable::__internals::numUtils;
using namespace steppable::__internals::utils;
using namespace std::literals;
@@ -52,27 +52,28 @@ namespace steppable::__internals::calculus
auto h = subtract(b, a, 0);
auto fAB = add(f(a), f(b), 0);
- auto halfH = multiply(h, "0.5", 0);
- previous.front() = multiply(halfH, fAB, 0);
+ auto halfH = multiply(h, "0.5", 0, decimals + 2);
+ previous.front() = multiply(halfH, fAB, 0, decimals + 2);
for (int i = 1; i < max_steps; i++)
{
- h = multiply(h, "0.5", 0);
+ h = multiply(h, "0.5", 0, decimals + 2);
auto c = "0"s;
long ep = 1 << (i - 1); // 2^(i - 1)
for (long j = 1; j < (ep + 1); j++)
{
- auto d = multiply(std::to_string((2 * j) - 1), h, 0);
+ auto d = multiply(std::to_string((2 * j) - 1), h, 0, decimals + 2);
c = add(c, f(add(a, d, 0)), 0);
}
- current.front() = add(multiply(h, c, 0), multiply("0.5", previous.front(), 0), 0);
+ current.front() =
+ add(multiply(h, c, 0, decimals + 2), multiply("0.5", previous.front(), 0, decimals + 2), 0);
for (int j = 1; j < (i + 1); j++)
{
long double n_k = pow(4, j);
- auto one = multiply(std::to_string(n_k), current.at(j - 1), 0);
+ auto one = multiply(std::to_string(n_k), current.at(j - 1), 0, decimals + 2);
auto top = subtract(one, previous.at(j - 1), 0);
- current.at(j) = divide(top, std::to_string(n_k - 1), 0, decimals + 1);
+ current.at(j) = divide(top, std::to_string(n_k - 1), 0, decimals + 2);
if (i > 1 and compare(abs(subtract(previous.at(i - 1), current.at(i), 0), 0), acc, 0) == "0")
return roundOff(current.at(i), decimals);
diff --git a/src/constants.cpp b/src/constants.cpp
index e715b0dff..6cbba03b4 100644
--- a/src/constants.cpp
+++ b/src/constants.cpp
@@ -27,15 +27,5 @@
// NOLINTBEGIN(cert-err58-cpp)
namespace steppable::constants
{
- const std::string_view& PI =
- "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679";
- const std::string_view& TWO_PI = "6.283185307179586231995926937088370323181152343750";
- const std::string_view& PI_OVER_2 =
- "1.570796326794896619231321691639751442098584699687552910487472296153908203143104499314017412835292542";
- const std::string_view& PI_OVER_180 =
- "0.01745329251994329508887757482524547311994764539930555555555555555555555555555555555555555555555555556";
- const std::string_view& PI_OVER_200 =
- "0.01570796326794896619231321691639716312084074699687552942986246296153903203140449499314017412671058534";
- const std::string_view& E = "2.718281828459045090795598298427648842334747314453125";
} // namespace steppable::constants
// NOLINTEND(cert-err58-cpp)
diff --git a/src/factors.cpp b/src/factors.cpp
index dfa585cd3..a31416228 100644
--- a/src/factors.cpp
+++ b/src/factors.cpp
@@ -28,7 +28,7 @@
#include
#include
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
using namespace steppable::types;
namespace steppable::__internals::numUtils
@@ -54,20 +54,22 @@ namespace steppable::__internals::numUtils
return factors;
}
- ResultBool getRootFactor(const std::string& _number, const std::string& base)
+ ResultBool getRootFactor(const std::string& _number, const std::string& base)
{
auto factors = getFactors(_number);
// Reverse the factors
- std::reverse(factors.begin(), factors.end());
+ std::ranges::reverse(factors);
// Get the largest root factor
for (const auto& factor : factors)
{
auto rootResult = isRoot(factor, base);
if (rootResult.getStatus() == StatusBool::CALCULATED_SIMPLIFIED_YES)
- return { { _number, base, rootResult.getOutput() }, factor, StatusBool::CALCULATED_SIMPLIFIED_YES };
+ return {
+ { _number, base, rootResult.getOutput() }, { factor }, factor, StatusBool::CALCULATED_SIMPLIFIED_YES
+ };
}
// The number has no root factors
- return { { _number, base }, "1", StatusBool::CALCULATED_SIMPLIFIED_YES };
+ return { { _number, base }, { "1" }, { "1" }, StatusBool::CALCULATED_SIMPLIFIED_YES };
}
std::string getGreatestRootNum(const std::string& _number, const std::string& base)
@@ -82,12 +84,12 @@ namespace steppable::__internals::numUtils
return factors.size() == 2; // Only 1 and the number itself are factors ==> prime!
}
- ResultBool isRoot(const std::string& _number, const std::string& base)
+ ResultBool isRoot(const std::string& _number, const std::string& base)
{
auto iRoot = rootIntPart(_number, base);
auto rootNum = power(iRoot, base, 0);
if (compare(rootNum, _number, 0) == "2")
- return { { _number, base }, iRoot, StatusBool::CALCULATED_SIMPLIFIED_YES };
- return { { _number, base }, "1", StatusBool::CALCULATED_SIMPLIFIED_NO };
+ return { { _number, base }, { iRoot }, { iRoot }, StatusBool::CALCULATED_SIMPLIFIED_YES };
+ return { { _number, base }, { "1" }, { "1" }, StatusBool::CALCULATED_SIMPLIFIED_NO };
}
} // namespace steppable::__internals::numUtils
diff --git a/src/format.cpp b/src/format.cpp
index 4c61820c0..02889f1ab 100644
--- a/src/format.cpp
+++ b/src/format.cpp
@@ -42,9 +42,8 @@ namespace steppable::__internals::format
std::string result = format;
std::string index;
bool inBrackets = false;
- for (size_t idx = 0; idx < format.size(); idx++)
+ for (char i : format)
{
- char i = format.at(idx);
switch (i)
{
// Start replacing!
@@ -61,7 +60,7 @@ namespace steppable::__internals::format
inBrackets = false;
// SIZE_MAX is 20 digits long, so we can safely assume that the index must not be longer than 20
// characters.
- if (index.length() > 20 or index.length() < 1)
+ if (index.length() > 20 or index.empty())
throw std::length_error("Argument index too long or too short.");
if (not std::ranges::all_of(index, [](const char& c) { return std::isdigit(c); }))
throw std::invalid_argument("Argument index must be a number.");
diff --git a/src/fraction.cpp b/src/fraction.cpp
index 9d822689f..018b1f248 100644
--- a/src/fraction.cpp
+++ b/src/fraction.cpp
@@ -44,7 +44,7 @@
#undef min
#endif
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
using namespace steppable::__internals::numUtils;
namespace steppable::prettyPrint::printers
diff --git a/src/number.cpp b/src/number.cpp
index 00ca97358..838f2e061 100644
--- a/src/number.cpp
+++ b/src/number.cpp
@@ -40,7 +40,7 @@
namespace steppable
{
- using namespace steppable::__internals::arithmetic;
+ using namespace steppable::__internals::calc;
Number::Number() : prec(8), value("0") {}
@@ -52,7 +52,7 @@ namespace steppable
Number Number::operator-(const Number& rhs) const { return subtract(value, rhs.value, 0); }
- Number Number::operator*(const Number& rhs) const { return multiply(value, rhs.value, 0); }
+ Number Number::operator*(const Number& rhs) const { return multiply(value, rhs.value, 0, static_cast(prec)); }
Number Number::operator/(const Number& rhs) const
{
@@ -77,7 +77,7 @@ namespace steppable
Number Number::operator%(const Number& rhs) const { return divideWithQuotient(value, rhs.value).remainder; }
- Number Number::operator^(const Number& rhs) const { return power(value, rhs.value, 0); }
+ Number Number::operator^(const Number& rhs) const { return power(value, rhs.value, 0, static_cast(prec)); }
Number& Number::operator+=(const Number& rhs)
{
diff --git a/src/rounding.cpp b/src/rounding.cpp
index 1fa2d7c2d..421f7dc2d 100644
--- a/src/rounding.cpp
+++ b/src/rounding.cpp
@@ -51,9 +51,9 @@ namespace steppable::__internals::numUtils
// Round up the number
auto splitNumberResult = splitNumber(number, "0", false, true, true, false).splitNumberArray;
auto integer = splitNumberResult[0];
- auto decimal = splitNumberResult[1]; // Return the integer part
+ const auto& decimal = splitNumberResult[1]; // Return the integer part
if (decimal.front() > '5')
- integer = arithmetic::add(integer, "1", 0);
+ integer = calc::add(integer, "1", 0);
return integer;
}
@@ -72,12 +72,15 @@ namespace steppable::__internals::numUtils
auto decimal = splitNumberArray[1];
bool isNegative = splitNumberResult.aIsNegative;
+ if (decimal.length() < digits)
+ return _number;
+
// Preserve one digit after the rounded digit
decimal = decimal.substr(0, digits + 1);
// Modify the integer part if the digit is greater than 5
if (decimal.front() >= '5' and digits == 0)
{
- integer = arithmetic::add(integer, "1", 0);
+ integer = calc::add(integer, "1", 0);
return integer;
}
auto newDecimal = decimal.substr(0, digits);
@@ -94,7 +97,7 @@ namespace steppable::__internals::numUtils
{
newDecimal[i] = '0';
if (i == newDecimal.length() - 1)
- integer = arithmetic::add(integer, "1", 0);
+ integer = calc::add(integer, "1", 0);
}
else
{
diff --git a/src/testing.cpp b/src/testing.cpp
index 712766082..4ae92c3a1 100644
--- a/src/testing.cpp
+++ b/src/testing.cpp
@@ -26,13 +26,14 @@
#include "output.hpp"
#include
+#include
using namespace std::literals;
using namespace steppable::output;
namespace steppable::testing
{
- TestCase::TestCase(const std::string& testCaseName) : testCaseName(testCaseName) {}
+ TestCase::TestCase(std::string testCaseName) : testCaseName(std::move(testCaseName)) {}
void TestCase::assert(const bool condition, const std::string& conditionName)
{
diff --git a/src/util.cpp b/src/util.cpp
index 0c4011ee3..1177a1fdf 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -22,8 +22,6 @@
#include "util.hpp"
-#include "platform.hpp"
-
#include
#ifdef WINDOWS
@@ -171,7 +169,9 @@ namespace steppable::__internals::numUtils
aDecimal += std::string(-diffLengthDecimal, '0');
}
std::array splitNumberResult{ aInteger, aDecimal, bInteger, bDecimal };
- return SplitNumberResult{ splitNumberResult, aIsNegative, bIsNegative };
+ return SplitNumberResult{ .splitNumberArray = splitNumberResult,
+ .aIsNegative = aIsNegative,
+ .bIsNegative = bIsNegative };
}
auto replaceLeadingZeros(const std::vector& vector) -> std::decay_t
@@ -244,8 +244,8 @@ namespace steppable::__internals::numUtils
long long determineScale(const std::string& number)
{
auto splitNumberResult = splitNumber(number, "0", false, false).splitNumberArray;
- auto numberInteger = splitNumberResult[0];
- auto numberDecimal = splitNumberResult[1];
+ const auto& numberInteger = splitNumberResult[0];
+ const auto& numberDecimal = splitNumberResult[1];
// If there is an integer component, determine the scale of it
if (not isZeroString(numberInteger))
@@ -285,6 +285,27 @@ namespace steppable::__internals::numUtils
number = number.substr(1, number.length() - 1);
return not std::ranges::any_of(number, [](const auto& c) { return c != '0' and c != '.'; });
}
+
+ bool isOdd(const std::string& number)
+ {
+ if (isDecimal(number))
+ return false; // Decimals cannot be classified.
+ if (isZeroString(number))
+ return false; // Zero is neither even nor odd.
+
+ const char lastDigit = number.back();
+ return (lastDigit - '0') % 2 == 1;
+ }
+
+ bool isEven(const std::string& number)
+ {
+ if (isDecimal(number))
+ return false; // Decimals cannot be classified.
+ if (isZeroString(number))
+ return false; // Zero is neither even nor odd.
+
+ return not isOdd(number);
+ }
} // namespace steppable::__internals::numUtils
namespace steppable::__internals::stringUtils
diff --git a/steppyble/__init__.pyi b/steppyble/__init__.pyi
new file mode 100644
index 000000000..a62e1732d
--- /dev/null
+++ b/steppyble/__init__.pyi
@@ -0,0 +1,25 @@
+#####################################################################################################
+# Copyright (c) 2023-2025 NWSOFT #
+# #
+# Permission is hereby granted, free of charge, to any person obtaining a copy #
+# of this software and associated documentation files (the "Software"), to deal #
+# in the Software without restriction, including without limitation the rights #
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell #
+# copies of the Software, and to permit persons to whom the Software is #
+# furnished to do so, subject to the following conditions: #
+# #
+# The above copyright notice and this permission notice shall be included in all #
+# copies or substantial portions of the Software. #
+# #
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, #
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, #
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE #
+# SOFTWARE. #
+#####################################################################################################
+
+from .number import *
+from .fraction import *
+from .rounding_mode import *
diff --git a/steppyble/fraction.pyi b/steppyble/fraction.pyi
new file mode 100644
index 000000000..489a420df
--- /dev/null
+++ b/steppyble/fraction.pyi
@@ -0,0 +1,79 @@
+#####################################################################################################
+# Copyright (c) 2023-2025 NWSOFT #
+# #
+# Permission is hereby granted, free of charge, to any person obtaining a copy #
+# of this software and associated documentation files (the "Software"), to deal #
+# in the Software without restriction, including without limitation the rights #
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell #
+# copies of the Software, and to permit persons to whom the Software is #
+# furnished to do so, subject to the following conditions: #
+# #
+# The above copyright notice and this permission notice shall be included in all #
+# copies or substantial portions of the Software. #
+# #
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, #
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, #
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE #
+# SOFTWARE. #
+#####################################################################################################
+
+import steppyble
+
+
+class Fraction:
+ def __init__(self, top: str = "1", bottom: str = "1") -> None:
+ ...
+
+ def __repr__(self) -> str:
+ ...
+
+ def __add__(self, _: steppyble.Fraction, /) -> steppyble.Fraction:
+ ...
+
+ def __iadd__(self, _: steppyble.Fraction, /) -> steppyble.Fraction:
+ ...
+
+ def __sub__(self, _: steppyble.Fraction, /) -> steppyble.Fraction:
+ ...
+
+ def __isub__(self, _: steppyble.Fraction, /) -> steppyble.Fraction:
+ ...
+
+ def __mul__(self, _: steppyble.Fraction, /) -> steppyble.Fraction:
+ ...
+
+ def __imul__(self, _: steppyble.Fraction, /) -> steppyble.Fraction:
+ ...
+
+ def __truediv__(self, _: steppyble.Fraction, /) -> steppyble.Fraction:
+ ...
+
+ def __itruediv__(self, _: steppyble.Fraction, /) -> steppyble.Fraction:
+ ...
+
+ def __pow__(self, _: steppyble.Fraction, /) -> steppyble.Fraction:
+ ...
+
+ def __ipow__(self, _: steppyble.Fraction, /) -> steppyble.Fraction:
+ ...
+
+ def __eq__(self, _: object, /) -> bool:
+ ...
+
+ def __ne__(self, _: object, /) -> bool:
+ ...
+
+ def __ge__(self, _: steppyble.Fraction, /) -> bool:
+ ...
+
+ def __gt__(self, _: steppyble.Fraction, /) -> bool:
+ ...
+
+ def __le__(self, _: steppyble.Fraction, /) -> bool:
+ ...
+
+ def __lt__(self, _: steppyble.Fraction, /) -> bool:
+ ...
diff --git a/steppyble/number.pyi b/steppyble/number.pyi
new file mode 100644
index 000000000..3e2c8b5e9
--- /dev/null
+++ b/steppyble/number.pyi
@@ -0,0 +1,86 @@
+#####################################################################################################
+# Copyright (c) 2023-2025 NWSOFT #
+# #
+# Permission is hereby granted, free of charge, to any person obtaining a copy #
+# of this software and associated documentation files (the "Software"), to deal #
+# in the Software without restriction, including without limitation the rights #
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell #
+# copies of the Software, and to permit persons to whom the Software is #
+# furnished to do so, subject to the following conditions: #
+# #
+# The above copyright notice and this permission notice shall be included in all #
+# copies or substantial portions of the Software. #
+# #
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, #
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, #
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE #
+# SOFTWARE. #
+#####################################################################################################
+
+import steppyble
+
+
+class Number:
+ """A Steppable number, which performs exactly like a Python number, allowing add, subtract, multiply..."""
+
+ def __init__(
+ self,
+ value: str = "0",
+ prec: int = 5,
+ roundingMode: steppyble.RoundingMode = steppyble.RoundingMode.USE_CURRENT_PREC,
+ ) -> None:
+ ...
+
+ def __repr__(self) -> str:
+ ...
+
+ def __add__(self, _: steppyble.Number, /) -> steppyble.Number:
+ ...
+
+ def __iadd__(self, _: steppyble.Number, /) -> steppyble.Number:
+ ...
+
+ def __sub__(self, _: steppyble.Number, /) -> steppyble.Number:
+ ...
+
+ def __isub__(self, _: steppyble.Number, /) -> steppyble.Number:
+ ...
+
+ def __mul__(self, _: steppyble.Number, /) -> steppyble.Number:
+ ...
+
+ def __imul__(self, _: steppyble.Number, /) -> steppyble.Number:
+ ...
+
+ def __truediv__(self, _: steppyble.Number, /) -> steppyble.Number:
+ ...
+
+ def __itruediv__(self, _: steppyble.Number, /) -> steppyble.Number:
+ ...
+
+ def __pow__(self, _: steppyble.Number, /) -> steppyble.Number:
+ ...
+
+ def __ipow__(self, _: steppyble.Number, /) -> steppyble.Number:
+ ...
+
+ def __eq__(self, _: object, /) -> bool:
+ ...
+
+ def __ne__(self, _: object, /) -> bool:
+ ...
+
+ def __ge__(self, _: steppyble.Number, /) -> bool:
+ ...
+
+ def __gt__(self, _: steppyble.Number, /) -> bool:
+ ...
+
+ def __le__(self, _: steppyble.Number, /) -> bool:
+ ...
+
+ def __lt__(self, _: steppyble.Number, /) -> bool:
+ ...
diff --git a/steppyble/rounding_mode.pyi b/steppyble/rounding_mode.pyi
new file mode 100644
index 000000000..238532f34
--- /dev/null
+++ b/steppyble/rounding_mode.pyi
@@ -0,0 +1,42 @@
+#####################################################################################################
+# Copyright (c) 2023-2025 NWSOFT #
+# #
+# Permission is hereby granted, free of charge, to any person obtaining a copy #
+# of this software and associated documentation files (the "Software"), to deal #
+# in the Software without restriction, including without limitation the rights #
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell #
+# copies of the Software, and to permit persons to whom the Software is #
+# furnished to do so, subject to the following conditions: #
+# #
+# The above copyright notice and this permission notice shall be included in all #
+# copies or substantial portions of the Software. #
+# #
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, #
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, #
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE #
+# SOFTWARE. #
+#####################################################################################################
+
+import enum
+
+
+class RoundingMode(enum.Enum):
+ """Specifies how Steppable should round the number in operations."""
+
+ USE_MAXIMUM_PREC = 0xFF
+ """Use the higher precision whenever possible."""
+
+ USE_MINIMUM_PREC = 0x01
+ """Use the lower precision whenever possible."""
+
+ USE_CURRENT_PREC = 0x02
+ """Use the current precision."""
+
+ USE_OTHER_PREC = 0x03
+ """Use the other number's precision."""
+
+ DISCARD_ALL_DECIMALS = 0x00
+ """Do not append any decimal places."""
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index a61cf08fc..2e25b6389 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -28,3 +28,6 @@ FOREACH(ITEM IN LISTS TEST_TARGETS)
ADD_TEST(NAME ${ITEM} COMMAND ${CMAKE_BINARY_DIR}/tests/${ITEM})
MESSAGE(TRACE "Added test case: ${ITEM}: ${ITEM}.cpp")
ENDFOREACH()
+
+ADD_CUSTOM_TARGET(tests)
+ADD_DEPENDENCIES(tests ${TEST_TARGETS})
diff --git a/tests/testAbs.cpp b/tests/testAbs.cpp
index 3bac52a3f..bed133324 100644
--- a/tests/testAbs.cpp
+++ b/tests/testAbs.cpp
@@ -31,7 +31,7 @@
TEST_START()
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
SECTION(Absolute value with positive number)
const std::string& a = "6453.55";
diff --git a/tests/testAdd.cpp b/tests/testAdd.cpp
index 27afa8813..fdc0ed7b7 100644
--- a/tests/testAdd.cpp
+++ b/tests/testAdd.cpp
@@ -31,7 +31,7 @@
TEST_START()
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
SECTION(Addition with multiple digits of different length)
const std::string& a = "6453.55";
diff --git a/tests/testComparison.cpp b/tests/testComparison.cpp
index 9a790155a..1a05421e5 100644
--- a/tests/testComparison.cpp
+++ b/tests/testComparison.cpp
@@ -31,7 +31,7 @@
TEST_START()
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
SECTION(Comparison at integer)
const std::string &a = "6453.55";
diff --git a/tests/testDecimalConvert.cpp b/tests/testDecimalConvert.cpp
index 7e36a992b..5649c34b4 100644
--- a/tests/testDecimalConvert.cpp
+++ b/tests/testDecimalConvert.cpp
@@ -31,7 +31,7 @@
TEST_START()
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
SECTION(Decimal Convert without letters)
const std::string &a = "46432231133131";
diff --git a/tests/testDivision.cpp b/tests/testDivision.cpp
index 531a6f5fa..5d3a75b65 100644
--- a/tests/testDivision.cpp
+++ b/tests/testDivision.cpp
@@ -31,7 +31,7 @@
TEST_START()
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
SECTION(Integer division)
// A gogol divided by 50
diff --git a/tests/testFactorial.cpp b/tests/testFactorial.cpp
index 75caa21bf..0461eda71 100644
--- a/tests/testFactorial.cpp
+++ b/tests/testFactorial.cpp
@@ -29,7 +29,7 @@
#include
#include
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
TEST_START()
SECTION(Factorial)
diff --git a/tests/testHyp.cpp b/tests/testHyp.cpp
index 02f64d95e..f57efded2 100644
--- a/tests/testHyp.cpp
+++ b/tests/testHyp.cpp
@@ -31,7 +31,7 @@
TEST_START()
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
SECTION(Test hyperbolic sine)
_.assertIsEqual(sinh("10", 3), "11013.233");
@@ -46,7 +46,7 @@ _.assertIsEqual(tanh("0.5", 5), "0.46212");
SECTION_END()
SECTION(Test hyperbolic cotangent)
-_.assertIsEqual(coth("1.25", 5), "1.17884");
+_.assertIsEqual(coth("1.25", 5), "1.17885");
SECTION_END()
SECTION(Test hyperbolic secant)
diff --git a/tests/testLog.cpp b/tests/testLog.cpp
index e94b3fb9d..0eafdeaaa 100644
--- a/tests/testLog.cpp
+++ b/tests/testLog.cpp
@@ -30,7 +30,7 @@
#include
TEST_START()
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
SECTION(Test natural logarithm)
_.assertIsEqual(ln("5.3", 4), "1.6677");
diff --git a/tests/testMultiply.cpp b/tests/testMultiply.cpp
index 1b1ee0e3a..4586f827c 100644
--- a/tests/testMultiply.cpp
+++ b/tests/testMultiply.cpp
@@ -31,7 +31,7 @@
TEST_START()
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
SECTION(Multiplication without carry)
const std::string &a = "2";
diff --git a/tests/testNInt.cpp b/tests/testNInt.cpp
index 9dae516f2..7e3568d6d 100644
--- a/tests/testNInt.cpp
+++ b/tests/testNInt.cpp
@@ -31,7 +31,7 @@
#include
using namespace steppable::__internals::calculus;
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
TEST_START()
diff --git a/tests/testPower.cpp b/tests/testPower.cpp
index d30779bdc..76e2904d0 100644
--- a/tests/testPower.cpp
+++ b/tests/testPower.cpp
@@ -32,12 +32,12 @@
TEST_START()
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
SECTION(Power)
const std::string number = "47";
const std::string raiseTo = "10";
-const auto& result = power(number, raiseTo, 0);
+const auto& result = power(number, raiseTo, 0, 8);
_.assertIsEqual(result, "52599132235830049");
SECTION_END()
@@ -45,23 +45,23 @@ SECTION_END()
SECTION(Power with Decimals)
const std::string number = "47.5";
const std::string raiseTo = "10";
-const auto& result = power(number, raiseTo, 0);
+const auto& result = power(number, raiseTo, 0, 8);
-_.assertIsEqual(result, "58470404222497940.0634765625");
+_.assertIsEqual(result, "58470404222497940.06347656");
SECTION_END()
SECTION(Power with Decimals)
const std::string number = "0.5";
const std::string raiseTo = "10";
-const auto& result = power(number, raiseTo, 0);
+const auto& result = power(number, raiseTo, 0, 8);
-_.assertIsEqual(result, "0.0009765625");
+_.assertIsEqual(result, "0.00097656");
SECTION_END()
SECTION(Power with Decimal Exponents)
const std::string number = "4";
const std::string raiseTo = "0.5";
-const auto& result = power(number, raiseTo, 0);
+const auto& result = power(number, raiseTo, 0, 2);
_.assertIsEqual(numUtils::roundOff(result), "2");
SECTION_END()
diff --git a/tests/testRoot.cpp b/tests/testRoot.cpp
index 6f181b7ba..8d020743e 100644
--- a/tests/testRoot.cpp
+++ b/tests/testRoot.cpp
@@ -31,17 +31,17 @@
TEST_START()
SECTION(Root with a sqare number)
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
_.assertIsEqual(root("4", "2", 0), "2");
SECTION_END()
SECTION(Root with a decimal index)
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
_.assertIsEqual(root("4", "0.5", 0), "16");
SECTION_END()
SECTION(Surds)
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
auto surd = rootSurd("27", "2");
_.assertIsEqual(surd.multiplier, "3");
_.assertIsEqual(surd.radicand, "3");
diff --git a/tests/testSubtract.cpp b/tests/testSubtract.cpp
index 3cbe06d74..ddd65017c 100644
--- a/tests/testSubtract.cpp
+++ b/tests/testSubtract.cpp
@@ -31,7 +31,7 @@
TEST_START()
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
SECTION(Subtraction with multiple digits of different length)
const std::string &a = "54329.334";
diff --git a/tests/testTrig.cpp b/tests/testTrig.cpp
index fb6998eed..4b9f45cfb 100644
--- a/tests/testTrig.cpp
+++ b/tests/testTrig.cpp
@@ -30,7 +30,7 @@
#include
TEST_START()
-using namespace steppable::__internals::arithmetic;
+using namespace steppable::__internals::calc;
// We can just test the basics of the trigonometric functions, as the rest are based on them.
SECTION(Test sine and cosine)
@@ -45,7 +45,7 @@ _.assertIsEqual(tan("90", 2, 1), "Infinity");
SECTION_END()
SECTION(Test arc cosine)
-_.assertIsEqual(acos("0.5", 2, 1), "60.00");
+_.assertIsEqual(acos("0.5", 2, 1), "60");
// Zero check test
_.assertIsEqual(acos("1", 2, 1), "0");
SECTION_END()
diff --git a/tools/add_copyright_header.py b/tools/add_copyright_header.py
index bbcf8a6c2..a38528d9c 100644
--- a/tools/add_copyright_header.py
+++ b/tools/add_copyright_header.py
@@ -186,7 +186,7 @@ def process(file: Path) -> None:
with open(file, "w", encoding="utf-8") as f:
f.write(contents)
elif (
- file.suffix == ".py"
+ file.suffix in (".py", ".pyi")
or file.name == "CMakeLists.txt"
or ".stp_" in file.suffix # Steppable configuration files
): # Python File or CMake file
@@ -235,3 +235,4 @@ def walk_into_directory(path: Path) -> None:
walk_into_directory(PROJECT_PATH / "src")
walk_into_directory(PROJECT_PATH / "tests")
walk_into_directory(PROJECT_PATH / "tools")
+ walk_into_directory(PROJECT_PATH / "steppyble")
diff --git a/tools/run_clang_tidy.py b/tools/run_clang_tidy.py
index baf521a82..06da1755d 100644
--- a/tools/run_clang_tidy.py
+++ b/tools/run_clang_tidy.py
@@ -324,7 +324,7 @@ def run_tidy(
err += msg.encode("utf-8")
failed_files.append(name)
with lock:
- sys.stdout.write(" ".join(invocation) + "\n" + output.decode("utf-8"))
+ sys.stdout.write(output.decode("utf-8"))
if len(err) > 0:
sys.stdout.flush()
sys.stderr.write(err.decode("utf-8"))
@@ -552,6 +552,7 @@ def main() -> None:
args.warnings_as_errors,
)
invocation.append("-list-checks")
+ invocation.append("-header-filter=.*")
invocation.append("-")
if args.quiet:
# Even with -quiet we still want to check if we can call clang-tidy.