NewLang Project
Yet another programm language
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Loading...
Searching...
No Matches
rational.cpp
Go to the documentation of this file.
1//#include "pch.h"
2
3#include <cmath>
4#include <openssl/bn.h>
5
6#include "rational.h"
7#include "logger.h"
8//#include "types.h"
9
10using namespace newlang;
11
12BigNum::CtxHelper::CtxHelper() : ctx(BN_CTX_new()) {
13 ASSERT(ctx);
14}
15
17 if (ctx) {
18 BN_CTX_free(static_cast<BN_CTX *> (ctx));
19 ctx = nullptr;
20 }
21}
22
23BigNum::BigNum() : value(BN_new()) {
25}
26
27BigNum::BigNum(const int64_t var) {
28 set_(var);
29}
30
31BigNum::BigNum(const std::string_view str) : BigNum() {
32 SetFromString(str);
33}
34
35BigNum::BigNum(const BigNum &copy) : BigNum() {
36 VERIFY(BN_copy(static_cast<BIGNUM *> (value), static_cast<BIGNUM *> (copy.value)));
37}
38
39BigNum & BigNum::set_(const BigNum & copy) {
40 VERIFY(BN_copy(static_cast<BIGNUM *> (value), static_cast<BIGNUM *> (copy.value)));
41 return *this;
42}
43
44BigNum & BigNum::set_(const int64_t var) {
45 if (var < 0) {
46 BN_set_word(static_cast<BIGNUM *> (value), -var);
47 BN_set_negative(static_cast<BIGNUM *> (value), -1);
48 } else {
49
50 BN_set_word(static_cast<BIGNUM *> (value), var);
51 }
52 return *this;
53}
54
56
57 return set_(var);
58}
59
60BigNum & BigNum::operator=(const int64_t var) {
61
62 return set_(var);
63}
64
66 if (value) {
67 BN_free(static_cast<BIGNUM *> (value));
68 value = nullptr;
69 }
70}
71
72int64_t BigNum::GetAsInteger() const {
73 if (isOverflow()) {
74 LOG_RUNTIME("BigNum integer overflow!");
75 }
76
77 int64_t result = BN_get_word(static_cast<BIGNUM *> (value));
78 if (BN_is_negative(static_cast<BIGNUM *> (value))) {
79
80 result = -result;
81 }
82 return result;
83}
84
85/*
86 * Конвертировать длинное целое в число с плавающей точкой (с потерей точности)
87 */
88double BigNum::GetAsNumber() const {
89 int num_bits = BN_num_bits(static_cast<BIGNUM *> (value));
90
91 if (num_bits <= 52) { // Размер мантиссы double
93 // Точности мантисы хватает для хранения всех значащих бит длинного числа
94 return static_cast<double> (GetAsInteger());
95 } else {
96 BigNum temp(*this);
97
98 BigNum one;
99 one.SetOne();
100
101 BigNum divider;
102 BN_lshift(static_cast<BIGNUM *> (divider.value), static_cast<BIGNUM *> (one.value), num_bits - 52);
103
104 BigNum remander;
105 temp.div(divider, remander);
106
107 ASSERT(!temp.isOverflow());
108 double result = static_cast<double> (temp.GetAsInteger());
109
110 result *= std::pow(2, num_bits - 52);
111
112 return result;
113 }
114 /*
115 1 \ / 2 3
116 123456789123465789123456789123465789
117 123456789123465786113767616146309120.000000
118 */
119}
120
121bool BigNum::SetFromString(const std::string_view str) {
122 ASSERT(!str.empty());
123 BIGNUM * temp = static_cast<BIGNUM *> (value);
124 if (!BN_dec2bn(&temp, str.begin())) {
125 LOG_RUNTIME("Fail create BinNum from string '%s'!", str.begin());
126 }
127 value = (void *) temp;
128 return value;
129}
130
131std::string BigNum::GetAsString() const {
132 char * number_str = BN_bn2dec(static_cast<BIGNUM *> (value));
133 std::string result(number_str);
134 OPENSSL_free(number_str);
135
136 return result;
137}
138
139BigNum & BigNum::add(const BigNum &val) {
140 const BigNum temp(*this);
141 if (!BN_add(static_cast<BIGNUM *> (value), static_cast<BIGNUM *> (temp.value), static_cast<BIGNUM *> (val.value))) {
142 LOG_RUNTIME("BN_add operation fail!");
143 }
144 return *this;
145}
146
147BigNum & BigNum::sub(const BigNum &val) {
148 const BigNum temp(*this);
149 if (!BN_sub(static_cast<BIGNUM *> (value), static_cast<BIGNUM *> (temp.value), static_cast<BIGNUM *> (val.value))) {
150 LOG_RUNTIME("BN_sub operation fail!");
151 }
152 return *this;
153}
154
155BigNum & BigNum::mul(const BigNum &val) {
156 CtxHelper ctx;
157 const BigNum temp(*this);
158 if (!BN_mul(static_cast<BIGNUM *> (value), static_cast<BIGNUM *> (temp.value), static_cast<BIGNUM *> (val.value), static_cast<BN_CTX *> (ctx.ctx))) {
159 LOG_RUNTIME("BN_mul operation fail!");
160 }
161 return *this;
162}
163
164BigNum & BigNum::div(const BigNum &val, BigNum &rem) {
165 CtxHelper ctx;
166 const BigNum temp(*this);
167 if (!BN_div(static_cast<BIGNUM *> (value), static_cast<BIGNUM *> (rem.value), static_cast<BIGNUM *> (temp.value), static_cast<BIGNUM *> (val.value), static_cast<BN_CTX *> (ctx.ctx))) {
168 LOG_RUNTIME("BN_div operation fail!");
169 }
170 return *this;
171}
172
174
175 BN_one(static_cast<BIGNUM *> (value));
176}
177
179
180 BN_zero(static_cast<BIGNUM *> (value));
181}
182
183bool BigNum::isOverflow() const {
184
185 return BN_get_word(static_cast<BIGNUM *> (value)) == static_cast<uint64_t>(~0);
186}
187
188bool BigNum::isZero() const {
189
190 return BN_is_zero(static_cast<BIGNUM *> (value));
191}
192
193bool BigNum::isOne() const {
194
195 return BN_is_one(static_cast<BIGNUM *> (value));
196}
197
198bool BigNum::isNegative() const {
199
200 return BN_is_negative(static_cast<BIGNUM *> (value));
201}
202
203/*
204 *
205 *
206 */
207
209}
210
211Rational::Rational(const int64_t value) {
212 set_(value);
213}
214
215//Rational::Rational(const Rational &copy) {
216// set_(copy);
217//}
218
219Rational::Rational(const std::string_view numerator, const std::string_view denominator) {
220 set_(numerator, denominator);
221}
222
223std::shared_ptr<Rational> Rational::clone() const {
224 std::shared_ptr<Rational> result = std::make_shared<Rational>(*this);
225
226 return result;
227}
228
229std::string Rational::GetAsString() const {
230 std::string result = m_numerator.GetAsString();
231 result += "\\";
233
234 return result;
235}
236
237int64_t Rational::GetAsBoolean() const {
238
239 return !m_numerator.isZero();
240}
241
242int64_t Rational::GetAsInteger() const {
243 if (m_denominator.isZero()) {
244 LOG_RUNTIME("Denominator must be different from zero!");
245 }
246
247 if (m_denominator.isOne()) {
248 return m_numerator.GetAsInteger();
249 }
250
252
253 BigNum rem;
255
256 return result.GetAsInteger();
257}
258
259double Rational::GetAsNumber() const {
260 if (m_denominator.isZero()) {
261 LOG_RUNTIME("Denominator must be different from zero!");
262 }
263 if (m_denominator.isOne()) {
264
265 return m_numerator.GetAsNumber();
266 }
268}
269
270// Сокращения дроби
271
274 BigNum gcd;
275
276 if (!BN_gcd(static_cast<BIGNUM *> (gcd.value), static_cast<BIGNUM *> (m_numerator.value), static_cast<BIGNUM *> (m_denominator.value), static_cast<BN_CTX *> (ctx.ctx))) {
277
278 LOG_RUNTIME("Fail call BN_gcd!");
279 }
280
281 BigNum rem;
282 m_numerator.div(gcd, rem);
283 ASSERT(rem.isZero());
284 m_denominator.div(gcd, rem);
285 ASSERT(rem.isZero());
286}
287
288Rational & Rational::set_(const int64_t value) {
289 if (value < 0) {
290 BN_set_word(static_cast<BIGNUM *> (m_numerator.value), -value);
291 BN_set_negative(static_cast<BIGNUM *> (m_numerator.value), -1);
292 } else {
293 BN_set_word(static_cast<BIGNUM *> (m_numerator.value), value);
294 }
295 BN_set_word(static_cast<BIGNUM *> (m_denominator.value), 1);
296
297 return *this;
298}
299
303
304 return *this;
305}
306
307Rational & Rational::set_(const std::string_view numerator, const std::string_view denominator) {
308 m_numerator.SetFromString(numerator);
309 m_denominator.SetFromString(denominator);
310
311 return *this;
312}
313
315 m_numerator.mul(rational.m_numerator);
317 reduce();
318
319 return *this;
320}
321
323 m_numerator.mul(rational.m_denominator);
324 m_denominator.mul(rational.m_numerator);
325 reduce();
326
327 return *this;
328}
329
331
332 BigNum sub_num(rational.m_numerator);
333 sub_num.mul(m_denominator);
334
335 m_numerator.mul(rational.m_denominator);
337
338 m_numerator.sub(sub_num);
339
340 reduce();
341
342 return *this;
343}
344
346 BigNum add_num(rational.m_numerator);
347 add_num.mul(m_denominator);
348
349 m_numerator.mul(rational.m_denominator);
351
352 m_numerator.add(add_num);
353
354 reduce();
355
356 return *this;
357}
358
360 LOG_RUNTIME("Not implemented!");
361
362 return *this;
363}
364
366 LOG_RUNTIME("Operator '^=' not implementd!");
367
368 return *this;
369}
370
372 LOG_RUNTIME("Operator '|=' not implementd!");
373 return *this;
374}
375
377 LOG_RUNTIME("Operator '<<=' not implementd!");
378
379 return *this;
380}
381
383 LOG_RUNTIME("Operator '>>=' not implementd!");
384
385 return *this;
386}
387
389 LOG_RUNTIME("Operator '>>>=' not implementd!");
390
391 return *this;
392}
393
395 LOG_RUNTIME("Not implemented!");
396
397 return *this;
398}
399
400bool Rational::op_equal(const Rational &rational) const {
401
402 return BN_cmp(static_cast<BIGNUM *> (m_numerator.value), static_cast<BIGNUM *> (rational.m_numerator.value)) == 0 &&
403 BN_cmp(static_cast<BIGNUM *> (m_denominator.value), static_cast<BIGNUM *> (rational.m_denominator.value)) == 0;
404}
405
406int Rational::op_compare(const Rational &rational) const {
407 if (BN_cmp(static_cast<BIGNUM *> (m_denominator.value), static_cast<BIGNUM *> (rational.m_denominator.value)) == 0) {
408 return BN_cmp(static_cast<BIGNUM *> (m_numerator.value), static_cast<BIGNUM *> (rational.m_numerator.value));
409 }
410
411 Rational first(*this);
412 Rational second(rational);
413
414 Rational mul;
416 second *= mul;
417 mul.m_numerator.set_(rational.m_denominator);
418 first *= mul;
419
420 ASSERT(BN_cmp(static_cast<BIGNUM *> (first.m_denominator.value), static_cast<BIGNUM *> (second.m_denominator.value)) == 0);
421
422 return BN_cmp(static_cast<BIGNUM *> (first.m_numerator.value), static_cast<BIGNUM *> (second.m_numerator.value));
423}
424
426 LOG_RUNTIME("Not implemented!");
427 return *this;
428}
429
Rational & operator-=(const Rational &rational)
Definition rational.cpp:330
std::string GetAsString() const
Definition rational.cpp:229
Rational & op_lshift_set(const Rational &)
Definition rational.cpp:376
Rational & op_pow_(const Rational &rational)
Definition rational.cpp:394
Rational & op_div_ceil_(Rational &rational)
Definition rational.cpp:425
bool op_equal(const Rational &rational) const
Definition rational.cpp:400
std::shared_ptr< Rational > clone() const
Definition rational.cpp:223
Rational & operator*=(const Rational &rational)
Definition rational.cpp:314
Rational & op_rshift_set(const Rational &)
Definition rational.cpp:382
Rational & operator^=(const Rational &)
Definition rational.cpp:365
const Rational & op_rrshift_set(const Rational &)
Definition rational.cpp:388
Rational & operator|=(const Rational &)
Definition rational.cpp:371
BigNum m_numerator
Definition rational.h:57
Rational & operator/=(const Rational &rational)
Definition rational.cpp:322
Rational & operator%=(const Rational &rational)
Definition rational.cpp:359
int64_t GetAsBoolean() const
Definition rational.cpp:237
int op_compare(const Rational &rational) const
Definition rational.cpp:406
Rational & set_(const int64_t value)
Definition rational.cpp:288
Rational & operator+=(const Rational &rational)
Definition rational.cpp:345
BigNum m_denominator
Definition rational.h:58
int64_t GetAsInteger() const
Definition rational.cpp:242
double GetAsNumber() const
Definition rational.cpp:259
int result
Definition lexer.l:367
#define LOG_RUNTIME(format,...)
Definition logger.h:26
#define VERIFY(exp)
Definition logger.h:65
#define ASSERT(condition)
Definition logger.h:60
Definition nlc.h:59
BigNum & div(const BigNum &val, BigNum &rem)
Definition rational.cpp:164
bool isOne() const
Definition rational.cpp:193
bool SetFromString(const std::string_view str)
Definition rational.cpp:121
bool isZero() const
Definition rational.cpp:188
BigNum & operator=(const BigNum &var)
Definition rational.cpp:55
BigNum & mul(const BigNum &val)
Definition rational.cpp:155
std::string GetAsString() const
Definition rational.cpp:131
bool isOverflow() const
Definition rational.cpp:183
bool isNegative() const
Definition rational.cpp:198
BigNum & sub(const BigNum &val)
Definition rational.cpp:147
virtual ~BigNum()
Definition rational.cpp:65
double GetAsNumber() const
Definition rational.cpp:88
BigNum & add(const BigNum &val)
Definition rational.cpp:139
int64_t GetAsInteger() const
Definition rational.cpp:72
BigNum & set_(const BigNum &copy)
Definition rational.cpp:39