Russian Qt Forum
Ноябрь 24, 2024, 03:56 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 2 [3]   Вниз
  Печать  
Автор Тема: Как правильно сделать преобразование для целых и вещественных чисел?  (Прочитано 22483 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #30 : Март 01, 2011, 13:03 »

1) Флоты везде 4 (float) и 8 (double) байт и везде следуют IEEE.

2) qint32 определяется через typedef, т.е. это не новый тип, поэтому проблем нет

3)
Цитировать
if (d > std::numeric_limits<float>::max())
Это длинно и неудобно, Сделайте пределы static членами класса чтобы в случае чего подстроить, напр
Код
C++ (Qt)
struct NNumeric {
...
static void InitLimits( void ) { mFloatMax = std::numeric_limits<float>::max(); }
static float mFloatMax;
};
 
Записан
Eten
Гость
« Ответ #31 : Март 02, 2011, 05:44 »

3)
Цитировать
if (d > std::numeric_limits<float>::max())
Это длинно и неудобно, Сделайте пределы static членами класса чтобы в случае чего подстроить, напр
Код
C++ (Qt)
struct NNumeric {
...
static void InitLimits( void ) { mFloatMax = std::numeric_limits<float>::max(); }
static float mFloatMax;
};
 

А зачем мне создавать лишний статик-член класса NNumeric, если можно обойтись несколькими статик функциями возвращающими границы (как InitLimits, только с возвращением)?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #32 : Март 02, 2011, 10:06 »

А зачем мне создавать лишний статик-член класса NNumeric, если можно обойтись несколькими статик функциями возвращающими границы (как InitLimits, только с возвращением)?
Можно и так, дело вкуса. Смысл один - не разбрасывать ту длинную простыню по всему тексту класса
Записан
Eten
Гость
« Ответ #33 : Март 02, 2011, 12:37 »

В общем переписал свой класс и в итоге получилось запрятывание чисел диапазона float и int32, типом double. Разве, что способ записи целых чисел изменился, но зато добился полного контроля диапазона, как для int32, так float. Код стал компактнее, плюс в той функции, что я ранее приводил сильно сократил кол-во строк до понятного кода, т.к. теперь контроль границ у меня происходит внутри класса в виде внутренних функций. А, пока места с NAN еще не сделал, также не стоит забывать про погрешности у double (происходит при експоненте 11 или -11 у числа, но int32 эта погрешность не затрагивает, как во float-е). +/-inf приравнивается к максимальным границам, для моей ТЗ этого достаточно.

Собственно, код класса NNumeric:

Код:
#include <limits>
#include <cmath>

class NNumeric{
public:
    inline NNumeric(double Value = 0) {this->data._isreal = true; this->setValue(Value); this->data._id = -1; this->data._constvalue = false; this->data._name = "";}
    inline NNumeric(const NNumeric& a) {this->setConstValue(a.data._constvalue); this->setID(a.data._id); this->setName(a.data._name); this->setIsReal(a.data._isreal); this->setValue(a.data._value);}

    inline double round() {return floor(this->Value() + 0.5);}
    inline double fractional() {return this->Value() < 0.0 ? this->Value() - ceil(this->Value()) : this->Value() - floor(this->Value());}
    inline double integer() {return this->Value() < 0.0 ? ceil(this->Value()) : floor(this->Value());}

    inline int ID() {return this->data._id;}
    inline void setID(int ID) {this->data._id = ID;}
    inline bool ConstValue() {return this->data._constvalue;}
    inline void setConstValue(bool ConstValue) {this->data._constvalue = ConstValue;}
    inline QString Name() {return this->data._name;}
    inline void setName(QString Name) {this->data._name = Name;}
    inline void setIsReal(bool IsReal) {this->data._isreal = IsReal;}
    //Если ложно, то значение принимается и выдается (при печати числа на экране)
    // с отсечение дробной части числа и соблюдением границ типа qint32.
    inline bool IsReal() const {return this->data._isreal;}
    inline void setValue(double Value) {if (!this->IsReal()) Value = this->CheckingInt32Borders(Value); else Value = this->CheckingFloatBorders(Value); this->data._value = Value;}
    inline double Value() const {return double(this->CheckingFloatBorders(this->data._value));}

