Arkulib
ERational.hpp
Go to the documentation of this file.
1
10#pragma once
11
12#include "Rational.hpp"
13#include <iomanip>
14
15namespace Arkulib {
20 template<typename FloatType = double>
21 class ERational {
22
23 public:
24
25 /************************************************************************************************************
26 ****************************************** CONSTRUCTOR / DESTRUCTOR ****************************************
27 ************************************************************************************************************/
28
32 constexpr explicit ERational();
33
41 template<typename IntType = int>
42 constexpr explicit ERational(
43 IntType numerator,
44 IntType denominator,
45 bool willBeReduce = false,
46 bool willDenominatorBeVerified = true
47 );
48
54 template<typename FloatingType>
55 constexpr explicit ERational(const FloatingType &nonRational);
56
62 inline constexpr ERational(const ERational<FloatType> &reference) = default;
63
68 template<typename IntType>
69 inline constexpr explicit ERational(const Rational<IntType> &reference) {
70 *this = ERational<FloatType>(reference.getNumerator(), reference.getDenominator());
71 };
72
80 constexpr ERational(
81 FloatType numMultiplier, short int numExponent,
82 FloatType denMultiplier, short int denExponent
83 );
84
90 constexpr ERational(
91 std::pair<FloatType, short int> numerator,
92 std::pair<FloatType, short int> denominator
93 );
94
98 inline ~ERational() = default;
99
100 /************************************************************************************************************
101 ************************************************ GETTERS ***************************************************
102 ************************************************************************************************************/
103
104 [[maybe_unused]] [[nodiscard]] constexpr inline std::pair<FloatType,short int> getNumerator() const noexcept { return m_numerator; }
105 [[nodiscard]] constexpr inline FloatType getNumMultiplier() const noexcept { return m_numerator.first; }
106 [[nodiscard]] constexpr inline short int getNumExponent() const noexcept { return m_numerator.second; }
107
108 [[maybe_unused]] [[nodiscard]] constexpr inline std::pair<FloatType,short int> getDenominator() const noexcept { return m_denominator; }
109 [[nodiscard]] constexpr inline FloatType getDenMultiplier() const noexcept { return m_denominator.first; }
110 [[nodiscard]] constexpr inline short int getDenExponent() const noexcept { return m_denominator.second; }
111
112 /************************************************************************************************************
113 ************************************************ SETTERS ***************************************************
114 ************************************************************************************************************/
115
116 constexpr inline void setNumerator(std::pair<FloatType, short int> numerator) noexcept { m_numerator = numerator; }
117 constexpr inline void setNumerator(FloatType newMultiplier, short int newExponent) noexcept { m_numerator = std::make_pair(newMultiplier, newExponent); }
118 constexpr inline void setNumMultiplier(FloatType newNumMultiplier) noexcept { m_numerator.first = newNumMultiplier; }
119 constexpr inline void setNumExponent(short int newNumExponent) noexcept { m_numerator.second = newNumExponent; }
120
121 constexpr inline void setDenominator(std::pair<FloatType, short int> denominator) noexcept { m_denominator = denominator; }
122 constexpr inline void setDenominator(FloatType newMultiplier, short int newExponent) noexcept { m_denominator = std::make_pair(newMultiplier, newExponent); }
123 constexpr inline void setDenMultiplier(FloatType newDenMultiplier) noexcept { m_denominator.first = newDenMultiplier; }
124 constexpr inline void setDenExponent(short int newDenExponent) noexcept { m_denominator.second = newDenExponent; }
125
126 /************************************************************************************************************
127 *********************************************** OPERATOR + *************************************************
128 ************************************************************************************************************/
129
135 constexpr ERational<FloatType> operator+(const ERational<FloatType> &anotherERational) const;
136
137 /************************************************************************************************************
138 *********************************************** OPERATOR - *************************************************
139 ************************************************************************************************************/
140
146 constexpr ERational<FloatType> operator-(const ERational<FloatType> &anotherERational) const;
147
148 /************************************************************************************************************
149 *********************************************** OPERATOR * *************************************************
150 ************************************************************************************************************/
151
157 constexpr ERational<FloatType> operator*(const ERational<FloatType> &anotherERational) const;
158
159 /************************************************************************************************************
160 *********************************************** OPERATOR / *************************************************
161 ************************************************************************************************************/
162
168 constexpr ERational<FloatType> operator/(const ERational<FloatType> &anotherERational) const;
169
170 /************************************************************************************************************
171 *********************************************** OPERATOR == ************************************************
172 ************************************************************************************************************/
173
179 constexpr inline bool operator==(const ERational<FloatType> &anotherERational) const;
180
181 /************************************************************************************************************
182 ********************************************** OPERATOR != *************************************************
183 ************************************************************************************************************/
184
190 constexpr inline bool operator!=(const ERational<FloatType> &anotherERational) const;
191
192 /************************************************************************************************************
193 ************************************************* STATUS ***************************************************
194 ************************************************************************************************************/
195
199 [[maybe_unused]] [[nodiscard]] inline bool isNegative() const noexcept {
200 return (getNumMultiplier() < 0. && getDenMultiplier() > 0.)
201 || (getNumMultiplier() > 0. && getDenMultiplier() < 0.);
202 };
203
207 [[maybe_unused]] [[nodiscard]] inline bool isInteger() const noexcept { return getDenMultiplier() == 1.; };
208
212 [[maybe_unused]] [[nodiscard]] inline bool isZero() const noexcept { return getNumMultiplier() == 0.; };
213
214 /************************************************************************************************************
215 ************************************************** MATHS ***************************************************
216 ************************************************************************************************************/
217
222 [[maybe_unused]] [[nodiscard]] constexpr inline ERational<FloatType> abs() const {
224 std::abs(getNumMultiplier()), getNumExponent(),
225 std::abs(getDenMultiplier()), getDenExponent()
226 );
227 };
228
233 [[maybe_unused]] [[nodiscard]] constexpr inline ERational<FloatType> inverse() const {
235 }
236
240 [[maybe_unused]] constexpr ERational<FloatType> simplify() noexcept;
241
242 /************************************************************************************************************
243 *********************************************** CONVERSION *************************************************
244 ************************************************************************************************************/
245
251 template<typename AnotherFloatType = double>
252 [[nodiscard]] inline constexpr AnotherFloatType toRealNumber() const noexcept {
253 return static_cast<AnotherFloatType>
254 (getNumMultiplier() * std::pow(10, getNumExponent())) / (getDenMultiplier() * std::pow(10, getDenExponent())
255 );
256 }
257
262 [[nodiscard]] inline std::string toString() const noexcept {
265 }
266
267 private:
268 /************************************************************************************************************
269 ************************************************** METHODS *************************************************
270 ************************************************************************************************************/
271
277 template<typename IntType = int>
278 constexpr void transformToExperimental(IntType numerator, IntType denominator);
279
286 template<typename IntType = int>
287 static constexpr std::pair<FloatType, short int> transformOperandToPair(IntType operand);
288
293 constexpr void verifyDenominator(bool checkIfDenominatorIsNull = true);
294
298 constexpr inline void verifyTemplateType() const {
299 if (std::is_integral<FloatType>()) throw Exceptions::IntTypeGivenException();
300 };
301
307 constexpr void setAtSameNumeratorExponent(
308 ERational<FloatType> &firstERational,
309 ERational<FloatType> &secondERational
310 ) const;
311
317 constexpr void setAtSameDenominator(
318 ERational <FloatType> &firstERational,
319 ERational <FloatType> &secondERational
320 ) const;
321
322 /************************************************************************************************************
323 ************************************************** MEMBERS *************************************************
324 ************************************************************************************************************/
325
326 std::pair<FloatType, short int> m_numerator;
327
328 std::pair<FloatType, short int> m_denominator;
329 // We also could have create a struct for this pair to ease some methods
330 // (for example, we could have isNegative() in the struct or even operators)
331 };
332
333
334
335
336 /************************************************************************************************************
337 ************************************************************************************************************/
338
339
340
341 /************************************************************************************************************
342 ********************************************* CONSTRUCTOR DEF **********************************************
343 ************************************************************************************************************/
344
345 template<typename FloatType>
346 constexpr ERational<FloatType>::ERational() : m_numerator(0., 0), m_denominator(1., 0) {
348 }
349
350
351 template<typename FloatType>
352 template<typename IntType>
354 const IntType numerator,
355 const IntType denominator,
356 const bool willBeReduce,
357 const bool willDenominatorBeVerified
358 ) : m_numerator(transformOperandToPair(numerator)),
359 m_denominator(transformOperandToPair(denominator))
360 {
362 verifyDenominator(willDenominatorBeVerified);
363
364 if (willBeReduce) {
365 const int gcd = std::gcd(numerator, denominator);
366 assert(gcd != 0 && "GCD shouldn't be equal to 0");
367
368 transformToExperimental(numerator / gcd, denominator / gcd);
369 *this = simplify();
370 }
371 }
372
373 template<typename FloatType>
374 template<typename AnotherFloatType>
375 constexpr ERational<FloatType>::ERational(const AnotherFloatType &nonRational) {
376 verifyTemplateType();
377
379 *this = ERational{tmpRational};
380 }
381
382
383
384 template<typename FloatType>
386 const FloatType numMultiplier,
387 const short int numExponent,
388 const FloatType denMultiplier,
389 const short int denExponent
390 ) {
391 m_numerator = std::make_pair(numMultiplier, numExponent);
392 m_denominator = std::make_pair(denMultiplier, denExponent);
393 }
394
395
396 template<typename FloatType>
398 std::pair<FloatType, short int> numerator,
399 std::pair<FloatType, short int> denominator
400 ) {
401 m_numerator = numerator;
402 m_denominator = denominator;
403 }
404
405 /************************************************************************************************************
406 ********************************************* OPERATOR + DEF ***********************************************
407 ************************************************************************************************************/
408
409 template<typename FloatType>
411 // We create new Rational with the same denominator (we multiply them by denominator / denominator)
412 ERational<FloatType> firstERational = *this;
413 ERational<FloatType> secondERational = anotherERational;
414 setAtSameDenominator(firstERational, secondERational);
415 setAtSameNumeratorExponent(firstERational, secondERational);
416
418 std::make_pair(
419 firstERational.getNumMultiplier() + secondERational.getNumMultiplier(),
420 firstERational.getNumExponent()
421 ),
422 firstERational.getDenominator()
423 );
424 }
425
426 /************************************************************************************************************
427 ********************************************* OPERATOR - DEF ***********************************************
428 ************************************************************************************************************/
429
430 template<typename FloatType>
432 // We create new Rational with the same denominator (we multiply them by denominator / denominator)
433 ERational<FloatType> firstERational = *this;
434 ERational<FloatType> secondERational = anotherERational;
435 setAtSameDenominator(firstERational, secondERational);
436 setAtSameNumeratorExponent(firstERational, secondERational);
437
439 std::make_pair(
440 firstERational.getNumMultiplier() - secondERational.getNumMultiplier(),
441 firstERational.getNumExponent()
442 ),
443 firstERational.getDenominator()
444 );
445 }
446
447 /************************************************************************************************************
448 ********************************************* OPERATOR * DEF ***********************************************
449 ************************************************************************************************************/
450
451 template<typename FloatType>
454 getNumMultiplier() * anotherERational.getNumMultiplier(),
455 getNumExponent() + anotherERational.getNumExponent(),
456 getDenMultiplier() * anotherERational.getDenMultiplier(),
457 getDenExponent() + anotherERational.getDenExponent()
458 );
459 }
460
461 /************************************************************************************************************
462 ********************************************* OPERATOR / DEF ***********************************************
463 ************************************************************************************************************/
464
465 template<typename FloatType>
468 getNumMultiplier() * anotherERational.getDenMultiplier(),
469 getNumExponent() + anotherERational.getDenExponent(),
470 getDenMultiplier() * anotherERational.getNumMultiplier(),
471 getDenExponent() + anotherERational.getNumExponent()
472 );
473 }
474
475 /************************************************************************************************************
476 ********************************************* OPERATOR == DEF **********************************************
477 ************************************************************************************************************/
478
479 template<typename FloatType>
480 constexpr bool ERational<FloatType>::operator==(const ERational<FloatType> &anotherERational) const {
481 ERational<FloatType> leftRational = this->simplify();
482 ERational<FloatType> rightRational = anotherERational->simplify();
483
484 if (leftRational.getNumExponent() != rightRational.getNumExponent()
485 || leftRational.getDenExponent() != rightRational.getDenExponent()
486 || leftRational.toRealNumber() != rightRational.toRealNumber()) {
487 return false;
488 }
489
490 return true;
491 }
492
493 /************************************************************************************************************
494 ********************************************* OPERATOR != DEF **********************************************
495 ************************************************************************************************************/
496
497 template<typename FloatType>
498 constexpr bool ERational<FloatType>::operator!=(const ERational<FloatType> &anotherERational) const {
499 return (*this == anotherERational) == false;
500 }
501
502 /************************************************************************************************************
503 ************************************************ MATHS DEF *************************************************
504 ************************************************************************************************************/
505
506 template<typename FloatType>
508 const int exponentDifference = std::abs(getNumExponent() - getDenExponent());
509
510 if (exponentDifference == 0 && getNumExponent() != 0) {
511 setNumExponent(0);
512 setDenExponent(0);
513 }
514
515 const int minExponent = std::min(getNumExponent(), getDenExponent());
516 if (exponentDifference != 0 && minExponent > 0) {
517 setNumExponent(getNumExponent() - minExponent);
518 setDenExponent(getDenExponent() - minExponent);
519 }
520
521 return *this;
522 }
523
524 /************************************************************************************************************
525 ************************************************ METHODS DEF ***********************************************
526 ************************************************************************************************************/
527
528 template<typename FloatType>
529 template<typename IntType>
530 constexpr void ERational<FloatType>::transformToExperimental(const IntType numerator, const IntType denominator) {
531 setNumerator(transformOperandToPair(numerator));
532 setDenominator(transformOperandToPair(denominator));
533 }
534
535 template<typename FloatType>
536 template<typename IntType>
537 constexpr std::pair<FloatType, short> ERational<FloatType>::transformOperandToPair(IntType operand) {
538 const int operandLength = Tools::getNumberLength(operand);
539 return std::make_pair(
540 operand * std::pow(10, -operandLength),
541 operandLength
542 );
543 }
544
545 template<typename FloatType>
546 constexpr void ERational<FloatType>::verifyDenominator(bool checkIfDenominatorIsNull) {
547 if (getDenMultiplier() == 0. && checkIfDenominatorIsNull)
549
550 if (getDenMultiplier() < 0.) {
551 setNumMultiplier(-getNumMultiplier());
552 setDenMultiplier(-getDenMultiplier());
553 }
554 }
555
556 template<typename FloatType>
558 ERational<FloatType> &firstERational,
559 ERational<FloatType> &secondERational
560 ) const {
561 const int exponentDifference = firstERational.getNumExponent() - secondERational.getNumExponent();
562 secondERational.setNumMultiplier(secondERational.getNumMultiplier() / std::pow(10, exponentDifference));
563 secondERational.setNumExponent(secondERational.getNumExponent() + exponentDifference);
564
565 assert(firstERational.getNumExponent() == secondERational.getNumExponent() &&
566 "The two numerator exponents should be equal");
567 }
568
569 template<typename FloatType>
571 ERational <FloatType> &firstERational,
572 ERational <FloatType> &secondERational
573 ) const {
574 firstERational= firstERational * ERational(secondERational.getDenominator(), secondERational.getDenominator());
575 secondERational= secondERational * ERational(this->getDenominator(), this->getDenominator());
576 assert(firstERational.getDenominator() == secondERational.getDenominator() &&
577 "The two denominators should be equal");
578 }
579
580 /************************************************************************************************************
581 ************************************************* STD::COUT ************************************************
582 ************************************************************************************************************/
583
591 template<typename FloatType>
592 std::ostream &operator<<(std::ostream &stream, const ERational<FloatType> &rational) {
593 return stream << rational.toString();
594 }
595
596};
This class can be used to express big rationals.
Definition: ERational.hpp:21
constexpr ERational< FloatType > inverse() const
Get the inverse of an ERational.
Definition: ERational.hpp:233
constexpr bool operator==(const ERational< FloatType > &anotherERational) const
Comparison between 2 ERationals.
Definition: ERational.hpp:480
constexpr ERational(const Rational< IntType > &reference)
Copy constructor from a Rational.
Definition: ERational.hpp:69
constexpr std::pair< FloatType, short int > getDenominator() const noexcept
Definition: ERational.hpp:108
constexpr void verifyTemplateType() const
Verify if the template is correct. Throw an exception if the template is an integral.
Definition: ERational.hpp:298
constexpr ERational< FloatType > operator*(const ERational< FloatType > &anotherERational) const
Multiplication operation between 2 experimental rationals.
Definition: ERational.hpp:452
constexpr ERational()
Default constructor : instantiate an object without parameters.
Definition: ERational.hpp:346
constexpr short int getNumExponent() const noexcept
Definition: ERational.hpp:106
static constexpr std::pair< FloatType, short int > transformOperandToPair(IntType operand)
Transform a numerator/denominator into a pair.
constexpr void setNumExponent(short int newNumExponent) noexcept
Definition: ERational.hpp:119
constexpr void setDenMultiplier(FloatType newDenMultiplier) noexcept
Definition: ERational.hpp:123
constexpr ERational< FloatType > operator/(const ERational< FloatType > &anotherERational) const
Division operation between 2 experimental rationals.
Definition: ERational.hpp:466
bool isNegative() const noexcept
Definition: ERational.hpp:199
constexpr ERational(const FloatingType &nonRational)
Create an experimental rational from a floating number.
constexpr void setAtSameDenominator(ERational< FloatType > &firstERational, ERational< FloatType > &secondERational) const
Set firstERational and secondERational with the same denominator exponent.
Definition: ERational.hpp:570
bool isZero() const noexcept
Definition: ERational.hpp:212
std::string toString() const noexcept
Return ( numerator / denominator ) as a string.
Definition: ERational.hpp:262
constexpr FloatType getDenMultiplier() const noexcept
Definition: ERational.hpp:109
bool isInteger() const noexcept
Definition: ERational.hpp:207
constexpr ERational< FloatType > abs() const
Apply absolute value on the ERational.
Definition: ERational.hpp:222
constexpr ERational< FloatType > operator+(const ERational< FloatType > &anotherERational) const
Sum operation between 2 experimental rationals.
Definition: ERational.hpp:410
constexpr bool operator!=(const ERational< FloatType > &anotherERational) const
Different comparison between 2 erationals.
Definition: ERational.hpp:498
constexpr void setAtSameNumeratorExponent(ERational< FloatType > &firstERational, ERational< FloatType > &secondERational) const
Set firstERational and secondERational with the same numerator exponent.
Definition: ERational.hpp:557
constexpr ERational< FloatType > simplify() noexcept
Simplify the Rational with GCD.
Definition: ERational.hpp:507
constexpr void setNumerator(std::pair< FloatType, short int > numerator) noexcept
Definition: ERational.hpp:116
constexpr void verifyDenominator(bool checkIfDenominatorIsNull=true)
Verify if the denominator is null or negative.
Definition: ERational.hpp:546
~ERational()=default
Default Destructor.
constexpr void setNumerator(FloatType newMultiplier, short int newExponent) noexcept
Definition: ERational.hpp:117
constexpr void setDenominator(std::pair< FloatType, short int > denominator) noexcept
Definition: ERational.hpp:121
std::pair< FloatType, short int > m_denominator
Definition: ERational.hpp:328
constexpr void setNumMultiplier(FloatType newNumMultiplier) noexcept
Definition: ERational.hpp:118
constexpr void setDenExponent(short int newDenExponent) noexcept
Definition: ERational.hpp:124
constexpr void setDenominator(FloatType newMultiplier, short int newExponent) noexcept
Definition: ERational.hpp:122
constexpr AnotherFloatType toRealNumber() const noexcept
Get an approximation floating point number of the experimental ratio.
Definition: ERational.hpp:252
constexpr FloatType getNumMultiplier() const noexcept
Definition: ERational.hpp:105
constexpr short int getDenExponent() const noexcept
Definition: ERational.hpp:110
constexpr void transformToExperimental(IntType numerator, IntType denominator)
Set the parameters from a normal numerator and denominator.
Definition: ERational.hpp:530
constexpr ERational< FloatType > operator-(const ERational< FloatType > &anotherERational) const
Subtraction operation between 2 experimental rationals.
Definition: ERational.hpp:431
constexpr ERational(const ERational< FloatType > &reference)=default
Copy constructor.
constexpr std::pair< FloatType, short int > getNumerator() const noexcept
Definition: ERational.hpp:104
std::pair< FloatType, short int > m_numerator
Definition: ERational.hpp:326
An exception to handle divide by 0.
An exception to handle ERational multiplier in a non floating point type.
This class can be used to express rationals.
Definition: Rational.hpp:27
constexpr IntType getDenominator() const noexcept
Definition: Rational.hpp:87
static constexpr Rational< IntType > fromFloatingPoint(FloatingType floatingRatio, size_t iter=Constant::DEFAULT_ITERATIONS_FROM_FP)
A method who automatically set numerator and denominator to approach the float parameter.
constexpr IntType getNumerator() const noexcept
Definition: Rational.hpp:85
int getNumberLength(const Type value)
Get the length on a number.
Definition: Utils.hpp:53
std::string toStringWithPrecision(const Type value, const int precision=Arkulib::Constant::DEFAULT_COUT_ERATIONAL_DIGITS)
Let the user set the precision while transforming a floating point to a string.
Definition: Utils.hpp:36
std::ostream & operator<<(std::ostream &stream, const ERational< FloatType > &rational)
<< operator override to allow std::cout
Definition: ERational.hpp:592