Added '@' and '$' functions(RNG and INT function)
dc / build (push) Successful in 13s
Details
dc / build (push) Successful in 13s
Details
This commit is contained in:
parent
0e15856762
commit
d0156fae3a
13
README.md
13
README.md
|
@ -26,6 +26,8 @@ Some of the supported features are:
|
|||
- Trigonometrical functions(`sin`, `cos`, `tan`, `asin`, `acos`, `atan`);
|
||||
- Base conversion(binary: `pb`, octal: `po`, hexadecimal: `px`);
|
||||
- Factorial and constants(`!`, `pi`, `e`);
|
||||
- Random number generator(`@`);
|
||||
- Integer conversion(`$`);
|
||||
- Stack operations:
|
||||
- Print top element(`p`, `P`);
|
||||
- Clear the stack(`c`);
|
||||
|
@ -246,6 +248,17 @@ lB -1 * lD + lA # POSITIVE DELTA
|
|||
[ X2: ] P R LS lS p
|
||||
```
|
||||
|
||||
16. Generate $n$ (pseudo)random numbers from user-defined range:
|
||||
```
|
||||
5 k
|
||||
[ lA lB @ p ] sR
|
||||
[ Enter number of samples: ] P ? sN
|
||||
[ Enter lower bound: ] P ? sA
|
||||
[ Enter upper bound: ] P ? sB
|
||||
[ lR x r 1 + d lN >=L ] sL
|
||||
0 lL x
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
[GPLv3](https://choosealicense.com/licenses/gpl-3.0/)
|
||||
|
|
32
man.md
32
man.md
|
@ -3,7 +3,7 @@ title: dc
|
|||
section: 1
|
||||
header: General Commands Manual
|
||||
footer: Marco Cetica
|
||||
date: March 13, 2024
|
||||
date: March 14, 2024
|
||||
---
|
||||
|
||||
|
||||
|
@ -102,7 +102,7 @@ the map's `key` and the associated value is represented by the map's `value`.
|
|||
By default each value of any kind of stack is represented by a string. Each operation is in charge to type convert the value before and after
|
||||
their invocation. The user can store both numeric and alphanumeric values on the stack. The latter using the _macro_ syntax(see below).
|
||||
|
||||
Arrays are homogeneous, thus the only supported data type is the `string`(the internal string type and not the **dc** one).
|
||||
Arrays are homogeneous data structures that implement the same data type of the stack, i.e. the string.
|
||||
|
||||
# COMMANDS
|
||||
Below, there is a list of supported **dc** commands.
|
||||
|
@ -121,7 +121,7 @@ Pops off the value on top of the stack, without altering the stack.
|
|||
|
||||
Prints the entire contents of the stack without altering anything.
|
||||
|
||||
## Arithmetic
|
||||
## Mathematics
|
||||
|
||||
**+**
|
||||
|
||||
|
@ -167,11 +167,20 @@ Pops one value, computes its factorial, and pushes that.
|
|||
|
||||
**pi**
|
||||
|
||||
Pushes pi approximation
|
||||
Pushes pi approximation.
|
||||
|
||||
**e**
|
||||
|
||||
Pushes e approximation
|
||||
Pushes e approximation.
|
||||
|
||||
**@**
|
||||
|
||||
Pops two values from the stack and generate a random number, using the first value popped as the upper bound and the second popped as the lower bound.
|
||||
The random value is generated using a 64-bit Mersenne Twister pseudorandom number generator and a real uniform distribution.
|
||||
|
||||
**$**
|
||||
|
||||
Pops one value from the stack and convert it to the nearest integer of lesser magnitute.
|
||||
|
||||
## Trigonometrical
|
||||
|
||||
|
@ -474,7 +483,7 @@ lB -1 * lD + lA # POSITIVE DELTA
|
|||
```
|
||||
|
||||
11. Load an external file:
|
||||
```sh
|
||||
```
|
||||
$> echo "[ p 1 + d lN >=L ] sL" > loop.dc
|
||||
$> cat prg.dc
|
||||
[ loop.dc ] ' # Load loop macro
|
||||
|
@ -483,6 +492,17 @@ $> cat prg.dc
|
|||
c 1 lL x # Clear the stack, add lower bound, load and execute macro
|
||||
```
|
||||
|
||||
12. Generate *n* (pseudo)random numbers from user-defined range:
|
||||
```
|
||||
5 k
|
||||
[ lA lB @ p ] sR
|
||||
[ Enter number of samples: ] P ? sN
|
||||
[ Enter lower bound: ] P ? sA
|
||||
[ Enter upper bound: ] P ? sB
|
||||
[ lR x r 1 + d lN >=L ] sL
|
||||
0 lL x
|
||||
```
|
||||
|
||||
# AUTHORS
|
||||
The original version of the **dc** command was written by Robert Morris and Lorinda Cherry.
|
||||
This version of **dc** is developed by Marco Cetica.
|
||||
|
|
|
@ -3,7 +3,7 @@ project(src)
|
|||
set(HEADER_FILES
|
||||
eval.h
|
||||
macro.h
|
||||
math.h
|
||||
mathematics.h
|
||||
operation.h
|
||||
stack.h
|
||||
adt.h
|
||||
|
@ -12,9 +12,9 @@ set(HEADER_FILES
|
|||
set(SOURCE_FILES
|
||||
eval.cpp
|
||||
macro.cpp
|
||||
math.cpp
|
||||
mathematics.cpp
|
||||
stack.cpp
|
||||
adt.cpp
|
||||
)
|
||||
|
||||
add_library(src STATIC ${SOURCE_FILES} ${HEADER_FILES})
|
||||
add_library(src STATIC ${SOURCE_FILES} ${HEADER_FILES})
|
||||
|
|
40
src/eval.cpp
40
src/eval.cpp
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include "adt.cpp"
|
||||
#include "eval.h"
|
||||
#include "math.h"
|
||||
#include "mathematics.h"
|
||||
#include "stack.h"
|
||||
#include "macro.h"
|
||||
#include "is_num.h"
|
||||
|
@ -22,24 +22,26 @@
|
|||
|
||||
void Evaluate::init_environment() {
|
||||
// Numerical operations
|
||||
this->op_factory.emplace("+", MAKE_UNIQUE_PTR(Math, OPType::ADD));
|
||||
this->op_factory.emplace("-", MAKE_UNIQUE_PTR(Math, OPType::SUB));
|
||||
this->op_factory.emplace("*", MAKE_UNIQUE_PTR(Math, OPType::MUL));
|
||||
this->op_factory.emplace("/", MAKE_UNIQUE_PTR(Math, OPType::DIV));
|
||||
this->op_factory.emplace("%", MAKE_UNIQUE_PTR(Math, OPType::MOD));
|
||||
this->op_factory.emplace("~", MAKE_UNIQUE_PTR(Math, OPType::DIV_MOD));
|
||||
this->op_factory.emplace("|", MAKE_UNIQUE_PTR(Math, OPType::MOD_EXP));
|
||||
this->op_factory.emplace("^", MAKE_UNIQUE_PTR(Math, OPType::EXP));
|
||||
this->op_factory.emplace("v", MAKE_UNIQUE_PTR(Math, OPType::SQRT));
|
||||
this->op_factory.emplace("sin", MAKE_UNIQUE_PTR(Math, OPType::SIN));
|
||||
this->op_factory.emplace("cos", MAKE_UNIQUE_PTR(Math, OPType::COS));
|
||||
this->op_factory.emplace("tan", MAKE_UNIQUE_PTR(Math, OPType::TAN));
|
||||
this->op_factory.emplace("asin", MAKE_UNIQUE_PTR(Math, OPType::ASIN));
|
||||
this->op_factory.emplace("acos", MAKE_UNIQUE_PTR(Math, OPType::ACOS));
|
||||
this->op_factory.emplace("atan", MAKE_UNIQUE_PTR(Math, OPType::ATAN));
|
||||
this->op_factory.emplace("!", MAKE_UNIQUE_PTR(Math, OPType::FACT));
|
||||
this->op_factory.emplace("pi", MAKE_UNIQUE_PTR(Math, OPType::PI));
|
||||
this->op_factory.emplace("e", MAKE_UNIQUE_PTR(Math, OPType::E));
|
||||
this->op_factory.emplace("+", MAKE_UNIQUE_PTR(Mathematics, OPType::ADD));
|
||||
this->op_factory.emplace("-", MAKE_UNIQUE_PTR(Mathematics, OPType::SUB));
|
||||
this->op_factory.emplace("*", MAKE_UNIQUE_PTR(Mathematics, OPType::MUL));
|
||||
this->op_factory.emplace("/", MAKE_UNIQUE_PTR(Mathematics, OPType::DIV));
|
||||
this->op_factory.emplace("%", MAKE_UNIQUE_PTR(Mathematics, OPType::MOD));
|
||||
this->op_factory.emplace("~", MAKE_UNIQUE_PTR(Mathematics, OPType::DIV_MOD));
|
||||
this->op_factory.emplace("|", MAKE_UNIQUE_PTR(Mathematics, OPType::MOD_EXP));
|
||||
this->op_factory.emplace("^", MAKE_UNIQUE_PTR(Mathematics, OPType::EXP));
|
||||
this->op_factory.emplace("v", MAKE_UNIQUE_PTR(Mathematics, OPType::SQRT));
|
||||
this->op_factory.emplace("sin", MAKE_UNIQUE_PTR(Mathematics, OPType::SIN));
|
||||
this->op_factory.emplace("cos", MAKE_UNIQUE_PTR(Mathematics, OPType::COS));
|
||||
this->op_factory.emplace("tan", MAKE_UNIQUE_PTR(Mathematics, OPType::TAN));
|
||||
this->op_factory.emplace("asin", MAKE_UNIQUE_PTR(Mathematics, OPType::ASIN));
|
||||
this->op_factory.emplace("acos", MAKE_UNIQUE_PTR(Mathematics, OPType::ACOS));
|
||||
this->op_factory.emplace("atan", MAKE_UNIQUE_PTR(Mathematics, OPType::ATAN));
|
||||
this->op_factory.emplace("!", MAKE_UNIQUE_PTR(Mathematics, OPType::FACT));
|
||||
this->op_factory.emplace("pi", MAKE_UNIQUE_PTR(Mathematics, OPType::PI));
|
||||
this->op_factory.emplace("e", MAKE_UNIQUE_PTR(Mathematics, OPType::E));
|
||||
this->op_factory.emplace("@", MAKE_UNIQUE_PTR(Mathematics, OPType::RND));
|
||||
this->op_factory.emplace("$", MAKE_UNIQUE_PTR(Mathematics, OPType::INT));
|
||||
// Stack operations
|
||||
this->op_factory.emplace("p", MAKE_UNIQUE_PTR(Stack, OPType::PCG));
|
||||
this->op_factory.emplace("pb", MAKE_UNIQUE_PTR(Stack, OPType::PBB));
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
#include <cmath>
|
||||
#include <numbers>
|
||||
#include <iomanip>
|
||||
#include <random>
|
||||
|
||||
#include "adt.cpp"
|
||||
#include "math.h"
|
||||
#include "mathematics.h"
|
||||
#include "is_num.h"
|
||||
|
||||
std::optional<std::string> Math::exec(dc::Stack<std::string> &stack, dc::Parameters ¶meters, __attribute__((unused)) std::unordered_map<char, dc::Register> ®s) {
|
||||
std::optional<std::string> Mathematics::exec(dc::Stack<std::string> &stack, dc::Parameters ¶meters, __attribute__((unused)) std::unordered_map<char, dc::Register> ®s) {
|
||||
std::optional<std::string> err = std::nullopt;
|
||||
|
||||
switch(this->op_type) {
|
||||
|
@ -28,13 +29,15 @@ std::optional<std::string> Math::exec(dc::Stack<std::string> &stack, dc::Paramet
|
|||
case OPType::FACT: err = fn_fact(stack, parameters); break;
|
||||
case OPType::PI: err = fn_pi(stack, parameters); break;
|
||||
case OPType::E: err = fn_e(stack, parameters); break;
|
||||
case OPType::RND: err = fn_random(stack, parameters); break;
|
||||
case OPType::INT: err = fn_integer(stack, parameters); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_add(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
std::optional<std::string> Mathematics::fn_add(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
// Check if stack has enough elements
|
||||
if(stack.size() < 2) {
|
||||
return "'+' requires two operands";
|
||||
|
@ -62,7 +65,7 @@ std::optional<std::string> Math::fn_add(dc::Stack<std::string> &stack, const dc:
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_sub(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
std::optional<std::string> Mathematics::fn_sub(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
// Check if stack has enough elements
|
||||
if(stack.size() < 2) {
|
||||
return "'-' requires two operands";
|
||||
|
@ -100,7 +103,7 @@ std::optional<std::string> Math::fn_sub(dc::Stack<std::string> &stack, const dc:
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_mul(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
std::optional<std::string> Mathematics::fn_mul(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
// Check if stack has enough elements
|
||||
if(stack.size() < 2) {
|
||||
return "'*' requires two operands";
|
||||
|
@ -128,7 +131,7 @@ std::optional<std::string> Math::fn_mul(dc::Stack<std::string> &stack, const dc:
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_div(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
std::optional<std::string> Mathematics::fn_div(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
// Check if stack has enough elements
|
||||
if(stack.size() < 2) {
|
||||
return "'/' requires two operands";
|
||||
|
@ -161,7 +164,7 @@ std::optional<std::string> Math::fn_div(dc::Stack<std::string> &stack, const dc:
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_mod(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
std::optional<std::string> Mathematics::fn_mod(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
// Check if stack has enough elements
|
||||
if(stack.size() < 2) {
|
||||
return "'%' requires two operands";
|
||||
|
@ -194,7 +197,7 @@ std::optional<std::string> Math::fn_mod(dc::Stack<std::string> &stack, const dc:
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_div_mod(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
std::optional<std::string> Mathematics::fn_div_mod(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
// Check if stack has enough elements
|
||||
if(stack.size() < 2) {
|
||||
return "'~' requires two operands";
|
||||
|
@ -229,7 +232,7 @@ std::optional<std::string> Math::fn_div_mod(dc::Stack<std::string> &stack, const
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_mod_exp(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
std::optional<std::string> Mathematics::fn_mod_exp(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
// Check if stack has enough elements
|
||||
if(stack.size() < 3) {
|
||||
return "'|' requires three operands";
|
||||
|
@ -278,7 +281,7 @@ std::optional<std::string> Math::fn_mod_exp(dc::Stack<std::string> &stack, const
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_exp(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
std::optional<std::string> Mathematics::fn_exp(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
// Check if stack has enough elements
|
||||
if(stack.size() < 2) {
|
||||
return "'^' requires two operands";
|
||||
|
@ -306,7 +309,7 @@ std::optional<std::string> Math::fn_exp(dc::Stack<std::string> &stack, const dc:
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_sqrt(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
std::optional<std::string> Mathematics::fn_sqrt(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
// Check if stack has enough elements
|
||||
if(stack.empty()) {
|
||||
return "'v' requires one operand";
|
||||
|
@ -335,7 +338,7 @@ std::optional<std::string> Math::fn_sqrt(dc::Stack<std::string> &stack, const dc
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_sin(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
std::optional<std::string> Mathematics::fn_sin(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
// Check if stack has enough elements
|
||||
if(stack.empty()) {
|
||||
return "'sin' requires one operand";
|
||||
|
@ -360,7 +363,7 @@ std::optional<std::string> Math::fn_sin(dc::Stack<std::string> &stack, const dc:
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_cos(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
std::optional<std::string> Mathematics::fn_cos(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
// Check if stack has enough elements
|
||||
if(stack.empty()) {
|
||||
return "'cos' requires one operand";
|
||||
|
@ -385,7 +388,7 @@ std::optional<std::string> Math::fn_cos(dc::Stack<std::string> &stack, const dc:
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_tan(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
std::optional<std::string> Mathematics::fn_tan(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
// Check if stack has enough elements
|
||||
if(stack.empty()) {
|
||||
return "'tan' requires one operand";
|
||||
|
@ -410,7 +413,7 @@ std::optional<std::string> Math::fn_tan(dc::Stack<std::string> &stack, const dc:
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_asin(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
std::optional<std::string> Mathematics::fn_asin(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
// Check if stack has enough elements
|
||||
if(stack.empty()) {
|
||||
return "'asin' requires one operand";
|
||||
|
@ -435,7 +438,7 @@ std::optional<std::string> Math::fn_asin(dc::Stack<std::string> &stack, const dc
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_acos(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
std::optional<std::string> Mathematics::fn_acos(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
// Check if stack has enough elements
|
||||
if(stack.empty()) {
|
||||
return "'acos' requires one operand";
|
||||
|
@ -460,7 +463,7 @@ std::optional<std::string> Math::fn_acos(dc::Stack<std::string> &stack, const dc
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_atan(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
std::optional<std::string> Mathematics::fn_atan(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
// Check if stack has enough elements
|
||||
if(stack.empty()) {
|
||||
return "'atan' requires one operand";
|
||||
|
@ -485,7 +488,7 @@ std::optional<std::string> Math::fn_atan(dc::Stack<std::string> &stack, const dc
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_fact(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
std::optional<std::string> Mathematics::fn_fact(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
// Check if stack has enough elements
|
||||
if(stack.empty()) {
|
||||
return "'!' requires one operand";
|
||||
|
@ -519,19 +522,75 @@ std::optional<std::string> Math::fn_fact(dc::Stack<std::string> &stack, const dc
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_pi(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
std::optional<std::string> Mathematics::fn_pi(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
stack.push(trim_digits(std::numbers::pi, parameters.precision));
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_e(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
std::optional<std::string> Mathematics::fn_e(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
stack.push(trim_digits(std::numbers::e, parameters.precision));
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::string Math::trim_digits(double number, unsigned int precision) {
|
||||
std::optional<std::string> Mathematics::fn_random(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
// Check if stack has enough elements
|
||||
if(stack.size() < 2) {
|
||||
return "'@' requires two operands";
|
||||
}
|
||||
|
||||
// Extract two entries from the stack
|
||||
auto len = stack.size() - 1;
|
||||
auto b = stack[len];
|
||||
auto a = stack[len-1];
|
||||
auto is_a_num = is_num<double>(a);
|
||||
auto is_b_num = is_num<double>(b);
|
||||
|
||||
// Check whether both entries are numbers
|
||||
if(is_a_num && is_b_num) {
|
||||
stack.copy_xyz();
|
||||
auto u_bound = std::stod(stack.pop(true));
|
||||
auto l_bound = std::stod(stack.pop(true));
|
||||
|
||||
// Initialize random distribution with user bounds( [a, b] )
|
||||
std::random_device r_dev;
|
||||
std::mt19937_64 rng(r_dev());
|
||||
std::uniform_real_distribution<double> u_dist(l_bound, u_bound);
|
||||
auto r_number = u_dist(rng);
|
||||
|
||||
// Push the random value onto the stack
|
||||
stack.push(trim_digits(r_number, parameters.precision));
|
||||
} else {
|
||||
return "'@' requires numeric values";
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Mathematics::fn_integer(dc::Stack<std::string> &stack, const dc::Parameters ¶meters) {
|
||||
// Check if stack has enough elements
|
||||
if(stack.empty()) {
|
||||
return "'$' requires one operand";
|
||||
}
|
||||
|
||||
auto head = stack.pop(false);
|
||||
auto is_head_num = is_num<double>(head);
|
||||
|
||||
// Check whether head of the stack is a number
|
||||
if(is_head_num) {
|
||||
stack.copy_xyz();
|
||||
// Convert to integral type to truncate
|
||||
auto value = std::stol(stack.pop(true));
|
||||
// Push the truncated number back to the stack
|
||||
stack.push(trim_digits(static_cast<double>(value), parameters.precision));
|
||||
} else {
|
||||
return "'$' requires numeric values";
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
std::string Mathematics::trim_digits(double number, unsigned int precision) {
|
||||
std::ostringstream oss;
|
||||
|
||||
// Preserve non-zero decimal numbers even when precision is zero
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
#include "operation.h"
|
||||
|
||||
class Math : public IOperation {
|
||||
class Mathematics : public IOperation {
|
||||
public:
|
||||
explicit Math(const OPType op_t) : op_type(op_t) {}
|
||||
explicit Mathematics(const OPType op_t) : op_type(op_t) {}
|
||||
std::optional<std::string> exec(dc::Stack<std::string> &stack, dc::Parameters ¶meters, std::unordered_map<char, dc::Register> ®s) override;
|
||||
|
||||
private:
|
||||
|
@ -26,6 +26,8 @@ private:
|
|||
static std::optional<std::string> fn_fact(dc::Stack<std::string> &stack, const dc::Parameters ¶meters);
|
||||
static std::optional<std::string> fn_pi(dc::Stack<std::string> &stack, const dc::Parameters ¶meters);
|
||||
static std::optional<std::string> fn_e(dc::Stack<std::string> &stack, const dc::Parameters ¶meters);
|
||||
static std::optional<std::string> fn_random(dc::Stack<std::string> &stack, const dc::Parameters ¶meters);
|
||||
static std::optional<std::string> fn_integer(dc::Stack<std::string> &stack, const dc::Parameters ¶meters);
|
||||
static std::string trim_digits(double number, unsigned int precision);
|
||||
|
||||
OPType op_type;
|
|
@ -12,7 +12,8 @@ public:
|
|||
enum class OPType {
|
||||
// Numerical operations
|
||||
ADD, SUB, MUL, DIV, MOD, DIV_MOD, MOD_EXP, EXP,
|
||||
SQRT, SIN, COS, TAN, ASIN, ACOS, ATAN, FACT, PI, E,
|
||||
SQRT, SIN, COS, TAN, ASIN, ACOS, ATAN, FACT, PI,
|
||||
E, RND, INT,
|
||||
// Stack operations
|
||||
PCG, P, PBB, PBH, PBO, CLR, PH, SO, DP, PS, CH, CS,
|
||||
SP, GP, SOR, GOR, SIR, GIR, LX, LY, LZ,
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/sh
|
||||
|
||||
utest() {
|
||||
PROGRAM="$PWD/build/dc"
|
||||
EXPECTED="3"
|
||||
ACTUAL=$("$PROGRAM" -e 'pi $ p')
|
||||
assert_eq "$EXPECTED" "$ACTUAL"
|
||||
|
||||
# Test empty stack
|
||||
EXPECTED="'$' requires one operand"
|
||||
ACTUAL=$("$PROGRAM" -e '$' 2>&1) || true
|
||||
assert_eq "$EXPECTED" "$ACTUAL"
|
||||
|
||||
# Test non numerical values
|
||||
EXPECTED="'$' requires numeric values"
|
||||
ACTUAL=$("$PROGRAM" -e '[ foo ] $' 2>&1) || true
|
||||
assert_eq "$EXPECTED" "$ACTUAL"
|
||||
}
|
||||
# vim: ts=4 sw=4 softtabstop=4 expandtab:
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/sh
|
||||
|
||||
utest() {
|
||||
PROGRAM="$PWD/build/dc"
|
||||
ACTUAL=$("$PROGRAM" -e '-10 10 @ $ p')
|
||||
assert_ge "$ACTUAL" "-10"
|
||||
assert_le "$ACTUAL" "10"
|
||||
|
||||
# Test empty stack
|
||||
EXPECTED="'@' requires two operands"
|
||||
ACTUAL=$("$PROGRAM" -e '@' 2>&1) || true
|
||||
assert_eq "$EXPECTED" "$ACTUAL"
|
||||
|
||||
# Test non numerical values
|
||||
EXPECTED="'@' requires numeric values"
|
||||
ACTUAL=$("$PROGRAM" -e '[ foo ] 5 @' 2>&1) || true
|
||||
assert_eq "$EXPECTED" "$ACTUAL"
|
||||
}
|
||||
# vim: ts=4 sw=4 softtabstop=4 expandtab:
|
Loading…
Reference in New Issue