Проектное решение: определение подходящих алгоритмов во вспомогательной функции класса записи с плавающей запятой.

Я работаю над классом для представления чисел в научной нотации с планом преодоления точности с плавающей запятой в вычислениях чисел...

Обычно, если у нас есть два числа с плавающей запятой, как показано на рисунке:

double a = 23456234.892;
double b = 0.00000314;
double c = a + b;

Мы можем столкнуться с проблемами точности, а также с ошибками округления.

Чтобы попытаться бороться с этим, я решил разработать класс, который работает на принципах выполнения вычислений в экспоненциальном представлении.

Вот основная структура моего класса:

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:
};

Сейчас я работаю над своими арифметическими операторами: operator+(const &obj), operator+=(const &obj), operator-(const &obj), operator*, operator*=, operator/, operator/=...

Теперь, прежде чем мы сможем Add или Subtract, они должны быть одного порядка возведения в степень...

Я думал о создании частной вспомогательной функции для выполнения этого преобразования, а затем вызывал ее в моих операторах +, +=, - и -=...

В рамках моей функции я думаю о том, как выяснить, у какого из них показатель больше, а затем я хочу преобразовать объект более низкого порядка в объект более высокого порядка...

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;
        }
    }

Если показатель LHS больше, чем RHS, то я хочу преобразовать RHS в LHS и сделать то же самое, если RHS больше LHS...


Пожалуйста, не предлагайте std::scientific Я знаю, что это существует, и это не то, что мне нужно.


Должен ли я затем использовать другой оператор ternary, чтобы вернуть меньший из двух? Или без необходимости выполнять кучу условных проверок... существуют ли жизнеспособные алгоритмы с stl или каким-либо типом лямбда-выражения, которые помогли бы в этой части процесса?

Кроме того, я вычисляю разницу между ними, а затем проверяю, является ли эта разница отрицательной или положительной... если она отрицательная, то я использую abs() из <cmath>, в противном случае, если она положительная, я не звоню abs()... Теперь это это всего лишь побочный вопрос, поскольку он связан с этой функцией и ее дизайном ... Было бы лучше не иметь условной проверки и просто вызывать abs() независимо от того, или было бы лучше перейти между ними?

Есть еще одна функция, которую мне нужно написать, которая будет еще одной вспомогательной функцией, которую некоторые из этих операторов будут вызывать после выполнения своих арифметических вычислений, чтобы преобразовать окончательный результат в значение, где его коэффициент находится между [1,10], если Base равно 10, но эта функция еще не написано, так как мне нужно закончить с этой функцией convert().

Я знаю, что я хотел бы сделать, но я немного борюсь с дизайнерскими решениями, пытаясь использовать соответствующие методы и алгоритмы.

Я ценю любые отзывы, советы, предложения и т.