    inline void operator=(const NNumeric& a) {this->setConstValue(a.data._constvalue); this->setID(a.data._id); this->setName(a.data._name); this->setIsReal(a.data._isreal); this->setValue(a.data._value);}
    inline operator QString() {return QString::number(this->data._value);}
    inline operator double() {return double(this->CheckingFloatBorders(this->Value()));}
    inline operator float() {return this->CheckingFloatBorders(this->Value());}
    inline operator qint32() {return this->CheckingInt32Borders(this->data._value);}
    inline void operator++(int) {if (!this->IsReal()) this->data._value = this->CheckingInt32Borders(this->data._value+1); else this->data._value = this->CheckingFloatBorders(this->data._value+1);}
    inline void operator--(int) {if (!this->IsReal()) this->data._value = this->CheckingInt32Borders(this->data._value-1); else this->data._value = this->CheckingFloatBorders(this->data._value-1);}
    inline bool operator==(const NNumeric& a) {return this->data._value == a.Value();}
    inline bool operator!=(const NNumeric& a) {return this->data._value != a.Value();}
    inline bool operator&&(const NNumeric& a) {return this->data._value && a.Value();}
    inline bool operator||(const NNumeric& a) {return this->data._value || a.Value();}
    inline bool operator<(const NNumeric& a) {return this->data._value < a.Value();}
    inline bool operator<=(const NNumeric& a) {return this->data._value <= a.Value();}
    inline bool operator>(const NNumeric& a) {return this->data._value > a.Value();}
    inline bool operator>=(const NNumeric& a) {return this->data._value >= a.Value();}

private:

    inline long double Int32Max() const {return std::numeric_limits<qint32>::max();}
    inline long double Int32Min() const {return std::numeric_limits<qint32>::min();}
    inline long double FloatMax() const {return std::numeric_limits<float>::max();}
    inline long double FloatMin() const {return std::numeric_limits<float>::min();}
    inline float CheckingFloatBorders (double Value) const
    {
        //В этой функции +/-inf приравниваются к max и min границам.
        double d = fabs(Value);
        bool usign = Value >= 0.0;

        if (d >= this->FloatMax())
            return (usign) ? this->FloatMax() : -this->FloatMax();

        if (d <= this->FloatMin() && d > 0.0)
            return (usign) ? this->FloatMin() : -this->FloatMin();

        return float(Value);
    }
    inline qint32 CheckingInt32Borders(double Value) const
    {
        if (Value >= Int32Max()) return Int32Max();

        if (Value <= Int32Min()) return Int32Min();

        return qint32(Value);
    }


    struct NData {
    //если идентификатор равен -1, значит это либо временная переменная, либо константное значение
    qint32 _id;
    //константные или временные значения имен не имеют, только переменные.
    QString _name;
    double _value;
    bool _isreal;
    //это указывает на константное значение
    bool _constvalue;
    };
    NData data;
};

Пример суммы для целых и вещественных чисел в классе NNumeric:
Код:
            if (!arg1.IsReal() && !arg2.IsReal())
            {//здесь оба целые
                 arg0.setIsReal(false);
                 arg0.setValue(double(arg1) + double(arg2));
            }
            else
                arg0 = double(arg1) + double(arg2);
« Последнее редактирование: Март 02, 2011, 14:05 от Eten » Записан
Eten
Гость
« Ответ #34 : Март 02, 2011, 14:44 »

Посмотрел ситуацию с nan и +/-inf. Все это ситуации с делением на ноль и мне негде их конролировать внутри класса, т.к. у него нет перегруженного оператора "/", а также целочисленного деления и остатка от него (это производится в той самой функции с мат. операциями там же). Погрешности в double - это уже отдельная тема. В итоге считаю свой вопрос уж точно раскрытым именно с моей постановкой задачи для класса NNumeric.

