calc
This commit is contained in:
commit
9d90fa79b0
|
@ -0,0 +1,65 @@
|
|||
CXX=g++
|
||||
LD=g++
|
||||
CXXFLAGS=-Wall -pedantic -Wextra -g
|
||||
DBGFLAGS=-g
|
||||
SRC_DIR=src/code/
|
||||
BUILD_DIR=build/
|
||||
TARGET=hladuond
|
||||
SRC = $(wildcard src/code/*.cpp)
|
||||
OBJ = $(SRC:src/code/%.cpp=build/%.o)
|
||||
|
||||
.PHONY: all
|
||||
all: compile doc
|
||||
|
||||
.PHONY: run
|
||||
run: hladuond
|
||||
./hladuond
|
||||
|
||||
doc: doc/html
|
||||
doc/html:
|
||||
doxygen Doxyfile
|
||||
cp ./doc/html/index.html ./doc/index.html
|
||||
|
||||
compile:
|
||||
mkdir -p $(BUILD_DIR)
|
||||
$(MAKE) -j8 hladuond
|
||||
|
||||
test:
|
||||
mkdir -p $(BUILD_DIR)
|
||||
$(MAKE) -j8 examples/test
|
||||
|
||||
examples/test: build/test.o $(filter-out $(BUILD_DIR)main.o, $(OBJ))
|
||||
$(LD) $(CXXFLAGS) -o $@ $^
|
||||
|
||||
# link
|
||||
$(TARGET): $(OBJ)
|
||||
$(LD) $(CXXFLAGS) -o $@ $^
|
||||
|
||||
# compile
|
||||
$(BUILD_DIR)%.o: $(SRC_DIR)%.cpp
|
||||
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
build/test.o: examples/test.cpp
|
||||
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf hladuond
|
||||
rm -f hladuond.zip
|
||||
rm -rf ./build
|
||||
rm -rf ./doc/html ./doc/index.html
|
||||
rm -f Makefile.d
|
||||
rm -f ./examples/test
|
||||
|
||||
progtest: clean
|
||||
mkdir hladuond
|
||||
cp -r src hladuond/src
|
||||
cp -r doc hladuond/doc
|
||||
cp -r examples hladuond/examples
|
||||
cp README.md hladuond/README.md
|
||||
cp prohlaseni.txt hladuond/prohlaseni.txt
|
||||
cp zadani.txt hladuond/zadani.txt
|
||||
cp Doxyfile hladuond/Doxyfile
|
||||
cp Makefile hladuond/Makefile
|
||||
zip -r hladuond.zip hladuond/
|
||||
rm -rf hladuond
|
|
@ -0,0 +1,49 @@
|
|||
#Kalkulačka racionálních čísel
|
||||
|
||||
Interaktivní terminálová kalkulačka
|
||||
|
||||
##Struktura programu:
|
||||
Instance třídy CParser zpracovává algebraické výrazy v LL1 gramatice
|
||||
(viz. doc/dor/grammar.dot)
|
||||
Pamatuje si proměnné a řídí dodaný saver.
|
||||
|
||||
Ze zadaných výrazů složí strom na jehož vrchol zavolá rekurzivní eval()
|
||||
|
||||
Abstraktní třída CPrintable zastřešuje veškeré výstupy z parseru,
|
||||
tedy čísla a operace. Její potomci imlepentují metodu eval() kterou
|
||||
se rekurzivně vyhodnotí celý strom operací. Polymorfismus zajištěje
|
||||
že operandy můžou být jak čísla tak jiné operace.
|
||||
|
||||
Kalkulačcka implementuje exaktní operace pro racionální čísla,
|
||||
celočíselné modulo, a proximaxi logaritmů a exponenciel.
|
||||
|
||||
+-------------------------+ +---------------------------+
|
||||
| CPrintable *abstract* | | CParser |
|
||||
|-input from parser | | parses input into |
|
||||
|-output to UI |--+ | tree of CPrintables |
|
||||
| SPrintableValue *eval() | | | |
|
||||
+-------------------------+ | +---------------------------+
|
||||
|
|
||||
|
|
||||
|
|
||||
+-------------------------+ | +---------------------------+
|
||||
| COperator *abstarct* |<-+->| CRational |
|
||||
| CPrintable *operandB | | CBigInt *deniminator |
|
||||
| CPrintable *operandA | | CBigInt *numerator |
|
||||
| | | |
|
||||
+-------------------------+ +---------------------------+
|
||||
|
|
||||
| +-----------+ +---------------------------+
|
||||
+-->| CAdittion | | CBigInt |
|
||||
| +-----------+ | CBigInt *add( CBigint *) |
|
||||
| | CBigInt *sub( CBigint *) |
|
||||
| +----------------+ | CBigInt *mul( CBigint *) |
|
||||
+-->| CMultipication | +---------------------------+
|
||||
| +----------------+
|
||||
|
|
||||
| +------------+
|
||||
+-->| CFactorial |
|
||||
| +------------+
|
||||
.
|
||||
.
|
||||
.
|
|
@ -0,0 +1,47 @@
|
|||
digraph UML_Class_diagram {
|
||||
graph [
|
||||
label="Class diagram"
|
||||
labelloc="t"
|
||||
fontname="Helvetica,Arial,sans-serif"
|
||||
rankdir=LR
|
||||
splines=ortho
|
||||
]
|
||||
node [
|
||||
fontname="Helvetica,Arial,sans-serif"
|
||||
shape=record
|
||||
style=filled
|
||||
fillcolor=gray95
|
||||
|
||||
]
|
||||
edge [
|
||||
|
||||
]
|
||||
CPrintable [label=<{ <b>CPrintable</b> } | { virtual std::stringtoString() } | { virtual CRational *evaluate() }>]
|
||||
COperator [label=<{ <b>COperator</b> } | { controls CRational }>]
|
||||
CRational [label=<{ <b>CRational</b> } | { controls CBigInt }>]
|
||||
|
||||
|
||||
COperator -> CPrintable
|
||||
CRational -> CPrintable
|
||||
|
||||
|
||||
subgraph cluster_0 {
|
||||
style=filled
|
||||
color=lightgrey
|
||||
node [style=filled,color=gray95,width=1.5]
|
||||
edge []
|
||||
|
||||
|
||||
CAdittion -> COperator
|
||||
CSubtraction -> COperator
|
||||
CMultiplication -> COperator
|
||||
CDivision -> COperator
|
||||
CLogarithm -> COperator
|
||||
CExponencial -> COperator
|
||||
CModulo -> COperator
|
||||
label = "Operators";
|
||||
}
|
||||
|
||||
CTextsaver->CSaver
|
||||
CBinsaver->CSaver
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
digraph UML_Class_diagram {
|
||||
// rankdir=LR
|
||||
b->a
|
||||
c->b
|
||||
c->a
|
||||
d->c
|
||||
d->b
|
||||
d->a
|
||||
e->a
|
||||
e->b
|
||||
e->c
|
||||
e->d
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
digraph Grammar_diagram {
|
||||
graph [
|
||||
label="Grammar diagram"
|
||||
labelloc="t"
|
||||
fontname="Helvetica,Arial,sans-serif"
|
||||
// rankdir=LR
|
||||
// splines=ortho
|
||||
]
|
||||
node [
|
||||
fontname="Helvetica,Arial,sans-serif"
|
||||
// shape=record
|
||||
style=filled
|
||||
fillcolor=gray95
|
||||
|
||||
]
|
||||
edge [
|
||||
|
||||
]
|
||||
START -> OPEN_BRACKET
|
||||
|
||||
SIGN_PREFIX //[label="SIGN_PREFIX (unary operator)"]
|
||||
SIGN_PREFIX -> NUMBER
|
||||
|
||||
OPEN_BRACKET -> NUMBER
|
||||
OPEN_BRACKET -> OPEN_BRACKET
|
||||
OPEN_BRACKET -> SIGN_PREFIX
|
||||
|
||||
NUMBER -> BINARY_OPERATOR
|
||||
BINARY_OPERATOR -> NUMBER
|
||||
BINARY_OPERATOR -> OPEN_BRACKET
|
||||
|
||||
NUMBER -> CLOSE_BRACKET
|
||||
CLOSE_BRACKET -> CLOSE_BRACKET
|
||||
CLOSE_BRACKET -> BINARY_OPERATOR
|
||||
CLOSE_BRACKET -> END
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
digraph parser_FSM_diagram {
|
||||
graph [
|
||||
label="parser FSM diagram"
|
||||
labelloc="t"
|
||||
fontname="Helvetica,Arial,sans-serif"
|
||||
rankdir=BT
|
||||
]
|
||||
node [
|
||||
fontname="Helvetica,Arial,sans-serif"
|
||||
// shape=record
|
||||
style=filled
|
||||
fillcolor=gray95
|
||||
|
||||
]
|
||||
edge [
|
||||
|
||||
]
|
||||
NUM //[label=<{ NUM } | { 1 - 9 } >]
|
||||
START -> NUM
|
||||
NUM -> NUM
|
||||
NUM -> DOT
|
||||
DOT -> NUM
|
||||
|
||||
Operator //[label=<{ Operator } | { ! $ + - / * ( ) ^ % = }>]
|
||||
NUM -> Operator
|
||||
Operator -> NUM
|
||||
Operator -> Label
|
||||
Operator -> END
|
||||
START -> Label
|
||||
START -> END
|
||||
Label -> Operator
|
||||
Label -> END
|
||||
NUM -> END
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
digraph UML_Class_diagram {
|
||||
graph [
|
||||
label="UML Class diagram demo"
|
||||
labelloc="t"
|
||||
fontname="Helvetica,Arial,sans-serif"
|
||||
]
|
||||
node [
|
||||
fontname="Helvetica,Arial,sans-serif"
|
||||
shape=record
|
||||
style=filled
|
||||
fillcolor=gray95
|
||||
]
|
||||
edge [fontname="Helvetica,Arial,sans-serif"]
|
||||
edge [arrowhead=vee style=dashed]
|
||||
Client -> Interface1 [label=dependency]
|
||||
Client -> Interface2
|
||||
|
||||
edge [dir=back arrowtail=empty style=""]
|
||||
Interface1 -> Class1 [xlabel=inheritance]
|
||||
Interface2 -> Class1 [dir=none]
|
||||
Interface2 [label="" xlabel="Simple\ninterface" shape=circle]
|
||||
|
||||
Interface1[label = <{<b>«interface» I/O</b> | + property<br align="left"/>...<br align="left"/>|+ method<br align="left"/>...<br align="left"/>}>]
|
||||
Class1[label = <{<b>I/O class</b> | + property<br align="left"/>...<br align="left"/>|+ method<br align="left"/>...<br align="left"/>}>]
|
||||
edge [dir=back arrowtail=empty style=dashed]
|
||||
Class1 -> System_1 [label=implementation]
|
||||
System_1 [
|
||||
shape=plain
|
||||
label=<<table border="0" cellborder="1" cellspacing="0" cellpadding="4">
|
||||
<tr> <td> <b>System</b> </td> </tr>
|
||||
<tr> <td>
|
||||
<table border="0" cellborder="0" cellspacing="0" >
|
||||
<tr> <td align="left" >+ property</td> </tr>
|
||||
<tr> <td port="ss1" align="left" >- Subsystem 1</td> </tr>
|
||||
<tr> <td port="ss2" align="left" >- Subsystem 2</td> </tr>
|
||||
<tr> <td port="ss3" align="left" >- Subsystem 3</td> </tr>
|
||||
<tr> <td align="left">...</td> </tr>
|
||||
</table>
|
||||
</td> </tr>
|
||||
<tr> <td align="left">+ method<br/>...<br align="left"/></td> </tr>
|
||||
</table>>
|
||||
]
|
||||
|
||||
edge [dir=back arrowtail=diamond]
|
||||
System_1:ss1 -> Subsystem_1 [xlabel="composition"]
|
||||
|
||||
Subsystem_1 [
|
||||
shape=plain
|
||||
label=<<table border="0" cellborder="1" cellspacing="0" cellpadding="4">
|
||||
<tr> <td> <b>Subsystem 1</b> </td> </tr>
|
||||
<tr> <td>
|
||||
<table border="0" cellborder="0" cellspacing="0" >
|
||||
<tr> <td align="left">+ property</td> </tr>
|
||||
<tr> <td align="left" port="r1">- resource</td> </tr>
|
||||
<tr> <td align="left">...</td> </tr>
|
||||
</table>
|
||||
</td> </tr>
|
||||
<tr> <td align="left">
|
||||
+ method<br/>
|
||||
...<br align="left"/>
|
||||
</td> </tr>
|
||||
</table>>
|
||||
]
|
||||
Subsystem_2 [
|
||||
shape=plain
|
||||
label=<<table border="0" cellborder="1" cellspacing="0" cellpadding="4">
|
||||
<tr> <td> <b>Subsystem 2</b> </td> </tr>
|
||||
<tr> <td>
|
||||
<table align="left" border="0" cellborder="0" cellspacing="0" >
|
||||
<tr> <td align="left">+ property</td> </tr>
|
||||
<tr> <td align="left" port="r1">- resource</td> </tr>
|
||||
<tr> <td align="left">...</td> </tr>
|
||||
</table>
|
||||
</td> </tr>
|
||||
<tr> <td align="left">
|
||||
+ method<br/>
|
||||
...<br align="left"/>
|
||||
</td> </tr>
|
||||
</table>>
|
||||
]
|
||||
Subsystem_3 [
|
||||
shape=plain
|
||||
label=<<table border="0" cellborder="1" cellspacing="0" cellpadding="4">
|
||||
<tr> <td> <b>Subsystem 3</b> </td> </tr>
|
||||
<tr> <td>
|
||||
<table border="0" cellborder="0" cellspacing="0" >
|
||||
<tr> <td align="left">+ property</td> </tr>
|
||||
<tr> <td align="left" port="r1">- resource</td> </tr>
|
||||
<tr> <td align="left">...</td> </tr>
|
||||
</table>
|
||||
</td> </tr>
|
||||
<tr> <td align="left">
|
||||
+ method<br/>
|
||||
...<br align="left"/>
|
||||
</td> </tr>
|
||||
</table>>
|
||||
]
|
||||
System_1:ss2 -> Subsystem_2;
|
||||
System_1:ss3 -> Subsystem_3;
|
||||
|
||||
edge [xdir=back arrowtail=odiamond]
|
||||
Subsystem_1:r1 -> "Shared resource" [label=aggregation]
|
||||
Subsystem_2:r1 -> "Shared resource"
|
||||
Subsystem_3:r1 -> "Shared resource"
|
||||
"Shared resource" [
|
||||
label = <{
|
||||
<b>Shared resource</b>
|
||||
|
|
||||
+ property<br align="left"/>
|
||||
...<br align="left"/>
|
||||
|
|
||||
+ method<br align="left"/>
|
||||
...<br align="left"/>
|
||||
}>
|
||||
]
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
#include "../src/code/rational.cpp"
|
||||
#include <assert.h>
|
||||
|
||||
int main( void ) {
|
||||
{
|
||||
// CBigInt a(3), b(5);
|
||||
// auto c = b.lcm(&a);
|
||||
// delete c;
|
||||
// delete c;
|
||||
// CBigInt *c = a.add(&b);
|
||||
// assert( CBigInt(1111111110).cmp(c) == 0);
|
||||
// delete c;
|
||||
|
||||
// c = a.sub(&b);
|
||||
// assert( CBigInt(-864197532).cmp(c) == 0);
|
||||
// delete c;
|
||||
}
|
||||
// {
|
||||
// CBigInt a(123456789), b(987654321);
|
||||
// auto c = b.divmod(&a);
|
||||
// assert( CBigInt(8).cmp(c.first) == 0 );
|
||||
// assert( CBigInt(9).cmp(c.second) == 0 );
|
||||
// delete c.first;
|
||||
// delete c.second;
|
||||
// }
|
||||
|
||||
// //! leak
|
||||
// {
|
||||
// CRational a( new CBigInt(1), new CBigInt(6) );
|
||||
// CRational b( new CBigInt(2), new CBigInt(6) );
|
||||
// CRational d( new CBigInt(11),new CBigInt(15) );
|
||||
// a.setSameDenominator(&b);
|
||||
// CRational *c = a.add(&b);
|
||||
// c->simplify();
|
||||
// // assert( d.toString() == c->toString());
|
||||
// delete c;
|
||||
// }
|
||||
// {
|
||||
// CRational a( new CBigInt(123), new CBigInt(456) );
|
||||
// CRational b( new CBigInt(789), new CBigInt(123) );
|
||||
// CRational d( new CBigInt(41657),new CBigInt(6232) );
|
||||
// CRational *c = a.add(&b);
|
||||
// c->simplify();
|
||||
// // assert( d.toString() == c->toString());
|
||||
// delete c;
|
||||
// }
|
||||
|
||||
// //! leak
|
||||
// {
|
||||
// CRational a( new CBigInt(1), new CBigInt(3) );
|
||||
// CRational b( new CBigInt(2), new CBigInt(5) );
|
||||
// CRational d( new CBigInt(2),new CBigInt(15) );
|
||||
// CRational *c = a.mul(&b);
|
||||
// c->simplify();
|
||||
// // assert( d.toString() == c->toString());
|
||||
// delete c;
|
||||
// }
|
||||
// {
|
||||
// CBigInt a(12), b(-4);
|
||||
// CBigInt *c = a.div(&b);
|
||||
// // c->debugPrint();
|
||||
// delete c;
|
||||
// }
|
||||
// {
|
||||
// CRational a( new CBigInt(-1), new CBigInt(3) );
|
||||
// CRational b( new CBigInt(-1), new CBigInt(2) );
|
||||
// CRational *c = a.div(&b);
|
||||
// c->simplify();
|
||||
// auto str = c->toString();
|
||||
// // std::cout << str << '\n';
|
||||
// delete c;
|
||||
// }
|
||||
{
|
||||
CRational a( new CBigInt(3), new CBigInt(7));
|
||||
CRational *c = a.exp();
|
||||
auto str = c->toString();
|
||||
std::cout << c->debugDump() << '\n';
|
||||
delete c;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
#include "../src/include/parser.hpp"
|
||||
#include <assert.h>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
{
|
||||
std::cout << "running testset 1\n";
|
||||
CParser a;
|
||||
|
||||
a.convert("123456789 + 987654321");
|
||||
assert( a.m_output == "1111111110" );
|
||||
|
||||
a.convert("(12/50 + 1/8)/4 + 2/7");
|
||||
assert( a.m_output == "2111 / 5600" );
|
||||
|
||||
a.convert("velkeCislo=100000000000000000000000000000000000000000000");
|
||||
assert( a.m_output == "100000000000000000000000000000000000000000000");
|
||||
|
||||
a.convert("$velkeCislo*$velkeCislo");
|
||||
assert( a.m_output == "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" );
|
||||
|
||||
a.convert("$ans / $velkeCislo");
|
||||
assert( a.m_output == "100000000000000000000000000000000000000000000" );
|
||||
|
||||
a.convert("!save sav");
|
||||
CParser b;
|
||||
b.convert("!load sav");
|
||||
b.convert("$velkeCislo");
|
||||
assert( b.m_output == "100000000000000000000000000000000000000000000" );
|
||||
|
||||
std::filesystem::path pth = std::filesystem::current_path();
|
||||
std::filesystem::remove( pth / "sav" );
|
||||
b.convert("!load sav");
|
||||
assert( b.m_output == "load failed" );
|
||||
|
||||
b.convert("1 )+ 2");
|
||||
assert( b.m_output == "bad parenthesis parity" );
|
||||
|
||||
b.convert("1 + ()");
|
||||
assert( b.m_output == "Caught exception: parsing failed" );
|
||||
|
||||
b.convert(".3");
|
||||
assert( b.m_output == "3 / 10" );
|
||||
|
||||
b.convert( "(.1 + 9.9) % (3 * 2)" );
|
||||
assert( b.m_output == "4" );
|
||||
}
|
||||
|
||||
{
|
||||
std::cout << "running testset 2\n";
|
||||
CParser a;
|
||||
// Test case 1: Complex arithmetic expression
|
||||
a.convert("((3.14 + 2) * 5 - 8) / 2");
|
||||
assert(a.m_output == "177 / 20");
|
||||
|
||||
// Test case 2: Division by zero
|
||||
a.convert("1 / 0");
|
||||
assert(a.m_output == "Caught exception: division by zero");
|
||||
|
||||
// Test case 3: Mixed fraction and decimal calculations
|
||||
a.convert("(1/4 + 0.75) * 2");
|
||||
assert(a.m_output == "2");
|
||||
|
||||
// Test case 4: Negative numbers and subtraction
|
||||
a.convert("-5 + 7 - (-2) * (-3)");
|
||||
assert(a.m_output == "-4");
|
||||
|
||||
// Test case 5: Exponentiation
|
||||
a.convert("(2/1) ^ 16");
|
||||
assert(a.m_output == "65536");
|
||||
|
||||
// Test case 6: Order of operations
|
||||
a.convert("2 * 3 + 4 / 2 - 1");
|
||||
assert(a.m_output == "7");
|
||||
|
||||
// Test case 7: Large numbers
|
||||
a.convert("1234567890 + 9876543210");
|
||||
assert(a.m_output == "11111111100");
|
||||
|
||||
// Test case 8: Error handling for invalid input
|
||||
a.convert("1 + 2 *");
|
||||
assert(a.m_output == "Caught exception: parsing failed");
|
||||
|
||||
// Test case 9: Variable assignment and retrieval
|
||||
a.convert("x = 5");
|
||||
assert(a.m_output == "5");
|
||||
a.convert("$x + 3");
|
||||
assert(a.m_output == "8");
|
||||
}
|
||||
std::cout << "all tests successful!" << std::endl;
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#include "../include/rational.hpp"
|
||||
#include "../include/addition.hpp"
|
||||
|
||||
CAddition::CAddition( CPrintable *a, CPrintable *b ) : COperator(a, b) {}
|
||||
CRational *CAddition::evaluate() {
|
||||
std::unique_ptr<CRational> a (m_firstArgument->evaluate());
|
||||
std::unique_ptr<CRational> b (m_secondArgument->evaluate());
|
||||
return a->add(b.get());
|
||||
}
|
|
@ -0,0 +1,432 @@
|
|||
#include "../include/bigint.hpp"
|
||||
|
||||
CBigInt::CBigInt() : m_negative(false) {}
|
||||
CBigInt::CBigInt( int64_t parent ) : m_negative(parent < 0) {
|
||||
m_data.reserve( CHUNK_BYTES / sizeof(parent) );
|
||||
uint64_t par = std::abs(parent);
|
||||
if (CHUNK_BITS == 64) {
|
||||
m_data.push_back(par);
|
||||
return;
|
||||
}
|
||||
|
||||
while (par) {
|
||||
m_data.push_back(par);
|
||||
par >>= CHUNK_BITS;
|
||||
}
|
||||
}
|
||||
|
||||
CBigInt::CBigInt( const CBigInt &oth ) : m_data(oth.m_data), m_negative(oth.m_negative) {}
|
||||
CBigInt::~CBigInt() {}
|
||||
|
||||
std::string CBigInt::toString() const {
|
||||
std::string retStr;
|
||||
if (m_negative)
|
||||
retStr = '-';
|
||||
|
||||
if (m_data.size() <= 1) {
|
||||
// If the number fits within a single word, use sts conversion
|
||||
uint64_t ret = 0;
|
||||
for (uint64_t i = 0; i < sizeof(ret) / CHUNK_BYTES && i < m_data.size(); ++i)
|
||||
ret += m_data[i] << (8 * i);
|
||||
return retStr + std::to_string(ret);
|
||||
}
|
||||
|
||||
std::unique_ptr<CBigInt> divNum (new CBigInt(*this));
|
||||
CBigInt ten(10);
|
||||
while (!divNum->isZero()) {
|
||||
auto tmp = divNum->divmod(&ten);
|
||||
divNum.reset(tmp.first);
|
||||
retStr += std::to_string(tmp.second->m_data[0]);
|
||||
delete tmp.second;
|
||||
}
|
||||
|
||||
// Reverse the string representation of the number
|
||||
for (uint64_t i = 0; i < retStr.size() / 2; i++)
|
||||
std::swap(retStr[i], retStr[retStr.size() - i - 1]);
|
||||
return retStr;
|
||||
}
|
||||
|
||||
void CBigInt::debugPrint() {
|
||||
uint64_t tmp = 0;
|
||||
if (m_negative)
|
||||
std::cout << '-';
|
||||
for (uint64_t i = 0; i < sizeof(tmp) / CHUNK_BYTES && i < m_data.size(); ++i)
|
||||
tmp += (uint64_t)m_data[i] << (CHUNK_BITS * i);
|
||||
std::cout << tmp << '\n';
|
||||
}
|
||||
|
||||
int64_t CBigInt::debugDump() {
|
||||
int64_t tmp = 0;
|
||||
for (uint64_t i = 0; i < sizeof(tmp) / CHUNK_BYTES && i < m_data.size(); ++i)
|
||||
tmp += (uint64_t)m_data[i] << (CHUNK_BITS * i);
|
||||
if (m_negative)
|
||||
tmp *= -1;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
CBigInt *CBigInt::add( const CBigInt *oth ) const {
|
||||
if (isZero())
|
||||
return new CBigInt(*oth);
|
||||
if (oth->isZero())
|
||||
return new CBigInt(*this);
|
||||
|
||||
if (!(m_negative ^ oth->m_negative)) {
|
||||
|
||||
CBigInt *ret = new CBigInt();
|
||||
ret->m_data.reserve( std::max(m_data.size() + 1, oth->m_data.size() + 1) );
|
||||
bool carry = 0;
|
||||
|
||||
for (uint64_t i = 0; i < std::max(m_data.size(), oth->m_data.size()); ++i) {
|
||||
CHUNK_TYPE tmp = ( i < m_data.size() ? m_data[i] : 0 ) + ( i < oth->m_data.size() ? oth->m_data[i] : 0 ) + carry;
|
||||
carry = (tmp < ((i < m_data.size()) ? m_data[i] : oth->m_data[i]));
|
||||
ret->m_data.push_back(tmp);
|
||||
}
|
||||
if (carry)
|
||||
ret->m_data.push_back(1);
|
||||
|
||||
ret->m_negative = m_negative;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// If the numbers have different signs
|
||||
int comp = cmp(oth);
|
||||
CBigInt *bigger = (CBigInt *)((comp >= 0) * (size_t)this + (comp < 0) * (size_t) oth);
|
||||
CBigInt *smaller = (CBigInt *)((comp >= 0) * (size_t)oth + (comp < 0) * (size_t) this);
|
||||
bool tmpB = bigger->m_negative;
|
||||
bigger->m_negative = false;
|
||||
bool tmpS = smaller->m_negative;
|
||||
smaller->m_negative = false;
|
||||
|
||||
CBigInt *ret = bigger->sub(smaller);
|
||||
ret->m_negative = tmpB;
|
||||
|
||||
bigger->m_negative = tmpB;
|
||||
smaller->m_negative = tmpS;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
CBigInt *CBigInt::sub( const CBigInt *oth ) const {
|
||||
int comp = cmp(oth);
|
||||
CBigInt *bigger = (CBigInt *)((comp >= 0) * (size_t)this + (comp < 0) * (size_t) oth);
|
||||
CBigInt *smaller = (CBigInt *)((comp >= 0) * (size_t)oth + (comp < 0) * (size_t) this);
|
||||
|
||||
if (!(m_negative ^ oth->m_negative)) {
|
||||
|
||||
CBigInt *ret = new CBigInt();
|
||||
ret->m_data.reserve( bigger->m_data.size() );
|
||||
bool borrow = 0;
|
||||
|
||||
for (; smaller->m_data.size() < bigger->m_data.size(); smaller->m_data.push_back(0));
|
||||
|
||||
for (uint64_t i = 0; i < smaller->m_data.size(); ++i) {
|
||||
CHUNK_TYPE tmp = bigger->m_data[i];
|
||||
if (borrow) {
|
||||
if (bigger->m_data[i] == 0) {
|
||||
tmp = CHUNK_MAX;
|
||||
} else {
|
||||
tmp = bigger->m_data[i] - 1;
|
||||
borrow = false;
|
||||
}
|
||||
}
|
||||
|
||||
borrow |= bigger->m_data[i] < smaller->m_data[i];
|
||||
tmp -= smaller->m_data[i];
|
||||
ret->m_data.push_back(tmp);
|
||||
}
|
||||
|
||||
ret->m_negative = m_negative;
|
||||
if (this == smaller)
|
||||
ret->m_negative = !ret->m_negative;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// If the numbers have different signs
|
||||
bool tmpB = bigger->m_negative;
|
||||
bigger->m_negative = false;
|
||||
bool tmpS = smaller->m_negative;
|
||||
smaller->m_negative = false;
|
||||
|
||||
CBigInt *ret = bigger->add(smaller);
|
||||
ret->m_negative = tmpB;
|
||||
|
||||
bigger->m_negative = tmpB;
|
||||
smaller->m_negative = tmpS;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
CBigInt *CBigInt::mul( const CBigInt *oth ) const {
|
||||
std::unique_ptr<CBigInt> ret( new CBigInt() );
|
||||
std::unique_ptr<CBigInt> shifted( new CBigInt(*this) );
|
||||
|
||||
for (uint64_t i = 0; i < (oth->m_data.size() * CHUNK_BITS); ++i) {
|
||||
if (oth->getBit(i)) {
|
||||
ret->addDestructive( shifted.get() );
|
||||
}
|
||||
shifted->pushLeft(0);
|
||||
}
|
||||
ret->m_negative = m_negative ^ oth->m_negative;
|
||||
return ret.release();
|
||||
}
|
||||
|
||||
CBigInt *CBigInt::div( const CBigInt *oth ) const {
|
||||
auto ret = divmod(oth);
|
||||
delete ret.second;
|
||||
return ret.first;
|
||||
}
|
||||
|
||||
CBigInt *CBigInt::mod( const CBigInt *oth ) const {
|
||||
auto ret = divmod(oth);
|
||||
delete ret.first;
|
||||
return ret.second;
|
||||
}
|
||||
|
||||
CBigInt *CBigInt::gcd( const CBigInt *oth ) const {
|
||||
auto ret = rea(oth);
|
||||
delete ret.second;
|
||||
return ret.first;
|
||||
}
|
||||
|
||||
CBigInt *CBigInt::lcm( const CBigInt *oth ) const {
|
||||
auto ret = rea(oth);
|
||||
delete ret.first;
|
||||
return ret.second;
|
||||
}
|
||||
|
||||
CBigInt *CBigInt::shf( int64_t shift ) const {
|
||||
CBigInt *ret = new CBigInt();
|
||||
if (shift == 0) {
|
||||
delete ret;
|
||||
ret = new CBigInt(*this);
|
||||
}
|
||||
|
||||
if (shift < 0) {
|
||||
throw std::logic_error("invalid bitshift");
|
||||
}
|
||||
|
||||
if (shift > 0) {
|
||||
size_t bitOffset = shift % CHUNK_BITS;
|
||||
size_t chunkOffset = shift / CHUNK_BITS;
|
||||
size_t numNewChunks = m_data.size() + ((shift + CHUNK_BITS - 1) / CHUNK_BITS);
|
||||
|
||||
ret->m_data = std::vector<CHUNK_TYPE>( chunkOffset, 0 );
|
||||
ret->m_data.reserve( numNewChunks );
|
||||
|
||||
CHUNK_TYPE carry = 0;
|
||||
for (uint64_t i = 0; i < m_data.size(); ++i) {
|
||||
ret->m_data.push_back(carry | (m_data[i] << bitOffset));
|
||||
carry = m_data[i] >> (CHUNK_BITS - bitOffset);
|
||||
}
|
||||
if (carry)
|
||||
ret->m_data.push_back(carry);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
CBigInt* CBigInt::power(uint64_t pow) const {
|
||||
if (pow == 0)
|
||||
return new CBigInt(0);
|
||||
if (pow == 1)
|
||||
return new CBigInt(*this);
|
||||
|
||||
if (!(pow % 2)) { // a^(2b) = 2(a^b)
|
||||
CBigInt* halfPower = power(pow / 2);
|
||||
CBigInt* ret = halfPower->mul(halfPower);
|
||||
delete halfPower;
|
||||
return ret;
|
||||
}
|
||||
|
||||
CBigInt* ret = new CBigInt(*this);
|
||||
for (uint64_t i = 1; i < pow; ++i) {
|
||||
CBigInt* tmp = ret->mul(this);
|
||||
delete ret;
|
||||
ret = tmp;
|
||||
}
|
||||
|
||||
ret->m_negative = (pow % 2 && m_negative);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CBigInt::addDestructive( CBigInt *oth ) {
|
||||
m_data.reserve( std::max(m_data.size() + 1, oth->m_data.size() + 1) );
|
||||
bool carry = 0;
|
||||
|
||||
for (uint64_t i = 0; i < std::max(m_data.size(), oth->m_data.size()); ++i) {
|
||||
CHUNK_TYPE tmp = ( i < m_data.size() ? m_data[i] : 0 ) + ( i < oth->m_data.size() ? oth->m_data[i] : 0 ) + carry;
|
||||
carry = (tmp < ((i < m_data.size()) ? m_data[i] : oth->m_data[i]));
|
||||
if (m_data.size() > i)
|
||||
m_data[i] = tmp;
|
||||
else
|
||||
m_data.push_back(tmp);
|
||||
}
|
||||
if (carry)
|
||||
m_data.push_back(1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBigInt::subDestructive( CBigInt *oth ) {
|
||||
bool borrow = 0;
|
||||
size_t len = oth->m_data.size();
|
||||
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
CHUNK_TYPE tmp = m_data[i];
|
||||
if (borrow) {
|
||||
if (m_data[i] == 0) {
|
||||
tmp = CHUNK_MAX;
|
||||
} else {
|
||||
tmp = m_data[i] - 1;
|
||||
borrow = false;
|
||||
}
|
||||
}
|
||||
|
||||
borrow = m_data[i] < oth->m_data[i];
|
||||
tmp -= oth->m_data[i];
|
||||
m_data[i] = tmp;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBigInt::isZero( void ) const {
|
||||
if (!m_data.size())
|
||||
return true;
|
||||
|
||||
for (uint64_t i = 0; i < m_data.size(); ++i)
|
||||
if (m_data[i])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::pair<CBigInt*, CBigInt*> CBigInt::divmod( const CBigInt* oth) const {
|
||||
if (oth->isZero()) {
|
||||
throw std::logic_error("Division by zero");
|
||||
}
|
||||
|
||||
std::unique_ptr<CBigInt> quotient( new CBigInt());
|
||||
std::unique_ptr<CBigInt> remainder( new CBigInt());
|
||||
|
||||
const CBigInt *numerator(this);
|
||||
|
||||
std::unique_ptr<CBigInt> divisor( new CBigInt(*oth));
|
||||
|
||||
// Calculate the number of bits in the numerator and divisor
|
||||
int64_t numeratorBits = ((numerator->m_data.size() - 1) * CHUNK_BITS );
|
||||
if (numerator->m_data.size())
|
||||
numeratorBits += ( 64 - __builtin_clzll(numerator->m_data[numerator->m_data.size() - 1]) );
|
||||
int64_t divisorBits = ((divisor->m_data.size() - 1) * CHUNK_BITS);
|
||||
if (divisor->m_data.size())
|
||||
divisorBits += ( 64 - __builtin_clzll(divisor->m_data[divisor->m_data.size() - 1]) );
|
||||
|
||||
int64_t shift = numeratorBits - divisorBits;
|
||||
|
||||
if (shift < 0) {
|
||||
return { new CBigInt(), new CBigInt(*this) };
|
||||
}
|
||||
|
||||
for (int64_t i = numeratorBits - 1; i >= 0; --i) {
|
||||
remainder->pushLeft( getBit(i) );
|
||||
|
||||
if (remainder->cmp(divisor.get()) >= 0) {
|
||||
remainder->subDestructive(divisor.get());
|
||||
quotient->setBit(i, 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
quotient->m_negative = (m_negative ^ oth->m_negative);
|
||||
remainder->m_negative = false; // Ensure the remainder is positive
|
||||
|
||||
quotient->optimize();
|
||||
remainder->optimize();
|
||||
|
||||
return { quotient.release(), remainder.release() };
|
||||
}
|
||||
|
||||
std::pair<CBigInt*, CBigInt*> CBigInt::rea( const CBigInt* oth) const {
|
||||
//* GCD LCM
|
||||
std::unique_ptr<CBigInt> a(new CBigInt(*this));
|
||||
std::unique_ptr<CBigInt> b(new CBigInt(*oth));
|
||||
|
||||
if (a->isZero() || b->isZero()) {
|
||||
return { a->add(b.get()), new CBigInt(0) };
|
||||
}
|
||||
|
||||
while (!b->isZero()) {
|
||||
auto tmp = a->divmod(b.get());
|
||||
a.reset(b.release());
|
||||
b.reset(tmp.second);
|
||||
delete tmp.first;
|
||||
}
|
||||
|
||||
std::unique_ptr<CBigInt> lcm(mul(oth));
|
||||
lcm.reset( lcm->div(a.get()) );
|
||||
|
||||
return { a.release(), lcm.release() };
|
||||
}
|
||||
|
||||
bool CBigInt::getBit( uint64_t i) const {
|
||||
if (i > m_data.size() * CHUNK_BITS)
|
||||
return false;
|
||||
|
||||
return (m_data[ i / CHUNK_BITS ] & ( 1u << ( i % CHUNK_BITS )));
|
||||
}
|
||||
|
||||
bool CBigInt::setBit( uint64_t i, bool b) {
|
||||
while (i >= m_data.size() * CHUNK_BITS) {
|
||||
m_data.push_back(0);
|
||||
}
|
||||
|
||||
if (b)
|
||||
m_data[ i / CHUNK_BITS ] |= ( (CHUNK_TYPE)1 << (( i % CHUNK_BITS )));
|
||||
else
|
||||
m_data[ i / CHUNK_BITS ] &= ~( (CHUNK_TYPE)1 << (( i % CHUNK_BITS )));
|
||||
return true;
|
||||
}
|
||||
|
||||
int CBigInt::cmp( const CBigInt *oth ) const {
|
||||
if (m_data.size() != oth->m_data.size())
|
||||
return m_data.size() - oth->m_data.size();
|
||||
|
||||
for (int64_t i = m_data.size() - 1; i >= 0; --i) {
|
||||
if (m_data[i] != oth->m_data[i])
|
||||
return 1 + ( -2 * (m_data[i] < oth->m_data[i]));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CBigInt::pushLeft( bool i ) {
|
||||
bool carry = i;
|
||||
CHUNK_TYPE mask = (uint64_t)1 << (CHUNK_BITS - 1);
|
||||
for (uint64_t j = 0; j < m_data.size(); ++j) {
|
||||
bool tmp = m_data[j] & mask;
|
||||
m_data[j] <<= 1;
|
||||
m_data[j] |= carry;
|
||||
carry = tmp;
|
||||
}
|
||||
if (carry)
|
||||
m_data.push_back(1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBigInt::optimize( void ) {
|
||||
if (m_data.size() < 1) {
|
||||
m_negative = false;
|
||||
return true;
|
||||
}
|
||||
// Delete trailing zeros
|
||||
for (int i = m_data.size() - 1; !m_data[i] && i ; m_data.pop_back(), --i);
|
||||
|
||||
// Shrink the capacity if it's significantly larger than the size
|
||||
if (m_data.capacity() >= 2 * m_data.size())
|
||||
m_data.shrink_to_fit();
|
||||
|
||||
// remove negative flag if its zero
|
||||
if (isZero())
|
||||
m_negative = false;
|
||||
|
||||
return true;
|
||||
} // delete zeros + shrink to fit
|
|
@ -0,0 +1,143 @@
|
|||
#include "../include/binsaver.hpp"
|
||||
|
||||
|
||||
CBinsaver::CBinsaver(std::map<std::string, CRational> &variablesMap) : CSaver(variablesMap) {}
|
||||
|
||||
CBinsaver::~CBinsaver() {}
|
||||
|
||||
bool CBinsaver::save(const std::string& fileName) {
|
||||
ssize_t variableCount = m_variables.size();
|
||||
// ssize_t fileHash = 0;
|
||||
// uint64_t hashWord;
|
||||
|
||||
std::ofstream ofs(fileName);
|
||||
if (!ofs || !ofs.good())
|
||||
return false;
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
// write variable count
|
||||
ss << std::to_string(variableCount) + "\n";
|
||||
|
||||
// write variables
|
||||
for (auto& i : m_variables) {
|
||||
ss << i.first + " " + i.second.toString() + "\n";
|
||||
}
|
||||
|
||||
// calculate file hash
|
||||
// std::stringstream hashSS(ss.str());
|
||||
// while (hashSS.read(reinterpret_cast<char*>(&hashWord), sizeof(hashWord))) {
|
||||
// fileHash ^= hashWord;
|
||||
// }
|
||||
// ss << "hash " + std::to_string(fileHash);
|
||||
|
||||
ofs << ss.rdbuf();
|
||||
ofs.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBinsaver::load( const std::string &fileName ) {
|
||||
ssize_t variableCount;
|
||||
|
||||
std::ifstream ifs(fileName);
|
||||
if (!ifs || !ifs.good()) {
|
||||
m_log = "file reading error";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string buffer;
|
||||
std::getline( ifs, buffer );
|
||||
|
||||
// check if variable count is valid
|
||||
if (buffer.size() < 1 || buffer.size() > 10 || !(std::all_of(buffer.begin(), buffer.end(),
|
||||
[](unsigned char ch) { return std::isdigit(ch); }) )) {
|
||||
ifs.close();
|
||||
m_log = "invalid argument count";
|
||||
return false;
|
||||
}
|
||||
|
||||
variableCount = std::stoll(buffer);
|
||||
if (variableCount < 0) {
|
||||
ifs.close();
|
||||
m_log = "invalid argument count";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (;variableCount && std::getline(ifs, buffer); --variableCount) {
|
||||
std::istringstream iss(buffer);
|
||||
std::string varName;
|
||||
std::string numStr;
|
||||
std::string denStr;
|
||||
std::string slash;
|
||||
bool numSign = 0;
|
||||
bool denSign = 0;
|
||||
|
||||
if (!(iss >> varName >> numStr >> slash >> denStr) || slash != "/") {
|
||||
ifs.close();
|
||||
m_log = "wrong format";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (numStr.at(0) == '-') {
|
||||
numSign = 1;
|
||||
numStr = numStr.substr(1);
|
||||
}
|
||||
if (denStr.at(0) == '-') {
|
||||
denSign = 1;
|
||||
denStr = denStr.substr(1);
|
||||
}
|
||||
|
||||
if (!(std::all_of(numStr.begin(), numStr.end(), [](unsigned char ch) { return std::isdigit(ch); }) )
|
||||
|| !(std::all_of(denStr.begin(), denStr.end(), [](unsigned char ch) { return std::isdigit(ch); }) )) {
|
||||
ifs.close();
|
||||
m_log = "invalid number";
|
||||
return false;
|
||||
}
|
||||
|
||||
for ( auto &c : numStr)
|
||||
c -= 48;
|
||||
for ( auto &c : denStr)
|
||||
c -= 48;
|
||||
|
||||
CBigInt *num = new CBigInt(0);
|
||||
uint64_t insertPosition = 0;
|
||||
while (!std::all_of(numStr.begin(), numStr.end(), [](char c) { return c == 0; })) {
|
||||
num->setBit(insertPosition++, CParser::stringDivideDecimal(numStr));
|
||||
}
|
||||
|
||||
CBigInt *den = new CBigInt(0);
|
||||
insertPosition = 0;
|
||||
while (!std::all_of(denStr.begin(), denStr.end(), [](char c) { return c == 0; })) {
|
||||
den->setBit(insertPosition++, CParser::stringDivideDecimal(denStr));
|
||||
}
|
||||
|
||||
num->m_negative = numSign;
|
||||
den->m_negative = denSign;
|
||||
if (!m_variables.emplace(varName, CRational(num, den)).second) {
|
||||
// delete num;
|
||||
// delete den;
|
||||
// ifs.close();
|
||||
// m_log = "varable already exists";
|
||||
// return false;
|
||||
}
|
||||
}
|
||||
ifs.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
#binsaveformat
|
||||
##header
|
||||
[64bit varible count]
|
||||
|
||||
##one variable
|
||||
[64bit identifier len] [identif]
|
||||
[64bit datalen] [data]
|
||||
|
||||
##padding zeros to 8byte multiply
|
||||
[0x0000]
|
||||
|
||||
[64bit hash]
|
||||
##hash
|
||||
xor all 64bit chunks
|
||||
*/
|
|
@ -0,0 +1,11 @@
|
|||
#include "../include/rational.hpp"
|
||||
#include "../include/division.hpp"
|
||||
|
||||
CDivision::CDivision( CPrintable *a, CPrintable *b ) : COperator(a, b) {}
|
||||
CRational *CDivision::evaluate() {
|
||||
std::unique_ptr<CRational> a (m_firstArgument->evaluate());
|
||||
std::unique_ptr<CRational> b (m_secondArgument->evaluate());
|
||||
if (b->m_numerator->isZero())
|
||||
throw std::logic_error("division by zero");
|
||||
return a->div(b.get());
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
#include "../include/rational.hpp"
|
||||
#include "../include/exponencial.hpp"
|
||||
|
||||
CExponencial::CExponencial( CPrintable *a, CPrintable *b ) : COperator(a, b) {}
|
||||
CRational *CExponencial::evaluate() {
|
||||
std::unique_ptr<CRational> a (m_firstArgument->evaluate());
|
||||
std::unique_ptr<CRational> b (m_secondArgument->evaluate());
|
||||
CBigInt one(1);
|
||||
if (b->m_denominator->cmp(&one)) {
|
||||
std::unique_ptr<CRational> tmp (a->ln());
|
||||
tmp.reset( tmp->mul(b.get()) );
|
||||
return tmp->exp();
|
||||
}
|
||||
|
||||
if (b->isNegative()) {
|
||||
b->negate();
|
||||
auto tmp = new CRational( a->m_denominator->power(b->m_numerator->debugDump()),
|
||||
a->m_numerator ->power(b->m_numerator->debugDump()) );
|
||||
b->negate();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
return new CRational( a->m_numerator ->power(b->m_numerator->debugDump()),
|
||||
a->m_denominator->power(b->m_numerator->debugDump()) );
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#include "../include/rational.hpp"
|
||||
#include "../include/logarithm.hpp"
|
||||
|
||||
CLogarith::CLogarith( CPrintable *a, CPrintable *b ) : COperator(a, b) {}
|
||||
CRational *CLogarith::evaluate() {
|
||||
std::unique_ptr<CRational> a (m_firstArgument->evaluate());
|
||||
std::unique_ptr<CRational> b (m_secondArgument->evaluate());
|
||||
if (a->m_numerator->isZero()) { // base zero -> neturtal log
|
||||
return b->ln();
|
||||
}
|
||||
if (a->isNegative() || b->isNegative())
|
||||
throw std::logic_error("logarith on negative numbers");
|
||||
|
||||
a.reset(a->ln());
|
||||
b.reset(b->ln());
|
||||
|
||||
return b->div(a.get());
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
#include "../include/parser.hpp"
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
int main() {
|
||||
std::string inputCursor = "> ";
|
||||
std::string outputCursor = "= ";
|
||||
|
||||
std::cout <<
|
||||
"█▀▀ ▄▀█ █ █▀▀" << '\n' <<
|
||||
"█▄▄ █▀█ █▄▄ █▄▄" << '\n' <<
|
||||
"version 1.0.a" << std::endl;
|
||||
|
||||
CParser a;
|
||||
while (a.m_continue) {
|
||||
std::string input;
|
||||
std::cout << inputCursor;
|
||||
if (!std::getline( std::cin, input))
|
||||
break;
|
||||
if (input.empty())
|
||||
continue;
|
||||
a.convert(input);
|
||||
std::cout << outputCursor << a.m_output << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#include "../include/rational.hpp"
|
||||
#include "../include/modulo.hpp"
|
||||
|
||||
CModulo::CModulo( CPrintable *a, CPrintable *b ) : COperator(a, b) {}
|
||||
CRational *CModulo::evaluate() {
|
||||
std::unique_ptr<CRational> a (m_firstArgument->evaluate());
|
||||
std::unique_ptr<CRational> b (m_secondArgument->evaluate());
|
||||
CBigInt one(1);
|
||||
if (a->m_denominator.get()->cmp(&one) || b->m_denominator.get()->cmp(&one))
|
||||
throw "mod on racional not supported";
|
||||
return new CRational( a->m_numerator.get()->mod(b->m_numerator.get()));
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#include "../include/rational.hpp"
|
||||
#include "../include/multiplication.hpp"
|
||||
|
||||
CMultiplication::CMultiplication( CPrintable *a, CPrintable *b ) : COperator(a, b) {}
|
||||
CRational *CMultiplication::evaluate() {
|
||||
std::unique_ptr<CRational> a (m_firstArgument->evaluate());
|
||||
std::unique_ptr<CRational> b (m_secondArgument->evaluate());
|
||||
return a->mul(b.get());
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
#include "../include/operator.hpp"
|
||||
|
||||
COperator::COperator( CPrintable *a, CPrintable *b ) : m_firstArgument(a), m_secondArgument(b) {}
|
|
@ -0,0 +1,677 @@
|
|||
#include "../include/parser.hpp"
|
||||
|
||||
CParser::CParser() {
|
||||
m_variables.emplace("ans", CRational(new CBigInt(0)));
|
||||
m_continue = 1;
|
||||
m_saver.reset(new CTextsaver(m_variables));
|
||||
// CRational::termPrecision = 4;
|
||||
}
|
||||
|
||||
CParser::~CParser() { clear(); }
|
||||
|
||||
uint64_t CParser::getOperatorPriority( TOKEN t ) const {
|
||||
uint64_t ret = 0;
|
||||
switch (t)
|
||||
{
|
||||
case DEREFERENCE:
|
||||
ret = 8;
|
||||
break;
|
||||
case LN:
|
||||
ret = 7;
|
||||
break;
|
||||
case EXP:
|
||||
ret = 6;
|
||||
break;
|
||||
case DIVIDE:
|
||||
ret = 5;
|
||||
break;
|
||||
case MULTIPLY:
|
||||
ret = 4;
|
||||
break;
|
||||
case MOD:
|
||||
ret = 3;
|
||||
break;
|
||||
case ADD:
|
||||
ret = 2;
|
||||
break;
|
||||
case SUBTRACT:
|
||||
ret = 1;
|
||||
break;
|
||||
default:
|
||||
// throw "unresolvable syntax error";
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
CParser::CMD CParser::recognizeCommand( uint64_t commandPos ) const {
|
||||
// position in raw lexems
|
||||
CParser::CMD ret = UNKNOWN_CMD;
|
||||
char c = m_input[m_rawLexems[commandPos].second];
|
||||
// std::cout << c;
|
||||
if (!std::islower(c))
|
||||
return ret;
|
||||
|
||||
switch (c) {
|
||||
case 'q':
|
||||
ret = QUIT_CMD;
|
||||
break;
|
||||
case 'h':
|
||||
ret = HELP_CMD;
|
||||
break;
|
||||
case 'p':
|
||||
ret = PRECISSION_CMD;
|
||||
break;
|
||||
case 's':
|
||||
ret = SAVE_CMD;
|
||||
break;
|
||||
case 'l':
|
||||
ret = LOAD_CMD;
|
||||
break;
|
||||
case 'r':
|
||||
ret = ROUND_CMD;
|
||||
break;
|
||||
default:
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
|
||||
char nextChar = m_input[m_rawLexems[commandPos].second + 1];
|
||||
if (m_input.size() == (uint64_t)m_rawLexems[commandPos].second
|
||||
|| nextChar == ' '
|
||||
|| nextChar == '\0') // short command
|
||||
return ret;
|
||||
|
||||
std::string comStr;
|
||||
switch (ret) {
|
||||
case QUIT_CMD:
|
||||
comStr = m_input.substr( m_rawLexems[commandPos].second, sizeof("quit") - 1);
|
||||
ret = comStr == "quit" ? QUIT_CMD : UNKNOWN_CMD;
|
||||
break;
|
||||
case HELP_CMD:
|
||||
comStr = m_input.substr( m_rawLexems[commandPos].second, sizeof("help") - 1);
|
||||
ret = comStr == "help" ? HELP_CMD : UNKNOWN_CMD;
|
||||
break;
|
||||
case PRECISSION_CMD:
|
||||
comStr = m_input.substr( m_rawLexems[commandPos].second, sizeof("precision") - 1);
|
||||
ret = comStr == "precision" ? PRECISSION_CMD : UNKNOWN_CMD;
|
||||
break;
|
||||
case SAVE_CMD:
|
||||
comStr = m_input.substr( m_rawLexems[commandPos].second, sizeof("save") - 1);
|
||||
ret = comStr == "save" ? SAVE_CMD : UNKNOWN_CMD;
|
||||
break;
|
||||
case LOAD_CMD:
|
||||
comStr = m_input.substr( m_rawLexems[commandPos].second, sizeof("load") - 1);
|
||||
ret = comStr == "load" ? LOAD_CMD : UNKNOWN_CMD;
|
||||
break;
|
||||
case ROUND_CMD:
|
||||
comStr = m_input.substr( m_rawLexems[commandPos].second, sizeof("round") - 1);
|
||||
ret = comStr == "round" ? ROUND_CMD : UNKNOWN_CMD;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
CParser::CMD CParser::parseCommand( uint64_t &startPos ) const {
|
||||
// position in raw lexems
|
||||
if (m_rawLexems[startPos].first == COMMAND) {
|
||||
|
||||
return recognizeCommand(startPos + 1);
|
||||
} else {
|
||||
startPos = 1;
|
||||
return NONE_CMD;
|
||||
}
|
||||
}
|
||||
|
||||
bool CParser::executeCommand( CParser::CMD cmd ) {
|
||||
switch (cmd) {
|
||||
case QUIT_CMD:
|
||||
m_continue = 0;
|
||||
m_output = "quitting..";
|
||||
return false;
|
||||
break;
|
||||
case HELP_CMD:
|
||||
helpCommand();
|
||||
return false;
|
||||
break;
|
||||
case PRECISSION_CMD:
|
||||
if (m_processedLexems.size() != 7)
|
||||
return false;
|
||||
try {
|
||||
CRational::termPrecision = std::stoull(m_input.substr(m_rawLexems[4].second));
|
||||
m_output = "precision set";
|
||||
if (CRational::termPrecision == 0) {
|
||||
m_output += ", zero will propably break exp and ln calculations!";
|
||||
}
|
||||
} catch ( std::exception &e ) {
|
||||
m_output = "invalid precision, recommended values are 1-10";
|
||||
}
|
||||
return false;
|
||||
break;
|
||||
case SAVE_CMD:
|
||||
if (m_processedLexems.size() != 7)
|
||||
return false;
|
||||
if (m_saver->save( m_input.substr(m_rawLexems[4].second) ))
|
||||
m_output = "save successful";
|
||||
else
|
||||
m_output = "save failed";
|
||||
return false;
|
||||
break;
|
||||
case LOAD_CMD:
|
||||
if (m_processedLexems.size() != 7)
|
||||
return false;
|
||||
if (m_saver->load( m_input.substr(m_rawLexems[4].second) ))
|
||||
m_output = "load successful";
|
||||
else
|
||||
m_output = "load failed";
|
||||
return false;
|
||||
break;
|
||||
case ROUND_CMD:
|
||||
if (m_processedLexems.size() != 8 ||
|
||||
(m_processedLexems[4].first != NUMBER && m_processedLexems[5].first != NUMBER))
|
||||
return false;
|
||||
try {
|
||||
uint64_t decimals = std::stoull( m_input.substr(m_rawLexems[4].second) );
|
||||
//todo check
|
||||
m_output = m_processedLexems[5].second->round(decimals);
|
||||
} catch (std::exception &e) {
|
||||
m_output = "rounding failed";
|
||||
}
|
||||
return false;
|
||||
break;
|
||||
case UNKNOWN_CMD:
|
||||
m_output = "unknown command. try !help";
|
||||
return false;
|
||||
break;
|
||||
case NONE_CMD:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CParser::helpCommand() {
|
||||
m_output = "!h !help - for this quick help\n";
|
||||
m_output += "!q !quit - to quit\n";
|
||||
m_output += "!p !precision x - to set number of terms for aproximating logarith and exponencial (positive int or LOW=4/HIGH=8, values below 1 or above 10 are not recommended)\n";
|
||||
m_output += "!s !save - to save variables (this is not automatic on quit!)\n";
|
||||
m_output += "!l !load - to load them back (this is not automatic on quit!)\n\n";
|
||||
m_output += "!r !round x y - to round y to x decimals\n";
|
||||
|
||||
m_output += "start by typing numbers and operators\n";
|
||||
m_output += "exact operation supported for racional numbers:\n";
|
||||
m_output += "addition (+), subtraction (-), multiplication (*), division (/)\n";
|
||||
m_output += "example usage:\n";
|
||||
m_output += "3.25 * ( -4/3 + 3/4 )\n\n";
|
||||
|
||||
m_output += "aproximation of logarith (&) and exponencial (^)\n";
|
||||
m_output += "example usage:\n";
|
||||
m_output += "(3)&(27) represents logartih with base 3 out of 27\n\n";
|
||||
|
||||
m_output += "(everything is case sensitive!)\n";
|
||||
m_output += "run \"dot ./doc/grammar.dot -T x11\" to see grammar guide\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CParser::clear() {
|
||||
m_rawLexems.clear();
|
||||
for( auto &i : m_processedLexems )
|
||||
if (i.second)
|
||||
delete i.second;
|
||||
m_processedLexems.clear();
|
||||
m_output = "SYNTAX ERROR try !help";
|
||||
}
|
||||
|
||||
CParser::TOKEN CParser::recognize( char c ) const {
|
||||
if (c == ' ')
|
||||
return CParser::TOKEN::WHITESPACE;
|
||||
if (c >= '0' && c <= '9')
|
||||
return CParser::TOKEN::NUMBER;
|
||||
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
|
||||
return CParser::TOKEN::LABEL;
|
||||
|
||||
CParser::TOKEN ret;
|
||||
switch (c) {
|
||||
case '!':
|
||||
ret = COMMAND;
|
||||
break;
|
||||
case '$':
|
||||
ret = DEREFERENCE;
|
||||
break;
|
||||
case '(':
|
||||
ret = OPEN;
|
||||
break;
|
||||
case ')':
|
||||
ret = CLOSE;
|
||||
break;
|
||||
case '&':
|
||||
ret = LN;
|
||||
break;
|
||||
case '^':
|
||||
ret = EXP;
|
||||
break;
|
||||
case '/':
|
||||
ret = DIVIDE;
|
||||
break;
|
||||
case '*':
|
||||
ret = MULTIPLY;
|
||||
break;
|
||||
case '%':
|
||||
ret = MOD;
|
||||
break;
|
||||
case '+':
|
||||
ret = ADD;
|
||||
break;
|
||||
case '-':
|
||||
ret = SUBTRACT;
|
||||
break;
|
||||
case '.':
|
||||
ret = DOT;
|
||||
break;
|
||||
case '=':
|
||||
ret = SAVE;
|
||||
break;
|
||||
default:
|
||||
ret = SYNTAX_ERROR;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
CRational *CParser::parseNumber( uint64_t i, bool isDecimal = false, bool hasSign = false ) const {
|
||||
CBigInt *num = new CBigInt(0);
|
||||
CBigInt *den;
|
||||
std::string rawNumber = readToken(i);
|
||||
if (isDecimal) {
|
||||
rawNumber += readToken(i+2);
|
||||
int64_t decimalLen = m_rawLexems[i+2].second;
|
||||
for (;decimalLen < m_rawLexems[i+3].second && m_input[decimalLen] != ' '; ++decimalLen);
|
||||
decimalLen -= m_rawLexems[i+2].second;
|
||||
|
||||
if (decimalLen <= 10)
|
||||
den = new CBigInt(std::pow(10, decimalLen));
|
||||
else {
|
||||
CBigInt *tmp = new CBigInt( 10 );
|
||||
den = tmp->power(decimalLen);
|
||||
delete tmp;
|
||||
}
|
||||
|
||||
} else {
|
||||
den = new CBigInt(1);
|
||||
}
|
||||
hasSign ^= 1;
|
||||
hasSign ^= 1;
|
||||
// convert ascii
|
||||
for ( auto &c : rawNumber) {
|
||||
c -= 48;
|
||||
}
|
||||
|
||||
uint64_t insertPosition = 0;
|
||||
while (!std::all_of(rawNumber.begin(), rawNumber.end(), [](char c) { return c == 0; })) {
|
||||
num->setBit(insertPosition++, stringDivideDecimal(rawNumber));
|
||||
}
|
||||
|
||||
return new CRational(num, den);
|
||||
}
|
||||
|
||||
bool CParser::stringDivideDecimal( std::string &s ) { // returns next bit for binary conversion
|
||||
uint16_t additive = 0;
|
||||
uint16_t nextAdditive;
|
||||
for (char &c : s) {
|
||||
nextAdditive = (c % 2) * 5;
|
||||
c = c / 2 + additive;
|
||||
std::swap(additive, nextAdditive);
|
||||
}
|
||||
return additive;
|
||||
}
|
||||
|
||||
bool CParser::tokenize() {
|
||||
m_rawLexems.emplace_back(START, -1);
|
||||
m_rawLexems.emplace_back(OPEN, -1);
|
||||
for (uint64_t i = 0; i < m_input.size(); ++i) {
|
||||
TOKEN type = recognize(m_input[i]);
|
||||
if (type == SYNTAX_ERROR)
|
||||
return false;
|
||||
if (type == WHITESPACE) {
|
||||
if (m_rawLexems.back().first != WHITESPACE)
|
||||
m_rawLexems.emplace_back(WHITESPACE, i);
|
||||
continue;
|
||||
}
|
||||
if (type == NUMBER) {
|
||||
if (m_rawLexems.back().first != NUMBER)
|
||||
m_rawLexems.emplace_back(NUMBER, i);
|
||||
continue;
|
||||
}
|
||||
if (type == LABEL) {
|
||||
if (m_rawLexems.back().first != LABEL)
|
||||
m_rawLexems.emplace_back(LABEL, i);
|
||||
continue;
|
||||
}
|
||||
if (type == COMMAND || type == SAVE) {
|
||||
// if (m_rawLexems.size() == 2)
|
||||
m_rawLexems.emplace_back(type, i);
|
||||
// else
|
||||
// return false;
|
||||
continue;
|
||||
}
|
||||
m_rawLexems.emplace_back(type, i);
|
||||
}
|
||||
m_rawLexems.emplace_back(CLOSE, m_input.size());
|
||||
m_rawLexems.emplace_back(END, m_input.size());
|
||||
return m_rawLexems.size() > 4;
|
||||
}
|
||||
|
||||
std::string CParser::readToken( uint64_t i ) const {
|
||||
std::string ret;
|
||||
for ( int64_t j = m_rawLexems[i].second; j < m_rawLexems[i+1].second && m_input[j] != ' '; ++j ) {
|
||||
ret.push_back(m_input[j]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CParser::grammarPreprocess() {
|
||||
// strip whitespaces
|
||||
m_rawLexems.erase(
|
||||
std::remove_if(
|
||||
m_rawLexems.begin(),
|
||||
m_rawLexems.end(),
|
||||
[](const std::pair<CParser::TOKEN, int64_t>& lexem) {
|
||||
return lexem.first == WHITESPACE;
|
||||
}
|
||||
),
|
||||
m_rawLexems.end()
|
||||
);
|
||||
|
||||
m_saveInto.clear();
|
||||
if (m_rawLexems[2].first == LABEL) {
|
||||
uint64_t varLen = m_rawLexems[2].second;
|
||||
for (; (m_input[varLen] >= 'a' && m_input[varLen] <= 'z') || (m_input[varLen] >= 'A' && m_input[varLen] <= 'Z'); ++ varLen);
|
||||
varLen -= m_rawLexems[2].second;
|
||||
m_saveInto = m_input.substr(m_rawLexems[2].second, varLen);
|
||||
|
||||
if (m_rawLexems[3].first != SAVE) {
|
||||
m_output = "SYNTAX ERROR try " + m_saveInto + " = " +
|
||||
(m_input.substr(m_rawLexems[3].second).size() ? m_input.substr(m_rawLexems[3].second) : "(1 + 2) * 3");
|
||||
return false;
|
||||
}
|
||||
m_rawLexems.erase( m_rawLexems.begin() + 2, m_rawLexems.begin() + 4);
|
||||
}
|
||||
|
||||
// process numbers
|
||||
uint64_t i = 0;
|
||||
for (; i < m_rawLexems.size(); ++i) {
|
||||
bool numberHasDecimals = false;
|
||||
bool numberHasDot = false;
|
||||
bool numberHasSign = false;
|
||||
bool numberNegative = false;
|
||||
if (m_rawLexems[i].first == WHITESPACE)
|
||||
continue;
|
||||
|
||||
if (m_rawLexems[i].first == DOT) {
|
||||
if (m_rawLexems[i+1].first == NUMBER) {
|
||||
m_processedLexems.emplace_back(NUMBER, parseNumber(i+1, false, false));
|
||||
|
||||
uint64_t decimalLen = m_rawLexems[i+1].second;
|
||||
for (; m_input[decimalLen] >= '0' && m_input[decimalLen] <= '9'; ++decimalLen);
|
||||
decimalLen -= m_rawLexems[i+1].second;
|
||||
|
||||
if (decimalLen <= 10)
|
||||
m_processedLexems.back().second->m_denominator.reset( new CBigInt(std::pow(10, decimalLen)));
|
||||
else {
|
||||
CBigInt *tmp = new CBigInt( 10 );
|
||||
m_processedLexems.back().second->m_denominator.reset( tmp->power(decimalLen) );
|
||||
delete tmp;
|
||||
}
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_rawLexems[i].first == NUMBER) {
|
||||
if (m_processedLexems.back().first == NUMBER)
|
||||
return false;
|
||||
numberHasDot = (m_rawLexems[i+1].first == DOT);
|
||||
|
||||
numberHasDecimals = numberHasDot && m_rawLexems[i+2].first == NUMBER;
|
||||
numberHasSign = ((m_rawLexems[i-1].first == ADD || m_rawLexems[i-1].first == SUBTRACT)
|
||||
&&
|
||||
(m_processedLexems[m_processedLexems.size() -2].first != NUMBER
|
||||
&& m_processedLexems[m_processedLexems.size() -2].first != CLOSE));
|
||||
|
||||
if (numberHasSign && !m_processedLexems.empty()) {
|
||||
numberNegative = m_processedLexems.back().first == SUBTRACT;
|
||||
|
||||
m_processedLexems.pop_back();
|
||||
|
||||
}
|
||||
|
||||
m_processedLexems.emplace_back(NUMBER, parseNumber(i, numberHasDecimals, numberHasSign));
|
||||
m_processedLexems.back().second->m_numerator->m_negative = numberNegative;
|
||||
i += numberHasDot;
|
||||
i += numberHasDecimals;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_rawLexems[i].first == DEREFERENCE) {
|
||||
if (m_rawLexems[i+1].first != LABEL) {
|
||||
m_output = "invalid dereference";
|
||||
return false;
|
||||
}
|
||||
uint64_t varLen = m_rawLexems[i+1].second;
|
||||
for (; (m_input[varLen] >= 'a' && m_input[varLen] <= 'z') || (m_input[varLen] >= 'A' && m_input[varLen] <= 'Z'); ++ varLen);
|
||||
varLen -= m_rawLexems[i+1].second;
|
||||
std::string variableName = m_input.substr(m_rawLexems[i+1].second, varLen);
|
||||
auto it = m_variables.find(variableName);
|
||||
if (it == m_variables.end()) {
|
||||
m_output = "unknown variable \"" + variableName + "\"";
|
||||
return false;
|
||||
}
|
||||
CRational *value = new CRational((*it).second);
|
||||
m_processedLexems.emplace_back(NUMBER, value);
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
m_processedLexems.emplace_back(m_rawLexems[i].first, nullptr);
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string CParser::numberToString( CRational *r ) const {
|
||||
std::string ret = r->m_numerator->toString();
|
||||
CBigInt one(1);
|
||||
if (r->m_denominator->cmp(&one))
|
||||
ret += " / " + r->m_denominator->toString();
|
||||
return ret;
|
||||
}
|
||||
|
||||
COperator *CParser::spawnOperator( CParser::TOKEN t ) const {
|
||||
COperator *ret = nullptr;
|
||||
switch (t) {
|
||||
case ADD:
|
||||
ret = new CAddition();
|
||||
break;
|
||||
case SUBTRACT:
|
||||
ret = new CSubtraction();
|
||||
break;
|
||||
case MULTIPLY:
|
||||
ret = new CMultiplication();
|
||||
break;
|
||||
case DIVIDE:
|
||||
ret = new CDivision();
|
||||
break;
|
||||
case MOD:
|
||||
ret = new CModulo();
|
||||
break;
|
||||
case EXP:
|
||||
ret = new CExponencial();
|
||||
break;
|
||||
case LN:
|
||||
ret = new CLogarith();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
CPrintable *CParser::parse( uint64_t &readIndex ) {
|
||||
enum STATE {
|
||||
FIRST_OPERAND,
|
||||
OPERATOR,
|
||||
SECOND_OPERAND
|
||||
};
|
||||
STATE parserState = FIRST_OPERAND;
|
||||
CPrintable *firstOperand = nullptr;
|
||||
// CPrintable *secondOperand = nullptr;
|
||||
COperator *currentOperator = nullptr;
|
||||
COperator *lastOperator = nullptr;
|
||||
uint64_t lastPriority = 0;
|
||||
|
||||
++readIndex; // skip first bracket
|
||||
while (m_processedLexems[readIndex].first != CLOSE) {
|
||||
if (m_processedLexems[readIndex].first == OPEN) {
|
||||
if (parserState == FIRST_OPERAND) {
|
||||
firstOperand = parse(readIndex);
|
||||
} else if (parserState == SECOND_OPERAND) {
|
||||
currentOperator->m_secondArgument.reset( parse(readIndex) );
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
parserState = OPERATOR;
|
||||
++readIndex;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (parserState) {
|
||||
|
||||
case FIRST_OPERAND:
|
||||
if (m_processedLexems[readIndex].first == OPEN) {
|
||||
firstOperand = parse(readIndex);
|
||||
parserState = OPERATOR;
|
||||
break;
|
||||
}
|
||||
if (m_processedLexems[readIndex].first == NUMBER) {
|
||||
firstOperand = m_processedLexems[readIndex].second;
|
||||
m_processedLexems[readIndex].second = nullptr;
|
||||
parserState = OPERATOR;
|
||||
break;
|
||||
}
|
||||
goto fail;
|
||||
|
||||
case OPERATOR:
|
||||
if (m_processedLexems[readIndex].first == CLOSE)
|
||||
goto sucess;
|
||||
|
||||
currentOperator = spawnOperator(m_processedLexems[readIndex].first);
|
||||
if (!currentOperator)
|
||||
goto fail;
|
||||
|
||||
if (lastOperator) {
|
||||
uint64_t thisPriority = getOperatorPriority(m_processedLexems[readIndex].first);
|
||||
|
||||
if (lastPriority <= thisPriority) {
|
||||
currentOperator->m_firstArgument.reset( lastOperator->m_secondArgument.release() );
|
||||
lastOperator->m_secondArgument.reset( currentOperator );
|
||||
} else {
|
||||
currentOperator->m_firstArgument.reset( lastOperator );
|
||||
lastOperator = currentOperator;
|
||||
}
|
||||
} else {
|
||||
lastPriority = getOperatorPriority(m_processedLexems[readIndex].first);
|
||||
lastOperator = currentOperator;
|
||||
lastOperator->m_firstArgument.reset( firstOperand );
|
||||
}
|
||||
parserState = SECOND_OPERAND;
|
||||
break;
|
||||
|
||||
case SECOND_OPERAND:
|
||||
if (m_processedLexems[readIndex].first == OPEN) {
|
||||
currentOperator->m_secondArgument.reset( parse(readIndex) );
|
||||
parserState = OPERATOR;
|
||||
break;
|
||||
}
|
||||
if (m_processedLexems[readIndex].first == NUMBER) {
|
||||
currentOperator->m_secondArgument.reset( m_processedLexems[readIndex].second );
|
||||
m_processedLexems[readIndex].second = nullptr;
|
||||
parserState = OPERATOR;
|
||||
break;
|
||||
}
|
||||
goto fail;
|
||||
break;
|
||||
}
|
||||
++readIndex;
|
||||
}
|
||||
|
||||
sucess:
|
||||
if ((currentOperator && (!currentOperator->m_firstArgument.get() || !currentOperator->m_secondArgument.get())) ||
|
||||
(lastOperator && (!lastOperator->m_firstArgument.get() || !lastOperator->m_secondArgument.get())))
|
||||
throw std::logic_error("parsing failed");
|
||||
if (lastOperator)
|
||||
return lastOperator;
|
||||
if (firstOperand)
|
||||
return firstOperand;
|
||||
|
||||
fail:
|
||||
throw std::logic_error("parsing failed");
|
||||
}
|
||||
|
||||
void CParser::convert( const std::string &s ) {
|
||||
clear();
|
||||
m_input = s;
|
||||
if (!tokenize())
|
||||
return;
|
||||
if (!grammarPreprocess())
|
||||
return;
|
||||
uint64_t readPos = 2;
|
||||
CMD command = parseCommand(readPos);
|
||||
if (command != NONE_CMD && !m_saveInto.empty())
|
||||
return;
|
||||
if (!executeCommand( command ))
|
||||
return;
|
||||
|
||||
try {
|
||||
m_head.reset( parse( readPos ) );
|
||||
} catch (const std::exception &e) {
|
||||
m_output = "Caught exception: " + std::string(e.what());
|
||||
return;
|
||||
} catch (...) {
|
||||
m_output = "Caught unknown exception";
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_processedLexems[++readPos].first != END) {
|
||||
m_output = "bad parenthesis parity";
|
||||
return;
|
||||
}
|
||||
if (!m_head.get()) {
|
||||
m_output = "parsing failed";
|
||||
return;
|
||||
}
|
||||
try {
|
||||
auto evaluated = m_head->evaluate();
|
||||
|
||||
m_output = numberToString(evaluated);
|
||||
auto ans = m_variables.find("ans");
|
||||
(*ans).second.m_numerator.reset( evaluated->m_numerator.release() );
|
||||
(*ans).second.m_denominator.reset( evaluated->m_denominator.release() );
|
||||
|
||||
if (!m_saveInto.empty()) {
|
||||
auto var = m_variables.find(m_saveInto);
|
||||
|
||||
if (var == m_variables.end()) {
|
||||
var = m_variables.emplace(m_saveInto, CRational( new CBigInt(0) )).first;
|
||||
}
|
||||
(*var).second.m_numerator.reset( new CBigInt( *(*ans).second.m_numerator.get() ));
|
||||
(*var).second.m_denominator.reset( new CBigInt( *(*ans).second.m_denominator.get() ));
|
||||
}
|
||||
delete evaluated;
|
||||
} catch (const std::exception &e) {
|
||||
m_output = "Caught exception: " + std::string(e.what());
|
||||
} catch (...) {
|
||||
m_output = "Caught unknown exception";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,237 @@
|
|||
#include "../include/rational.hpp"
|
||||
// #include "bigint.cpp"
|
||||
|
||||
uint64_t CRational::termPrecision = 4;
|
||||
CRational::CRational( CBigInt *num, CBigInt *den )
|
||||
: m_numerator(num), m_denominator(den) {}
|
||||
CRational::CRational( CBigInt *num )
|
||||
: m_numerator(num), m_denominator( new CBigInt(1) ) {}
|
||||
CRational::CRational( const CRational &parent )
|
||||
: m_numerator( std::make_unique<CBigInt>( *parent.m_numerator.get() )),
|
||||
m_denominator( std::make_unique<CBigInt>( *parent.m_denominator.get() )) {}
|
||||
CRational::~CRational() {}
|
||||
|
||||
std::string CRational::toString() {
|
||||
simplify();
|
||||
return /*((m_denominator->m_negative ^ m_numerator->m_negative) ? "-" : "") + */
|
||||
(m_numerator->toString() + " / " + m_denominator->toString());
|
||||
}
|
||||
|
||||
CRational *CRational::evaluate() {
|
||||
simplify();
|
||||
if (m_denominator->isZero())
|
||||
throw std::logic_error("division by zero");
|
||||
auto ret = new CRational(*this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
CRational *CRational::add( CRational *oth ) {
|
||||
setSameDenominator(oth);
|
||||
CRational *ret = new CRational( m_numerator->add(oth->m_numerator.get()), new CBigInt(*m_denominator.get()) );
|
||||
ret->simplify();
|
||||
return ret;
|
||||
}
|
||||
|
||||
CRational *CRational::sub( CRational *oth ) {
|
||||
setSameDenominator(oth);
|
||||
auto tmp = m_numerator->sub(oth->m_numerator.get());
|
||||
CRational *ret = new CRational( tmp, new CBigInt(*m_denominator.get()) );
|
||||
ret->simplify();
|
||||
return ret;
|
||||
}
|
||||
|
||||
CRational *CRational::mul( CRational *oth ) {
|
||||
auto ret = new CRational(m_numerator->mul(oth->m_numerator.get()), m_denominator->mul(oth->m_denominator.get()));
|
||||
ret->simplify();
|
||||
return ret;
|
||||
}
|
||||
|
||||
CRational *CRational::div( CRational *oth ) {
|
||||
std::unique_ptr<CRational> inverse( new CRational( new CBigInt(*oth->m_denominator.get()), new CBigInt(*oth->m_numerator.get()) ) );
|
||||
auto ret = mul( inverse.get() );
|
||||
ret->simplify();
|
||||
return ret;
|
||||
}
|
||||
|
||||
CRational *CRational::power( uint64_t pow ) {
|
||||
CRational *ret = new CRational( m_numerator->power(pow), m_denominator->power(pow) );
|
||||
ret->simplify();
|
||||
return ret;
|
||||
}
|
||||
|
||||
CRational *CRational::term( uint64_t pow ) { // term for taylor series
|
||||
CRational *numerator = power(pow);
|
||||
CRational denominator( new CBigInt(pow), new CBigInt(1) );
|
||||
CRational *ret = numerator->div(&denominator);
|
||||
delete numerator;
|
||||
return ret;
|
||||
}
|
||||
|
||||
CRational *CRational::ln() {
|
||||
if (m_numerator->isZero() || isNegative())
|
||||
throw "ln of nonpositive number";
|
||||
|
||||
if (m_numerator->cmp(m_denominator.get()) < 1) {
|
||||
std::unique_ptr<CRational> ret( new CRational( new CBigInt(0) ));
|
||||
CRational *tmp = new CRational(new CBigInt(1));
|
||||
std::unique_ptr<CRational> numerator( sub( tmp ));
|
||||
delete tmp;
|
||||
bool sign = false; // false: +, true: -
|
||||
|
||||
for (uint64_t i = 1; i <= termPrecision; ++i) {
|
||||
std::unique_ptr<CRational> currentTerm( numerator->power(i) );
|
||||
CRational *tmp = new CRational( new CBigInt(i) );
|
||||
currentTerm.reset( currentTerm->div( tmp ));
|
||||
delete tmp;
|
||||
if (sign)
|
||||
currentTerm->negate();
|
||||
ret.reset( ret->add(currentTerm.get()) );
|
||||
ret->simplify();
|
||||
sign ^= 1;
|
||||
}
|
||||
|
||||
return ret.release();
|
||||
} else {
|
||||
// Calculate the base for logarithm
|
||||
CRational base( m_numerator->mod(m_denominator.get()), new CBigInt( *m_denominator.get() ));
|
||||
CRational ln2( new CBigInt(3552463), new CBigInt(5125120) ); //https://scipp.ucsc.edu/~haber/webpage/Log2.pdf
|
||||
|
||||
// find highest numerator bit
|
||||
m_numerator->optimize();
|
||||
int64_t numeratorBits = ((m_numerator->m_data.size() - 1) * CHUNK_BITS );
|
||||
if (m_numerator->m_data.size())
|
||||
numeratorBits += ( 64 - __builtin_clzll(m_numerator->m_data[m_numerator->m_data.size() - 1]) );
|
||||
CRational expoN( new CBigInt(numeratorBits), new CBigInt(1));
|
||||
|
||||
std::unique_ptr<CRational> ret(new CRational(new CBigInt(0)));
|
||||
std::unique_ptr<CRational> numerator(new CRational(base));
|
||||
|
||||
//taylor series for |x-1| <= 1
|
||||
bool sign = false; // false: +, true: -
|
||||
|
||||
// Taylor series expansion
|
||||
for (uint64_t i = 1; i <= termPrecision; ++i) {
|
||||
std::unique_ptr<CRational> currentTerm( numerator->power(i) );
|
||||
CRational *tmp = new CRational(new CBigInt(i));
|
||||
currentTerm.reset( currentTerm->div(tmp) );
|
||||
delete tmp;
|
||||
if (sign)
|
||||
currentTerm->negate();
|
||||
|
||||
ret.reset(ret->add(currentTerm.get()));
|
||||
ret->simplify();
|
||||
sign ^= 1;
|
||||
}
|
||||
|
||||
CRational *tmp = ln2.mul( &expoN );
|
||||
ret.reset( ret->add( tmp ));
|
||||
delete tmp;
|
||||
return ret.release();
|
||||
}
|
||||
}
|
||||
|
||||
CRational *CRational::exp() {
|
||||
// e^(a/b) = lim n->inf (1+(a/b)/n)^n = lim n->inf ((bn*a)/bn)^n
|
||||
CBigInt *num = m_denominator->mul( new CBigInt(termPrecision) );
|
||||
CBigInt *den = new CBigInt(*num);
|
||||
num->addDestructive(m_numerator.get());
|
||||
|
||||
std::unique_ptr<CRational> ret (new CRational( num, den ));
|
||||
ret->simplify();
|
||||
|
||||
ret.reset( ret->power(termPrecision) );
|
||||
return ret.release();
|
||||
}
|
||||
|
||||
std::string CRational::round( uint64_t decimals ) {
|
||||
std::string ret;
|
||||
if (m_denominator->m_data.size() <= 2 &&
|
||||
m_numerator->m_data.size() <= 2) {
|
||||
m_numerator->m_data.push_back(0);
|
||||
m_denominator->m_data.push_back(0);
|
||||
ret = std::to_string( *((double *)m_numerator->m_data.data())
|
||||
/ *((double *)m_denominator->m_data.data()));
|
||||
size_t dotPosition = ret.find('.');
|
||||
if (dotPosition != std::string::npos)
|
||||
ret = ret.substr(0, dotPosition + decimals + 1);
|
||||
m_numerator->m_data.pop_back();
|
||||
m_denominator->m_data.pop_back();
|
||||
return ret;
|
||||
}
|
||||
throw std::length_error("too long to round");
|
||||
|
||||
CRational tmp(*this);
|
||||
CBigInt newDen(std::pow(10, decimals));
|
||||
int dif = m_denominator->cmp(&newDen);
|
||||
|
||||
if (dif > 0) {
|
||||
CBigInt *factor = tmp.m_denominator->div(&newDen);
|
||||
tmp.m_numerator.reset( tmp.m_numerator->div(factor) );
|
||||
delete factor;
|
||||
}
|
||||
if (dif < 0) {
|
||||
CBigInt *factor = newDen.div(tmp.m_denominator.get());
|
||||
tmp.m_numerator.reset( tmp.m_numerator->mul(factor) );
|
||||
delete factor;
|
||||
}
|
||||
ret = tmp.m_numerator->toString();
|
||||
if ((ret.size() - decimals) > 0)
|
||||
ret.insert( ret.size() - decimals, 1, ',' );
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CRational::setSameDenominator( CRational *oth ) {
|
||||
if (m_denominator->cmp(oth->m_denominator.get()) == 0)
|
||||
return true;
|
||||
|
||||
if ( m_numerator == 0 ) {
|
||||
m_denominator.reset( new CBigInt( *oth->m_denominator.get() ));
|
||||
return true;
|
||||
}
|
||||
if ( oth->m_numerator == 0 ) {
|
||||
oth->m_denominator.reset( new CBigInt( *m_denominator.get() ));
|
||||
return true;
|
||||
}
|
||||
std::unique_ptr<CBigInt> lcm( m_denominator->lcm(oth->m_denominator.get()) );
|
||||
std::unique_ptr<CBigInt> thisCoef( lcm->div(m_denominator.get()));
|
||||
std::unique_ptr<CBigInt> othCoef( lcm->div(oth->m_denominator.get()));
|
||||
|
||||
m_denominator.reset( m_denominator->mul(thisCoef.get()) );
|
||||
m_numerator.reset( m_numerator ->mul(thisCoef.get()) );
|
||||
|
||||
|
||||
oth->m_denominator.reset( oth->m_denominator->mul(othCoef.get()) );
|
||||
oth->m_numerator.reset( oth->m_numerator ->mul(othCoef.get()) );
|
||||
return true;
|
||||
}
|
||||
|
||||
void CRational::simplify() {
|
||||
if (m_numerator == nullptr)
|
||||
return;
|
||||
|
||||
std::unique_ptr<CBigInt> gcd( m_numerator->gcd(m_denominator.get()) );
|
||||
m_numerator.reset( m_numerator->div(gcd.get()) );
|
||||
m_denominator.reset( m_denominator->div(gcd.get()) );
|
||||
|
||||
m_numerator->m_negative = isNegative();
|
||||
m_denominator->m_negative = false;
|
||||
return;
|
||||
}
|
||||
|
||||
inline int64_t CRational::intfactorial( uint64_t i ) {
|
||||
int64_t ret = 1;
|
||||
for ( uint64_t j = 0; j < i; ret *= ++j);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CRational::isNegative() const {
|
||||
return m_numerator->m_negative ^ m_denominator->m_negative;
|
||||
}
|
||||
|
||||
void CRational::negate() {
|
||||
m_numerator->m_negative = !m_numerator->m_negative;
|
||||
}
|
||||
|
||||
double CRational::debugDump() {
|
||||
return (double) m_numerator->debugDump() / (double) m_denominator->debugDump();
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
#include "../include/saver.hpp"
|
||||
|
||||
CSaver::CSaver(std::map<std::string, CRational> &variablesMap)
|
||||
: m_variables(variablesMap) {}
|
|
@ -0,0 +1,9 @@
|
|||
#include "../include/rational.hpp"
|
||||
#include "../include/subtraction.hpp"
|
||||
|
||||
CSubtraction::CSubtraction( CPrintable *a, CPrintable *b ) : COperator(a, b) {}
|
||||
CRational *CSubtraction::evaluate() {
|
||||
std::unique_ptr<CRational> a (m_firstArgument->evaluate());
|
||||
std::unique_ptr<CRational> b (m_secondArgument->evaluate());
|
||||
return a->sub(b.get());
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
#include "../include/textsaver.hpp"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <cctype>
|
||||
|
||||
CTextsaver::CTextsaver(std::map<std::string, CRational> &variablesMap) : CSaver(variablesMap) {}
|
||||
|
||||
CTextsaver::~CTextsaver() {}
|
||||
|
||||
bool CTextsaver::save(const std::string& fileName) {
|
||||
ssize_t variableCount = m_variables.size();
|
||||
// ssize_t fileHash = 0;
|
||||
// uint64_t hashWord;
|
||||
|
||||
std::ofstream ofs(fileName);
|
||||
if (!ofs || !ofs.good())
|
||||
return false;
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
// write variable count
|
||||
ss << std::to_string(variableCount) + "\n";
|
||||
|
||||
// write variables
|
||||
for (auto& i : m_variables) {
|
||||
ss << i.first + " " + i.second.toString() + "\n";
|
||||
}
|
||||
|
||||
// calculate file hash
|
||||
// std::stringstream hashSS(ss.str());
|
||||
// while (hashSS.read(reinterpret_cast<char*>(&hashWord), sizeof(hashWord))) {
|
||||
// fileHash ^= hashWord;
|
||||
// }
|
||||
// ss << "hash " + std::to_string(fileHash);
|
||||
|
||||
ofs << ss.rdbuf();
|
||||
ofs.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CTextsaver::load( const std::string &fileName ) {
|
||||
ssize_t variableCount;
|
||||
|
||||
std::ifstream ifs(fileName);
|
||||
if (!ifs || !ifs.good()) {
|
||||
m_log = "file reading error";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string buffer;
|
||||
std::getline( ifs, buffer );
|
||||
|
||||
// check if variable count is valid
|
||||
if (buffer.size() < 1 || buffer.size() > 10 || !(std::all_of(buffer.begin(), buffer.end(),
|
||||
[](unsigned char ch) { return std::isdigit(ch); }) )) {
|
||||
ifs.close();
|
||||
m_log = "invalid argument count";
|
||||
return false;
|
||||
}
|
||||
|
||||
variableCount = std::stoll(buffer);
|
||||
if (variableCount < 0) {
|
||||
ifs.close();
|
||||
m_log = "invalid argument count";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (;variableCount && std::getline(ifs, buffer); --variableCount) {
|
||||
std::istringstream iss(buffer);
|
||||
std::string varName;
|
||||
std::string numStr;
|
||||
std::string denStr;
|
||||
std::string slash;
|
||||
bool numSign = 0;
|
||||
bool denSign = 0;
|
||||
|
||||
if (!(iss >> varName >> numStr >> slash >> denStr) || slash != "/") {
|
||||
ifs.close();
|
||||
m_log = "wrong format";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (numStr.at(0) == '-') {
|
||||
numSign = 1;
|
||||
numStr = numStr.substr(1);
|
||||
}
|
||||
if (denStr.at(0) == '-') {
|
||||
denSign = 1;
|
||||
denStr = denStr.substr(1);
|
||||
}
|
||||
|
||||
if (!(std::all_of(numStr.begin(), numStr.end(), [](unsigned char ch) { return std::isdigit(ch); }) )
|
||||
|| !(std::all_of(denStr.begin(), denStr.end(), [](unsigned char ch) { return std::isdigit(ch); }) )) {
|
||||
ifs.close();
|
||||
m_log = "invalid number";
|
||||
return false;
|
||||
}
|
||||
|
||||
for ( auto &c : numStr)
|
||||
c -= 48;
|
||||
for ( auto &c : denStr)
|
||||
c -= 48;
|
||||
|
||||
CBigInt *num = new CBigInt(0);
|
||||
uint64_t insertPosition = 0;
|
||||
while (!std::all_of(numStr.begin(), numStr.end(), [](char c) { return c == 0; })) {
|
||||
num->setBit(insertPosition++, CParser::stringDivideDecimal(numStr));
|
||||
}
|
||||
|
||||
CBigInt *den = new CBigInt(0);
|
||||
insertPosition = 0;
|
||||
while (!std::all_of(denStr.begin(), denStr.end(), [](char c) { return c == 0; })) {
|
||||
den->setBit(insertPosition++, CParser::stringDivideDecimal(denStr));
|
||||
}
|
||||
|
||||
num->m_negative = numSign;
|
||||
den->m_negative = denSign;
|
||||
if (!m_variables.emplace(varName, CRational(num, den)).second) {
|
||||
// delete num;
|
||||
// delete den;
|
||||
// ifs.close();
|
||||
// m_log = "varable already exists";
|
||||
// return false;
|
||||
}
|
||||
}
|
||||
ifs.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
#textsaveformat
|
||||
##header
|
||||
[varible count]
|
||||
|
||||
##one variable
|
||||
[identif] [whitespace] [textdata]
|
||||
|
||||
##padding whitespaces to 8byte multiply
|
||||
[0x0000]
|
||||
|
||||
// [64bit hash in text]
|
||||
// ##hash
|
||||
// xor all 64bit chunks
|
||||
*/
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
#include "rational.hpp"
|
||||
#include "operator.hpp"
|
||||
|
||||
/**
|
||||
* @class CAddition
|
||||
* @brief The CAddition class represents the addition operator.
|
||||
* It inherits from the COperator class.
|
||||
*/
|
||||
class CAddition : public COperator {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor for CAddition class.
|
||||
* @param a The first argument of the addition operation.
|
||||
* @param b The second argument of the addition operation.
|
||||
*/
|
||||
CAddition( CPrintable *a, CPrintable *b );
|
||||
|
||||
/**
|
||||
* @brief Default constructor for CAddition class.
|
||||
*/
|
||||
CAddition() = default;
|
||||
|
||||
/**
|
||||
* @brief Destructor for CAddition class.
|
||||
*/
|
||||
~CAddition() = default;
|
||||
|
||||
/**
|
||||
* @brief Evaluates the addition operation.
|
||||
* @return A CRational pointer representing the result of the addition.
|
||||
*/
|
||||
virtual CRational *evaluate() override;
|
||||
private:
|
||||
};
|
|
@ -0,0 +1,202 @@
|
|||
#pragma once
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#define CHUNK_TYPE uint32_t
|
||||
#define CHUNK_BYTES sizeof(CHUNK_TYPE)
|
||||
#define CHUNK_BITS (CHUNK_BYTES * 8)
|
||||
#define CHUNK_MAX UINT32_MAX
|
||||
|
||||
/**
|
||||
* @class CBigInt
|
||||
* @brief Class representing a big integer.
|
||||
*/
|
||||
class CBigInt {
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor.
|
||||
*/
|
||||
CBigInt();
|
||||
|
||||
/**
|
||||
* @brief Constructor that initializes the integer with a given value.
|
||||
* @param parent The value to initialize the integer with.
|
||||
*/
|
||||
CBigInt( int64_t parent );
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param oth The CBigInt object to copy.
|
||||
*/
|
||||
CBigInt( const CBigInt &oth );
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
~CBigInt();
|
||||
|
||||
/**
|
||||
* @brief Prints the big integer for debugging purposes.
|
||||
*/
|
||||
void debugPrint();
|
||||
|
||||
/**
|
||||
* @brief Dumps first 63bits and sign for debugging purposes.
|
||||
* @return The dumped value of the big integer.
|
||||
*/
|
||||
int64_t debugDump();
|
||||
|
||||
/**
|
||||
* @brief Converts the big integer to a string representation.
|
||||
* @return The string representation of the big integer.
|
||||
*/
|
||||
std::string toString() const;
|
||||
|
||||
/**
|
||||
* @brief Adds another big integer to this big integer.
|
||||
* @param oth The big integer to add.
|
||||
* @return A new big integer representing the sum.
|
||||
*/
|
||||
CBigInt *add( const CBigInt *oth ) const;
|
||||
|
||||
/**
|
||||
* @brief Subtracts another big integer from this big integer.
|
||||
* @param oth The big integer to subtract.
|
||||
* @return A new big integer representing the difference.
|
||||
*/
|
||||
CBigInt *sub( const CBigInt *oth ) const;
|
||||
|
||||
/**
|
||||
* @brief Multiplies another big integer with this big integer.
|
||||
* @param oth The big integer to multiply.
|
||||
* @return A new big integer representing the product.
|
||||
*/
|
||||
CBigInt *mul( const CBigInt *oth ) const;
|
||||
|
||||
/**
|
||||
* @brief Divides this big integer by another big integer.
|
||||
* uses divmod()
|
||||
* @param oth The divisor big integer.
|
||||
* @return A new big integer representing the quotient.
|
||||
*/
|
||||
CBigInt *div( const CBigInt *oth ) const;
|
||||
|
||||
/**
|
||||
* @brief Divides this big integer by another big integer.
|
||||
* uses divmod()
|
||||
* @param oth The divisor big integer.
|
||||
* @return A new big integer representing the quotient.
|
||||
*/
|
||||
CBigInt *mod( const CBigInt *oth ) const;
|
||||
|
||||
/**
|
||||
* @brief Calculates the greatest common divisor of the current big integer and another big integer.
|
||||
* uses rea()
|
||||
* @param oth The other big integer.
|
||||
* @return A new CBigInt object representing the greatest common divisor.
|
||||
*/
|
||||
CBigInt *gcd( const CBigInt *oth ) const;
|
||||
|
||||
/**
|
||||
* @brief Calculates the least common multiple of the current big integer and another big integer.
|
||||
* uses rea()
|
||||
* @param oth The other big integer.
|
||||
* @return A new CBigInt object representing the least common multiple.
|
||||
*/
|
||||
CBigInt *lcm( const CBigInt *oth ) const;
|
||||
|
||||
/**
|
||||
* @brief Performs a left shift operation on the current big integer.
|
||||
* @param shift The number of bits to shift.
|
||||
* @return A new CBigInt object representing the shifted big integer.
|
||||
*/
|
||||
CBigInt *shf( int64_t shift ) const;
|
||||
|
||||
/**
|
||||
* @brief Calculates the power of the current big integer raised to a given exponent.
|
||||
* @param pow The exponent.
|
||||
* @return A new CBigInt object representing the result of the power operation.
|
||||
*/
|
||||
CBigInt *power( uint64_t pow ) const;
|
||||
|
||||
/**
|
||||
* @brief Adds another big integer destructively to the current big integer.
|
||||
* @param oth The other big integer to be added.
|
||||
* @return A boolean indicating the success of the addition operation.
|
||||
*/
|
||||
bool addDestructive( CBigInt *oth );
|
||||
|
||||
/**
|
||||
* @brief Subtracts another big integer destructively from the current big integer.
|
||||
* @param oth The other big integer to be subtracted.
|
||||
* @return A boolean indicating the success of the subtraction operation.
|
||||
*/
|
||||
bool subDestructive( CBigInt *oth );
|
||||
|
||||
/**
|
||||
* @brief Pushes a bit to the left of the big integer.
|
||||
* @param i The bit to push to the left.
|
||||
* @return A boolean indicating the success of the push operation.
|
||||
*/
|
||||
bool pushLeft( bool i );
|
||||
|
||||
/**
|
||||
* @brief Gets the value of a specific bit at index i in the big integer.
|
||||
* @param i The index of the bit to retrieve.
|
||||
* @return The value of the bit at index i, or false if the index is out of range.
|
||||
*/
|
||||
bool getBit( uint64_t i) const ;
|
||||
|
||||
/**
|
||||
* @brief Sets the value of a specific bit at index i in the big integer.
|
||||
* @param i The index of the bit to set.
|
||||
* @param b The value to set the bit to (true or false).
|
||||
* @return A boolean indicating the success of the bit setting operation.
|
||||
*/
|
||||
bool setBit( uint64_t i, bool b);
|
||||
|
||||
/**
|
||||
* @brief Compares the current big integer with another big integer.
|
||||
* @param oth The other big integer to compare with.
|
||||
* @return An integer representing the comparison result: 0 if the numbers are equal, a negative value if the current number is smaller, and a positive value if the current number is larger.
|
||||
*/
|
||||
int cmp( const CBigInt *oth ) const ;
|
||||
|
||||
/**
|
||||
* @brief Optimizes the big integer by removing leading zero chunks.
|
||||
* @return A boolean indicating the success of the optimization operation.
|
||||
*/
|
||||
bool optimize( void );
|
||||
|
||||
/**
|
||||
* @brief Checks if the big integer is zero.
|
||||
* @return A boolean indicating whether the big integer is zero (true) or not (false).
|
||||
*/
|
||||
bool isZero( void ) const ;
|
||||
|
||||
/**
|
||||
* @brief Divides the current big integer by another big integer and calculates the remainder.
|
||||
* @param oth The divisor big integer.
|
||||
* @return A pair of CBigInt objects representing the quotient and remainder of the division.
|
||||
*/
|
||||
std::pair<CBigInt *, CBigInt *> divmod( const CBigInt *oth ) const;
|
||||
|
||||
/**
|
||||
* @brief Computes the GCD and LCM of two big integers.
|
||||
* @param oth The big integer to compute GCD and LCM with.
|
||||
* @return A pair of CBigInt pointers, representing the GCD and LCM respectively.
|
||||
*/
|
||||
std::pair<CBigInt *, CBigInt *> rea( const CBigInt *oth ) const;
|
||||
|
||||
/**
|
||||
* @brief Holds the chunks of the big integer's data.
|
||||
*/
|
||||
std::vector<CHUNK_TYPE> m_data;
|
||||
|
||||
/**
|
||||
* @brief Indicates whether the big integer is negative.
|
||||
*/
|
||||
bool m_negative;
|
||||
};
|
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
#include "../include/saver.hpp"
|
||||
#include "../include/parser.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <cctype>
|
||||
|
||||
class CBinsaver : public CSaver {
|
||||
private:
|
||||
/* data */
|
||||
public:
|
||||
CBinsaver(std::map<std::string, CRational> &variablesMap);
|
||||
~CBinsaver();
|
||||
|
||||
virtual bool save( const std::string &s ) override;
|
||||
virtual bool load( const std::string &s ) override;
|
||||
};
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
#include "rational.hpp"
|
||||
#include "operator.hpp"
|
||||
|
||||
/**
|
||||
* @class CDivision
|
||||
* @brief The CDivision class represents the division operator.
|
||||
* It inherits from the COperator class.
|
||||
*/
|
||||
class CDivision : public COperator {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor for CDivision class.
|
||||
* @param a The numerator of the division operation.
|
||||
* @param b The denominator of the division operation.
|
||||
*/
|
||||
CDivision( CPrintable *a, CPrintable *b );
|
||||
|
||||
/**
|
||||
* @brief Default constructor for CDivision class.
|
||||
*/
|
||||
CDivision() = default;
|
||||
|
||||
/**
|
||||
* @brief Destructor for CDivision class.
|
||||
*/
|
||||
~CDivision() = default;
|
||||
|
||||
/**
|
||||
* @brief Evaluates the division operation.
|
||||
* @return A CRational pointer representing the result of the division.
|
||||
*/
|
||||
virtual CRational *evaluate() override;
|
||||
private:
|
||||
};
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
#include "rational.hpp"
|
||||
#include "operator.hpp"
|
||||
|
||||
/**
|
||||
* @class CExponencial
|
||||
* @brief The CExponencial class represents an exponential operation.
|
||||
* It inherits from the COperator class.
|
||||
*/
|
||||
class CExponencial : public COperator {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor for CExponencial class.
|
||||
* @param a The base of the exponential operation.
|
||||
* @param b The exponent of the exponential operation.
|
||||
*/
|
||||
CExponencial( CPrintable *a, CPrintable *b );
|
||||
|
||||
/**
|
||||
* @brief Default constructor for CExponencial class.
|
||||
*/
|
||||
CExponencial() = default;
|
||||
|
||||
/**
|
||||
* @brief Destructor for CExponencial class.
|
||||
*/
|
||||
~CExponencial() = default;
|
||||
|
||||
/**
|
||||
* @brief Evaluates the exponential operation.
|
||||
* @return A CRational pointer representing the result of the exponential operation.
|
||||
*/
|
||||
virtual CRational *evaluate() override;
|
||||
private:
|
||||
};
|
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
#include "rational.hpp"
|
||||
#include "operator.hpp"
|
||||
|
||||
/**
|
||||
* @brief The CLogarith class represents a logarithm operation.
|
||||
* It inherits from the COperator class.
|
||||
*/
|
||||
class CLogarith : public COperator {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor for CLogarith class.
|
||||
* @param a The base of the logarithm operation.
|
||||
* @param b The argument of the logarithm operation.
|
||||
*/
|
||||
CLogarith( CPrintable *a, CPrintable *b );
|
||||
|
||||
/**
|
||||
* @brief Default constructor for CLogarith class.
|
||||
*/
|
||||
CLogarith() = default;
|
||||
|
||||
/**
|
||||
* @brief Destructor for CLogarith class.
|
||||
*/
|
||||
~CLogarith() = default;
|
||||
|
||||
/**
|
||||
* @brief Evaluates the logarithm operation.
|
||||
* @return A CRational pointer representing the result of the logarithm operation.
|
||||
*/
|
||||
virtual CRational *evaluate() override;
|
||||
private:
|
||||
};
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
#include "rational.hpp"
|
||||
#include "operator.hpp"
|
||||
|
||||
/**
|
||||
* @brief The CModulo class represents a modulo operation.
|
||||
* It inherits from the COperator class.
|
||||
*/
|
||||
class CModulo : public COperator {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor for CModulo class.
|
||||
* @param a The first argument of the modulo operation.
|
||||
* @param b The second argument of the modulo operation.
|
||||
*/
|
||||
CModulo( CPrintable *a, CPrintable *b );
|
||||
|
||||
/**
|
||||
* @brief Default constructor for CModulo class.
|
||||
*/
|
||||
CModulo() = default;
|
||||
|
||||
/**
|
||||
* @brief Destructor for CModulo class.
|
||||
*/
|
||||
~CModulo() = default;
|
||||
|
||||
/**
|
||||
* @brief Evaluates the modulo operation.
|
||||
* @return A CRational pointer representing the result of the modulo operation.
|
||||
* @throws An exception if the modulo operation is applied to rationals.
|
||||
*/
|
||||
virtual CRational *evaluate() override;
|
||||
private:
|
||||
};
|
|
@ -0,0 +1,36 @@
|
|||
#pragma once
|
||||
#include "rational.hpp"
|
||||
#include "operator.hpp"
|
||||
|
||||
/**
|
||||
* @brief The CMultiplication class represents a multiplication operation.
|
||||
* It inherits from the COperator class.
|
||||
*/
|
||||
class CMultiplication : public COperator {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor for CMultiplication class.
|
||||
* @param a The first argument of the multiplication operation.
|
||||
* @param b The second argument of the multiplication operation.
|
||||
*/
|
||||
CMultiplication( CPrintable *a, CPrintable *b );
|
||||
|
||||
/**
|
||||
* @brief Default constructor for CMultiplication class.
|
||||
*/
|
||||
CMultiplication() = default;
|
||||
|
||||
/**
|
||||
* @brief Destructor for CMultiplication class.
|
||||
*/
|
||||
~CMultiplication() = default;
|
||||
|
||||
/**
|
||||
* @brief Evaluates the multiplication operation.
|
||||
* @return A CRational pointer representing the result of the multiplication operation.
|
||||
*/
|
||||
virtual CRational *evaluate() override;
|
||||
|
||||
private:
|
||||
};
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
#include "printable.hpp"
|
||||
|
||||
/**
|
||||
* @brief The COperator class represents an abstract operator.
|
||||
* It inherits from the CPrintable class.
|
||||
*/
|
||||
class COperator : public CPrintable {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor for COperator class.
|
||||
* @param a The first argument of the operator.
|
||||
* @param b The second argument of the operator.
|
||||
*/
|
||||
COperator( CPrintable *a, CPrintable *b );
|
||||
|
||||
/**
|
||||
* @brief Default constructor for COperator class.
|
||||
*/
|
||||
COperator() = default;
|
||||
|
||||
/**
|
||||
* @brief Default destructor for COperator class.
|
||||
*/
|
||||
virtual ~COperator() = default;
|
||||
|
||||
/**
|
||||
* @brief Evaluates the operands and then itself.
|
||||
* @return A CRational pointer representing the result of the operator.
|
||||
*/
|
||||
virtual CRational *evaluate() = 0;
|
||||
|
||||
// protected:
|
||||
/**
|
||||
* @brief The first argument of the operator.
|
||||
*/
|
||||
std::unique_ptr<CPrintable> m_firstArgument;
|
||||
|
||||
/**
|
||||
* @brief The second argument of the operator.
|
||||
*/
|
||||
std::unique_ptr<CPrintable> m_secondArgument;
|
||||
};
|
|
@ -0,0 +1,217 @@
|
|||
#pragma once
|
||||
#include "../include/rational.hpp"
|
||||
#include "../include/operator.hpp"
|
||||
#include "../include/binsaver.hpp"
|
||||
#include "../include/textsaver.hpp"
|
||||
|
||||
#include "../include/addition.hpp"
|
||||
#include "../include/subtraction.hpp"
|
||||
#include "../include/multiplication.hpp"
|
||||
#include "../include/division.hpp"
|
||||
#include "../include/modulo.hpp"
|
||||
#include "../include/exponencial.hpp"
|
||||
#include "../include/logarithm.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <iterator>
|
||||
#include <cctype>
|
||||
//https://www.wikiwand.com/en/Lexical_analysis
|
||||
//https://courses.fit.cvut.cz/BI-AAG/lectures/bi-aag-07-bezkontextove_gramatiky.pdf
|
||||
|
||||
/**
|
||||
* @class CParser
|
||||
* @brief Singleton class responsible for converting input into results.
|
||||
*/
|
||||
class CParser {
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor for CParser class.
|
||||
*/
|
||||
CParser ();
|
||||
|
||||
/**
|
||||
* @brief Destructor for CParser class. Clears the parser data.
|
||||
*/
|
||||
~CParser();
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* @brief Clear the parser data.
|
||||
*/
|
||||
void clear();
|
||||
void convert( const std::string &s );
|
||||
|
||||
/**
|
||||
* @brief Divide a decimal string by 2 and return the next bit for binary conversion.
|
||||
*
|
||||
* @param s The decimal string to be divided.
|
||||
* @return The next bit for binary conversion.
|
||||
*/
|
||||
static bool stringDivideDecimal( std::string &s );
|
||||
|
||||
bool m_continue;
|
||||
std::string m_output;
|
||||
private:
|
||||
enum TOKEN { //by priority
|
||||
START,
|
||||
END,
|
||||
NUMBER,
|
||||
LABEL,
|
||||
COMMAND, //.!
|
||||
DEREFERENCE, // $
|
||||
OPEN, // (
|
||||
CLOSE, // )
|
||||
LN, // &
|
||||
EXP, // ^
|
||||
DIVIDE, // /
|
||||
MULTIPLY, //.*
|
||||
MOD, // %
|
||||
ADD, // +
|
||||
SUBTRACT, // -
|
||||
SAVE, // =
|
||||
DOT,
|
||||
WHITESPACE,
|
||||
SYNTAX_ERROR
|
||||
};
|
||||
|
||||
enum CMD {
|
||||
QUIT_CMD,
|
||||
LOAD_CMD,
|
||||
SAVE_CMD,
|
||||
PRECISSION_CMD,
|
||||
HELP_CMD,
|
||||
ROUND_CMD,
|
||||
UNKNOWN_CMD,
|
||||
NONE_CMD
|
||||
};
|
||||
|
||||
CParser::CMD recognizeCommand( uint64_t commandPos ) const;
|
||||
|
||||
CParser::CMD parseCommand( uint64_t &startPos ) const;
|
||||
|
||||
bool executeCommand( CParser::CMD cmd );
|
||||
|
||||
/**
|
||||
* @brief Tokenize the input string.
|
||||
*
|
||||
* This function analyzes the input string and breaks it down into lexemes,
|
||||
* classifying each lexeme into different types such as whitespace, number, label,
|
||||
* command, or operators.
|
||||
*
|
||||
* @return True if tokenization is successful, false otherwise.
|
||||
*/
|
||||
bool tokenize();
|
||||
|
||||
/**
|
||||
* @brief Perform grammar preprocessing on the raw lexemes.
|
||||
*
|
||||
* This function strips whitespaces from the raw lexemes and processes numbers
|
||||
* by creating rational numbers and handling various cases such as decimals,
|
||||
* signs, and dereferencing variables.
|
||||
*
|
||||
* @return True if grammar preprocessing is successful, false otherwise.
|
||||
*/
|
||||
bool grammarPreprocess(); // add bracket based on priority
|
||||
|
||||
/**
|
||||
* @brief Parses the input expression and constructs a syntax tree.
|
||||
*
|
||||
* This function recursively parses the input expression and constructs a syntax tree
|
||||
* based on the processed lexemes. It handles invalid semantics and builds the
|
||||
* tree of operators and operands.
|
||||
*
|
||||
* @param readIndex Index of opening bracket.
|
||||
* @return A pointer to the root of the syntax tree.
|
||||
*/
|
||||
CPrintable *parse( uint64_t &readPos );
|
||||
|
||||
/**
|
||||
* @brief Get the priority of an operator.
|
||||
*
|
||||
* @param t The operator token.
|
||||
* @return The priority of the operator.
|
||||
*/
|
||||
uint64_t getOperatorPriority( TOKEN t ) const;
|
||||
|
||||
/**
|
||||
* @brief Show the help command and return true.
|
||||
*
|
||||
* @return True.
|
||||
*/
|
||||
bool helpCommand();
|
||||
|
||||
/**
|
||||
* @brief Reads a token from the input string.
|
||||
*
|
||||
* This function reads a token from the input string based on the provided index. It starts
|
||||
* from the position indicated by the index and continues until it encounters a space character
|
||||
* or reaches the end of the token.
|
||||
*
|
||||
* @param i The index of the token in the raw lexemes.
|
||||
* @return The extracted token as a string.
|
||||
*/
|
||||
std::string readToken( uint64_t i ) const; // position in raw tokens
|
||||
|
||||
/**
|
||||
* @brief Converts a CRational number to a string representation.
|
||||
*
|
||||
* This function converts a CRational number to its string representation. The string
|
||||
* representation includes the numerator and, if the denominator is not equal to 1, the
|
||||
* fraction part in the format "numerator / denominator".
|
||||
*
|
||||
* @param r A pointer to the CRational number to convert.
|
||||
* @return The string representation of the CRational number.
|
||||
*/
|
||||
std::string numberToString( CRational *r ) const;
|
||||
|
||||
/**
|
||||
* @brief Parse a number from the input string and convert it to a CRational object.
|
||||
*
|
||||
* @param i The index of the token in the raw lexems vector.
|
||||
* @param isDecimal Flag indicating if the number is a decimal.
|
||||
* @param hasSign Flag indicating if the number has a sign.
|
||||
* @return A pointer to the parsed CRational object.
|
||||
*/
|
||||
CRational *parseNumber( uint64_t i, bool isDecimal, bool hasSign ) const;
|
||||
|
||||
/**
|
||||
* @brief Creates a new instance of an operator based on the given token.
|
||||
*
|
||||
* This function creates a new instance of a COperator-based class based on the provided token.
|
||||
* The specific type of the operator is determined by the token value.
|
||||
*
|
||||
* @param t The token representing the operator.
|
||||
* @return A pointer to the newly created operator instance, or nullptr if the token is not a valid operator.
|
||||
*/
|
||||
COperator *spawnOperator( TOKEN t ) const;
|
||||
|
||||
/**
|
||||
* @brief Recognize the type of a character token.
|
||||
*
|
||||
* @param c The character token.
|
||||
* @return The type of the token.
|
||||
*/
|
||||
TOKEN recognize( char c ) const;
|
||||
|
||||
/**
|
||||
* @brief Container for recognised lexems and their position in input.
|
||||
*/
|
||||
std::vector<std::pair<CParser::TOKEN, int64_t>> m_rawLexems;
|
||||
|
||||
/**
|
||||
* @brief Container for relevant lexems and parsed numbers
|
||||
*/
|
||||
std::vector<std::pair<CParser::TOKEN, CRational *>> m_processedLexems;
|
||||
|
||||
/**
|
||||
* @brief Copy of input string
|
||||
*/
|
||||
std::string m_input;
|
||||
std::string m_saveInto;
|
||||
std::unique_ptr<CPrintable> m_head;
|
||||
std::map<std::string, CRational> m_variables;
|
||||
std::unique_ptr<CSaver> m_saver;
|
||||
};
|
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class CRational;
|
||||
|
||||
/**
|
||||
* @brief The CPrintable class represents an abstract printable object.
|
||||
*/
|
||||
class CPrintable {
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor for CPrintable class.
|
||||
*/
|
||||
CPrintable() = default;
|
||||
|
||||
/**
|
||||
* @brief Default destructor for CPrintable class.
|
||||
*/
|
||||
virtual ~CPrintable() = default;
|
||||
|
||||
/**
|
||||
* @brief Evaluates the printable object.
|
||||
* @return A CRational pointer representing the evaluated result.
|
||||
*/
|
||||
virtual CRational *evaluate() = 0;
|
||||
};
|
|
@ -0,0 +1,168 @@
|
|||
#pragma once
|
||||
#include "printable.hpp"
|
||||
#include "bigint.hpp"
|
||||
#include <cmath>
|
||||
|
||||
/**
|
||||
* @brief The CRational class represents the rational number in fraction format.
|
||||
* Responsible for controlling BigInts
|
||||
* It inherits from the CPrintable class.
|
||||
*/
|
||||
class CRational : public CPrintable {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs a CRational object with a numerator and denominator.
|
||||
*
|
||||
* @param num Pointer to the numerator as a CBigInt object.
|
||||
* @param den Pointer to the denominator as a CBigInt object.
|
||||
*/
|
||||
CRational( CBigInt *num, CBigInt *den);
|
||||
|
||||
/**
|
||||
* @brief Constructs a CRational object with a numerator and a default denominator of 1.
|
||||
*
|
||||
* @param num Pointer to the numerator as a CBigInt object.
|
||||
*/
|
||||
CRational( CBigInt *num );
|
||||
|
||||
/**
|
||||
* @brief Constructs a CRational object as a copy of another CRational object.
|
||||
*
|
||||
* @param parent The CRational object to be copied.
|
||||
*/
|
||||
CRational( const CRational &parent );
|
||||
|
||||
/**
|
||||
* @brief Destroys the CRational object.
|
||||
*/
|
||||
virtual ~CRational();
|
||||
|
||||
/**
|
||||
* @brief Converts the CRational object to a string representation.
|
||||
*/
|
||||
virtual CRational *evaluate() override;
|
||||
|
||||
/**
|
||||
* @brief Converts the CRational object to a string representation.
|
||||
*
|
||||
*/
|
||||
std::string toString();
|
||||
|
||||
/**
|
||||
* @brief Simplifies the CRational object by dividing the numerator and denominator by their GCD.
|
||||
* Adjusts the signs of the numerator and denominator accordingly to just nominator.
|
||||
*/
|
||||
void simplify();
|
||||
|
||||
/**
|
||||
* @brief Adds another CRational object to the current CRational object.
|
||||
*
|
||||
* @param oth Pointer to the CRational object to be added.
|
||||
* @return A new CRational object representing the sum of the two CRational objects.
|
||||
*/
|
||||
CRational *add( CRational *oth );
|
||||
|
||||
/**
|
||||
* @brief Subtracts another CRational object from the current CRational object.
|
||||
*
|
||||
* @param oth Pointer to the CRational object to be subtracted.
|
||||
* @return A new CRational object representing the difference between the two CRational objects.
|
||||
*/
|
||||
CRational *sub( CRational *oth );
|
||||
|
||||
/**
|
||||
* @brief Multiplies the current CRational object with another CRational object.
|
||||
*
|
||||
* @param oth Pointer to the CRational object to be multiplied.
|
||||
* @return A new CRational object representing the product of the two CRational objects.
|
||||
*/
|
||||
CRational *mul( CRational *oth );
|
||||
|
||||
/**
|
||||
* @brief Divides the current CRational object by another CRational object.
|
||||
*
|
||||
* @param oth Pointer to the CRational object to be divided by.
|
||||
* @return A new CRational object representing the division of the two CRational objects.
|
||||
*/
|
||||
CRational *div( CRational *oth );
|
||||
|
||||
/**
|
||||
* @brief Raises the current CRational object to a specified power.
|
||||
*
|
||||
* @param pow The exponent to raise the CRational object to.
|
||||
* @return A new CRational object representing the result of the exponentiation.
|
||||
*/
|
||||
CRational *power( uint64_t pow );
|
||||
|
||||
/**
|
||||
* @brief Computes a term of the CRational object raised to the specified power.
|
||||
* @param pow The power to raise the CRational object to.
|
||||
* @return A new CRational object representing the term raised to the specified power.
|
||||
*/
|
||||
CRational *term( uint64_t pow );
|
||||
|
||||
/**
|
||||
* @brief Computes the natural logarithm of the CRational object.
|
||||
* @note Throws an exception if the CRational object is non-positive.
|
||||
* @return A new CRational object representing the natural logarithm of the CRational object.
|
||||
*/
|
||||
CRational *ln();
|
||||
|
||||
/**
|
||||
* @brief Computes the exponential function of the CRational object.
|
||||
* @return A new CRational object representing the exponential function of the CRational object.
|
||||
*/
|
||||
CRational *exp();
|
||||
|
||||
std::string round( uint64_t decimal );
|
||||
|
||||
/**
|
||||
* @brief Sets the same denominator for the current CRational object and another CRational object.
|
||||
* @param oth The other CRational object to set the same denominator with.
|
||||
* @return `true` if the operation is successful, `false` otherwise.
|
||||
*/
|
||||
bool setSameDenominator( CRational *oth );
|
||||
|
||||
/**
|
||||
* @brief Checks if the CRational number is negative.
|
||||
* @return `true` if the number is negative, `false` otherwise.
|
||||
*/
|
||||
bool isNegative() const;
|
||||
|
||||
/**
|
||||
* @brief Negates the CRational number by changing its sign.
|
||||
*/
|
||||
void negate();
|
||||
|
||||
/**
|
||||
* @brief Returns the debug dump of the CRational number as a double.
|
||||
* @return The debug dump value of the CRational number as a double.
|
||||
*/
|
||||
double debugDump();
|
||||
// private:
|
||||
|
||||
/**
|
||||
* @brief Calculates the factorial of an unsigned integer.
|
||||
* @param i The unsigned integer to calculate the factorial for.
|
||||
* @return The factorial of the unsigned integer as a signed 64-bit integer.
|
||||
*/
|
||||
inline static int64_t intfactorial( uint64_t i );
|
||||
|
||||
/**
|
||||
* @brief The precision used for the term calculations.
|
||||
* It specifies the number of terms used in certain calculations.
|
||||
*/
|
||||
static uint64_t termPrecision;
|
||||
|
||||
/**
|
||||
* @brief The numerator of the CRational number.
|
||||
* It is stored as a unique pointer to a CBigInt object.
|
||||
*/
|
||||
std::unique_ptr<CBigInt> m_numerator;
|
||||
|
||||
/**
|
||||
* @brief The denominator of the CRational number.
|
||||
* It is stored as a unique pointer to a CBigInt object.
|
||||
*/
|
||||
std::unique_ptr<CBigInt> m_denominator;
|
||||
};
|
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
#include "../include/rational.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <functional>
|
||||
|
||||
class CSaver {
|
||||
protected:
|
||||
std::string fileName;
|
||||
std::map<std::string, CRational> &m_variables;
|
||||
public:
|
||||
CSaver(std::map<std::string, CRational> &variablesMap);
|
||||
~CSaver() = default;
|
||||
|
||||
std::string m_log;
|
||||
virtual bool save( const std::string &s ) = 0;
|
||||
virtual bool load( const std::string &s ) = 0;
|
||||
};
|
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
#include "rational.hpp"
|
||||
#include "operator.hpp"
|
||||
|
||||
/**
|
||||
* @brief The CSubtraction class represents the subtraction operator.
|
||||
*/
|
||||
class CSubtraction : public COperator {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor for CSubtraction class.
|
||||
* @param a The first argument of the subtraction.
|
||||
* @param b The second argument of the subtraction.
|
||||
*/
|
||||
CSubtraction(CPrintable *a, CPrintable *b);
|
||||
|
||||
/**
|
||||
* @brief Default constructor for CSubtraction class.
|
||||
*/
|
||||
CSubtraction() = default;
|
||||
|
||||
/**
|
||||
* @brief Default destructor for CSubtraction class.
|
||||
*/
|
||||
~CSubtraction() = default;
|
||||
|
||||
/**
|
||||
* @brief Evaluates the subtraction operation.
|
||||
* @return A CRational pointer representing the evaluated result.
|
||||
*/
|
||||
virtual CRational *evaluate() override;
|
||||
private:
|
||||
};
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
#include "../include/saver.hpp"
|
||||
#include "../include/parser.hpp"
|
||||
|
||||
/**
|
||||
* @class CTextsaver
|
||||
* @brief A class for saving and loading variables in text format.
|
||||
*/
|
||||
class CTextsaver : public CSaver {
|
||||
private:
|
||||
CRational *parseNumber( const std::string &s ) const;
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor for CTextsaver.
|
||||
* @param variablesMap A reference to the map of variables to be saved.
|
||||
*/
|
||||
CTextsaver(std::map<std::string, CRational> &variablesMap);
|
||||
|
||||
/**
|
||||
* @brief Destructor for CTextsaver.
|
||||
*/
|
||||
~CTextsaver();
|
||||
|
||||
/**
|
||||
* @brief Saves the variables to a file in text format.
|
||||
* @param fileName The name of the file to save the variables.
|
||||
* @return True if the variables were successfully saved, false otherwise.
|
||||
*/
|
||||
virtual bool save( const std::string &fileName ) override;
|
||||
|
||||
/**
|
||||
* @brief Loads variables from a file in text format.
|
||||
* @param fileName The name of the file to load the variables from.
|
||||
* @return True if the variables were successfully loaded, false otherwise.
|
||||
*/
|
||||
virtual bool load( const std::string &fileName ) override;
|
||||
};
|
Loading…
Reference in New Issue