person Francis Cugler    schedule 19.08.2020    source источник
comment
Разве не это уже является с плавающей запятой? Значимое и показатель степени. Здесь разница только в базе. Итак, возможно, вы ищете расширение std::decimal? Или launchpad.net/std-decimal. Или decNumber++. Или...   -  person Asteroids With Wings    schedule 19.08.2020
comment
@AsteroidsWithWings Не совсем так... Я пытаюсь расширить представление о числах с плавающей запятой. Однако намерение этого класса в том, что с коэффициентом он имеет размер двойника, показатель степени имеет размер int64_t У меня тоже была опечатка для типа exponent, он должен был быть int64_t а не uint64_t... И база шаблонная...   -  person Francis Cugler    schedule 19.08.2020
comment
@AsteroidsWithWings Затем я могу взять значение, скажем, 23452228342,20, добавить к нему 0,00000000003002343 и по-прежнему сохранять значение, пока каждая часть соответствует своей точности.   -  person Francis Cugler    schedule 19.08.2020
comment
Правильно, это то, что делают десятичные типы с плавающей запятой.   -  person Asteroids With Wings    schedule 19.08.2020
comment
@AsteroidsWithWings На 64-битной машине двойное число обычно составляет 8 байтов или 64 бита, и только определенное количество бит зарезервировано для мантиссы, бит для знака и столько же битов для экспоненты в зависимости от соглашения, которое они используют, например как стандарт IEE-754 ... Здесь я расширяю тот факт, что база имеет 64 бита, а показатель степени - 64 бита.   -  person Francis Cugler    schedule 19.08.2020
comment
Да, вы сказали при условии, что каждая часть соответствует их точности. В приведенном вами примере показатели степени хорошо находятся в пределах точности показателя степени в std::decimal::decimal128. Например, на два порядка. Как вы думаете, зачем вам нужны показатели степени до ±9 223 372 036 854 775 807? Это кажется маловероятным.   -  person Asteroids With Wings    schedule 19.08.2020
comment
Зачем писать такую ​​библиотеку самому, а не использовать одну из существующих? Я бы предложил сделать double coefficient_; целым числом. Ваш void convert(Fpn& rhs) выполняет нормализацию числа с плавающей запятой, верно?   -  person KamilCuk    schedule 19.08.2020
comment
@AsteroidsWithWings Я пишу это как класс для своей личной библиотеки! Вопрос заключается в написании алгоритма в функции convert().   -  person Francis Cugler    schedule 19.08.2020
comment
@FrancisCugler Хорошо.   -  person Asteroids With Wings    schedule 19.08.2020
comment
@KamilCuk У человека А есть рецепт приготовления печенья с шоколадной крошкой, у человека С есть рецепт приготовления печенья с шоколадной крошкой... Просто потому, что я могу!   -  person Francis Cugler    schedule 19.08.2020
comment
@KamilCuk Ну, я буду использовать это с другими моими классами в моих библиотеках, и меня интересуют типы и то, как я буду их использовать. Это также хорошая практика. Мне нравится сначала писать и проектировать алгоритм, чтобы лучше понять, как он работает, прежде чем я просто начну использовать один из библиотек, предполагая, что он будет делать то, что я хочу.   -  person Francis Cugler    schedule 19.08.2020
comment
@AsteroidsWithWings, вы заявили, зачем вам нужны показатели до +/-9 ...... Это кажется маловероятным. Я планирую использовать его в симуляторе для выполнения расчетов как в масштабе доски, так и в космическом масштабе, и у меня будет несколько слоев масштабирования!   -  person Francis Cugler    schedule 19.08.2020
comment
относительно проверки знака, а затем использовать abs или не использовать его, учтите, что либо abs уже проверяет подписанность (и возвращает исходное значение, когда оно было положительным), и если это не так (потому что он просто устанавливает бит знака), то даже лучше, в любом случае вам не нужно проверять знак перед вызовом abs   -  person 463035818_is_not_a_number    schedule 19.08.2020
comment
@ idclev463035818 Спасибо за ясность ... иногда просто нужно напоминание!   -  person Francis Cugler    schedule 19.08.2020
comment
однако примечание здесь может иметь отношение к вам: en.cppreference.com/w /c/число/математика/абс   -  person 463035818_is_not_a_number    schedule 19.08.2020
comment
Вам нужны показатели порядка 30, 40, 50 по шкале Планка. Не 9 миллиардов миллиардов миллиардов.   -  person Asteroids With Wings    schedule 19.08.2020
comment
@AsteroidsWithWings, но я выхожу за рамки планки, я раздвигаю границы возможного! Почему только потому, что я могу! Не написано на камне, что длина Plank является наименьшей длиной! Вы всегда можете делить на 2 и никогда не получить 0, и вы можете делать это бесконечно и все равно никогда не достичь 0... Так что, кто знает, может быть, имея такую ​​точность, можно изобрести целую новую область математики и физики!   -  person Francis Cugler    schedule 19.08.2020
comment
Не высечено на камне, что длина доски — это наименьшая длина! Ну, это...   -  person Asteroids With Wings    schedule 19.08.2020
comment
@AsteroidsWithWings Я бросу вызов всему и всему! Нет никаких ограничений! Однако моя библиотека основана не только на точности floating-point, она также основана на различных системах счисления... Поэтому, если пользователь использует шаблон, скажем, ‹16›, тогда он будет выполнять логарифм 16 математики... если для него установлено значение ‹ 2> он будет выполнять двоичную базовую математику ... Ну, математика в настоящее время выполняется в десятичной системе счисления. Как только я заработаю основные функции, я буду беспокоиться о математических расчетах в других базах...   -  person Francis Cugler    schedule 19.08.2020
comment
@AsteroidsWithWings Этот класс будет не просто представлять 1,3x10^3 + -9,24^-6, он также сможет представлять 4Ax16^-3A + -FCx16^2B и т. д.   -  person Francis Cugler    schedule 19.08.2020