З.Ы.
Добился таки желаемого.  Веселый
Записан
brankovic
Гость
« Ответ #35 : Март 02, 2011, 15:44 »

Посмотрел ситуацию с nan и +/-inf. Все это ситуации с делением на ноль и мне негде их конролировать внутри класса

переполнение в double тоже даст inf, а операции с inf могут дать nan
Записан
Eten
Гость
« Ответ #36 : Март 03, 2011, 05:10 »

Посмотрел ситуацию с nan и +/-inf. Все это ситуации с делением на ноль и мне негде их конролировать внутри класса

переполнение в double тоже даст inf, а операции с inf могут дать nan
Моей задачке это очень просто лечится. Границы, как видить соблюдаются, а Nan в число не запишешь, кроме умышленных способов, которые у меня не осуществимы. Т.е. на этапе записи числа, ситуация с +/-inf и nan исключена, а перед выполнением математической операции "/", где собственно и возникает nan при делении на ноль (больше я ситуаций не находил), достаточно проверить чтобы аргумент, на который делят не быль равен нулю, иначе вызываем особую ситуацию. В итоге, ситуации с переполнением у меня отпадают из-за проверки границ, а не допускание nan производится проверкой до выполнения мат. операции.  Подмигивающий
Записан
brankovic
Гость
« Ответ #37 : Март 03, 2011, 08:39 »

а Nan в число не запишешь, кроме умышленных способов, которые у меня не осуществимы. Т.е. на этапе записи числа, ситуация с +/-inf и nan исключена
...
 В итоге, ситуации с переполнением у меня отпадают из-за проверки границ, а не допускание nan производится проверкой до выполнения мат. операции.  Подмигивающий

да, если * и / нет, а +- проверяются, то не получится inf

ps: в конструкторе ещё нет проверки входящего double на inf/nan.

на правах офтопа (code review Улыбающийся):
1. все операторы и функции, которые не изменяют объект (операторы == != > < и т.д.) лучше делать const, иначе они не будут работать в некоторых случаях (в std::map, например).
2. явный конструктор копирования, как и operator= в этом классе не нужны (определенные по умолчанию здесь вполне подойдут)
3. inline в теле класса писать не обязательно, если метод определён в классе, то inline  подразумевается.
Записан
Eten
Гость
« Ответ #38 : Март 03, 2011, 09:18 »

а Nan в число не запишешь, кроме умышленных способов, которые у меня не осуществимы. Т.е. на этапе записи числа, ситуация с +/-inf и nan исключена
...
 В итоге, ситуации с переполнением у меня отпадают из-за проверки границ, а не допускание nan производится проверкой до выполнения мат. операции.  Подмигивающий

да, если * и / нет, а +- проверяются, то не получится inf

ps: в конструкторе ещё нет проверки входящего double на inf/nan.

на правах офтопа (code review Улыбающийся):
1. все операторы и функции, которые не изменяют объект (операторы == != > < и т.д.) лучше делать const, иначе они не будут работать в некоторых случаях (в std::map, например).
2. явный конструктор копирования, как и operator= в этом классе не нужны (определенные по умолчанию здесь вполне подойдут)
3. inline в теле класса писать не обязательно, если метод определён в классе, то inline  подразумевается.
1) про const учту, хотя по началу думал, что так делать излишне.
2) а как сделан конструктор копирования и operator= по умолчанию, через inline или без него?
3) если я правильно понял, объявленная и определенная функция в классе, то inline будет проставлен уже без моей помощи?
Записан
brankovic
Гость
« Ответ #39 : Март 03, 2011, 11:03 »

2) а как сделан конструктор копирования и operator= по умолчанию, через inline или без него?
3) если я правильно понял, объявленная и определенная функция в классе, то inline будет проставлен уже без моей помощи?

2) работает как если бы был inline
3) да

вообще inline лучше не злоупотреблять, поскольку он обычно не нужен. Например gcc на -O3 спокойно инлайнит не-инлайн функции.
Записан
Страниц: 1 2 [3]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.184 секунд. Запросов: 22.