Как изящнее реализовать банковское округление?
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 15.03.21 20:17
Оценка:
Здравствуйте!

Собсно, если кто не помнит — https://en.wikipedia.org/wiki/Rounding#Round_half_to_even
Ну, и парнокопытноепарное к нему — https://en.wikipedia.org/wiki/Rounding#Round_half_to_odd

Все округления, что выше — реализовал, всё вышло довольно просто, а тут что-то затупил.

Числа у меня свои, с фиксированной точностью, но точка — плавает Но только влево-вправо, а не по экспоненте. Число в виде делимое/делитель, где делитель — это 10 в какой-то степени. Делимое — целое знаковое, делитель — целое беззнаковое

Есть методы:
  Скрытый текст
void precisionExpandTo( precision_t p ); // расширяем точность, ничего не теряем по дороге
void precisionShrinkTo( precision_t p ); // уменьшаем точность, что упало, то пропало - просто обрезаем
void precisionFitTo( precision_t p );    // тут как пойдёт

unum_t getLowestDecimalDigit() const;    // наименьшая десятичная циферка - для 3.14159 - это 9
bool isDigitEven( unum_t d );
bool isDigitOdd( unum_t d );
void replaceLowestDecimalDigit( unum_t d );


// Тут может стоит поменять Minimal и Precision местами
Decimal makeMinimalPrecisionOne() const;  // Единичка самого младшего разряда текущей точности - для 3.14159 это 0.00001
Decimal makeMinimalPrecisionFive() const; // Пятёрка самого младшего разряда текущей точности  - для 3.14159 это 0.00005


Обычное (математическое) округление выглядит так:
  Скрытый текст
            case RoundingMethod::roundHalfTowardsInf: // roundHalfAwayFromZero, roundMath
                 {
                     precisionFitTo(requestedPrecision + 1);
                     *this += makeMinimalPrecisionFive() * sign();
                     precisionShrinkTo( requestedPrecision );
                 }
                 break;


Floor/Ceil/Trunc:
  Скрытый текст
            case RoundingMethod::roundDown: // roundFloor
                 {
                     precisionFitTo(requestedPrecision + 1);

                     unum_t ldd = getLowestDecimalDigit();
                     precisionShrinkTo( requestedPrecision );

                     if (ldd==0)
                         break;

                     if (sign()<0)
                     {
                         *this -= makeMinimalPrecisionOne();
                     }
                 }
                 break;
        
            case RoundingMethod::roundUp: // roundCeil
                 {
                     precisionFitTo(requestedPrecision + 1);
                     unum_t ldd = getLowestDecimalDigit();
                     precisionShrinkTo( requestedPrecision );

                     if (ldd==0)
                         break;

                     if (sign()>0)
                     {
                         *this += makeMinimalPrecisionOne();
                     }
                 }
                 break;
        
            case RoundingMethod::roundTowardsZero: // roundAwayFromInf, roundTrunc
                 {
                     precisionFitTo(requestedPrecision + 1);
                     precisionShrinkTo( requestedPrecision );
                 }
                 break;


Пока всё, что рожаю, выглядит как кусок говна.

Но наверное тоже можно просто и изящно сделать?
Маньяк Робокряк колесит по городу
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.