I'm working on a class to represent numbers in scientific notation with the plan of overcoming floating-point precisions within calculations of numbers...
Typically if we have two floating-point numbers as illustrated:
double a = 23456234.892;
double b = 0.00000314;
double c = a + b;
We can run into precision problems as well as rounding errors.
To try and combat this I decided to design a class that works on the principles of doing calculations in scientific notation.
Here is the main structure of my class:
template<uint16_t BASE = 10>
class Fpn { // Floating Point Notation
public:
constexpr uint16_t Base{BASE};
private:
double coefficient_;
int64_t exponent_;
public:
Fpn() : coefficient_{0}, exponent_{1} {}
Fpn( double coeff, uint64_t exp ) : coefficient_{coeff}, exponent_{exp} {}
Fpn(const Fpn& rhs) {
coefficient_ = rhs.coefficient_;
exponent_ = rhs.exponent_;
}
Fpn& operator=(const Fpn& rhs) {
coefficient_ = rhs.coefficieint_;
exponent_ = rhs.coefficieint_;
return *this;
}
// Unary Operators:
Fpn operator+() const { return *this; }
// Negation:
Fpn operator-(bool invert = false) {
if (!invert) return { Fpn(-coefficient_, exponent_); }
return Fpn(coefficient_, -exponent_);
}
// arithmetic operators:
};
Now I'm at the point where I'm working on my arithmetic operators: operator+(const &obj)
, operator+=(const &obj)
, operator-(const &obj)
, operator*
, operator*=
, operator/
, operator/=
...
Now before we can Add
or Subtract
, they have to be of the same order of exponentiation...
I was thinking of creating a private helper function for doing this conversion and then calling that in my +
, +=
, -
, & -=
operators...
Within my function, I'm thinking on the lines of figuring out which one has the greater exponent, and then I want to convert the lower order to the higher-ordered object...
private:
void convert(Fpn& rhs) {
if(exponent_ == rhs.exponent_) return; // Don't need to do anything
// This will tell me which one has the higher exponent
auto higher_order = (exponent_ > rhs.exponent_) ? exponent_ : rhs.exponent_;
// This is where I'm getting a bit stumped...
auto difference = higher_order - /*? smaller of the two* ... another ternary check?*/
// I'm checking negative against positive so that if abs() doesn't have to be called...
// or would that not matter and just use `abs()` regardless?
// Also, once I figure out which one needs to be converted
// Then I have to convert the correct side RHS vs LHS...
// ????
if (difference < 0) { // negative case
coefficient_ *= (abs(difference)*Base);
exponent_ /= (abs(difference)*Base);
}
if (difference > 0) { // positive case
coefficient_ *= difference * Base;
exponent_ /= difference * Base;
}
}
If the LHS
's exponent is greater than the RHS
's then I want to convert the RHS
to LHS
and the do the same if RHS
is greater than LHS
...
Please do not suggest std::scientific
I know that exists and that's not what I'm after.
Would I have to then use another ternary
operator to return back the smaller of the two? Or, without having to perform a bunch of conditional checks... are there any viable algorithms with the stl
or some type of lambda expression that would help with this part of the process?
Also, I'm calculating the difference between them and then checking if that difference is negative or positive... if it's negative then I'm using abs()
from <cmath>
otherwise if it's positive I'm not calling abs()
... Now, this is just a side question as it is related to this function and its design... Would it be better to not have a conditional check and just call abs()
regardless or would it be better to branch between the two?
There is another function that I need write which will be another helper function that some of these operators will call after they perform their arithmetic calculations to convert the final result as a value where it's coefficient is between [1,10]
if the Base
is 10
, but that function is not written yet as I need to finish with this convert()
function.
I know what I would like to do, but I'm struggling a bit with design decisions while trying to use the appropriate techniques and algorithms.
I appreciate any and all feedback, tips, suggestions, etc.