Модераторы: bsa
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Число с плавающей строкой в строку 
:(
    Опции темы
cupper
Дата 25.4.2011, 09:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 525
Регистрация: 29.11.2006

Репутация: нет
Всего: 1



Нужно преобразовывать число с плавающей точкой (представленное в виде класса, мантиса + экспонента) в строку. В классе есть метод перевода числа в double, он не подходит так как в некоторых случаех сбивается точность и получается не совсем то что хотелось получить.

Написал вот такую функцию
Код

const std::string Book_entry::decimal_to_string(const Engine::Decimal& dec) const
{
    boost::int64_t mantisa = dec.getMantissa();
    boost::int32_t exp = dec.getExponent();
    boost::int32_t exp_abs = std::abs(exp);

    double val = dec.toDouble();

    std::string double_val = boost::lexical_cast<std::string>(mantisa);
    std::size_t len_mantisa = double_val.size();

    if(exp > 0)
    {
        std::string zero(exp, '0');
        double_val.append(zero);
    }
    else if(exp < 0)
    {
        if(exp_abs < len_mantisa)
            double_val.insert(len_mantisa - exp_abs, ".");
        else
        {
            std::string zero(exp_abs - len_mantisa + 1, '0');
            double_val.insert(0, zero);
            double_val.insert(1, ".");
        }
    }

    return double_val;
}


Проверил на таком наборе данных
Код

Decimal(3475, 0))
Decimal(3475, 2))
Decimal(3475, -2))
Decimal(3475, -5))
Decimal(3475, -4))

Получил следующее
Код

3475
347500
34.75
0.03475
0.3475


если я правильно понял теорию, то все правильно. 

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

Если говорить кратко, то
1.  если экспонента > 0 то мы просто к мантиссе прибавляем в конце это количество нулей.
2.  если экспонента = 0 мы оставляем число как оно есть в мантиссе.
3. если экспонента < 0, то нужно производить отсчет с права на лево в мантиссе на абсолютное значение мантиссы, дополняя его с лева нулями, и после первого нуля с левой стороны ставить запятую.

Вроде больше нету других вариантов ?
PM MAIL   Вверх
xvr
Дата 25.4.2011, 12:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 35
Всего: 223



А как у вас должно напечататься Decimal(3475, -1000) или Decimal(3475, 1000) ?

Добавлено через 32 секунды
Кроме того, у вас экспонента десятичная?

PM MAIL   Вверх
borisbn
Дата 25.4.2011, 12:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 21
Всего: 135



вроде всё правильно. Я б переделал последний if так
Код

        else
        {
            std::string zero(exp_abs - len_mantisa, '0'); // убрал + 1
            double_val = "0." + zero + double_val;
        }

просто, чтобы убрать 2 insert'а, но IMHO это некритично.
Ещё б передавать символ разделителя разрядов. По-умолчанию пусть будет '.'
Код

const std::string Book_entry::decimal_to_string(const Engine::Decimal& dec, char decSeparator = '.' ) const


Ну ище пару моментов. Зачем в ф-ции decimal_to_string, возвращающей копию строки, возвращаемое значение (копия) const ?
Цитата

const std::string Book_entry::decimal_to_string


Цитата(cupper @  25.4.2011,  09:47 Найти цитируемый пост)
 double val = dec.toDouble();

отладочная фигня ?


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
cupper
Дата 25.4.2011, 22:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 525
Регистрация: 29.11.2006

Репутация: нет
Всего: 1



Цитата(xvr @ 25.4.2011,  12:37)
А как у вас должно напечататься Decimal(3475, -1000) или Decimal(3475, 1000) ?

Добавлено @ 12:37
Кроме того, у вас экспонента десятичная?

Decimal(3475, -1000) = 0.00000...003475
Decimal(3475, 1000) = 347500000...0000

где нулей в первом случаем будет 1000 - len("3475")
а во втором случае 1000 нулей добавится.

да экспонента и мантисса целы числа. Мантисса 64 разрядная, экспонента 32 разрядная. Не я архитектор класса, но я столкнулся с тем что нет нормального способа его представления в строку.

Код

Я б переделал последний if так

да, так по лучше смотрится.

Про конст тут такая заморочка
Код

if(Decimal_to_string(...) = "34.75")

ошибка допущенная по глупости всплывет сразу. Без const будет epic fail. Об этом во многих книжках пишут. Вот приучил себя к хорошему стилю.
Цитата

отладочная фигня ?

она самая smile

Цитата

Ещё б передавать символ разделителя разрядов. По-умолчанию пусть будет '.'

для целостности картины, нужно. Для моей задачи нет необходимости.





Это сообщение отредактировал(а) cupper - 25.4.2011, 22:16
PM MAIL   Вверх
borisbn
Дата 25.4.2011, 23:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 21
Всего: 135



Цитата(cupper @  25.4.2011,  22:06 Найти цитируемый пост)
if(Decimal_to_string(...) = "34.75")

Цитата(cupper @  25.4.2011,  22:06 Найти цитируемый пост)
Без const будет epic fail. Об этом во многих книжках пишут

в данном случае не будет (у std::string нет оператора приведения ни к bool, ни к int ни к указателю), но в общем случае за совет спасибо. Попробую тоже принять для себя такое правило smile


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
volatile
Дата 25.4.2011, 23:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(cupper @  25.4.2011,  22:06 Найти цитируемый пост)
Decimal(3475, -1000) = 0.00000...003475
Decimal(3475, 1000) = 347500000...0000
где нулей в первом случаем будет 1000 - len("3475")
а во втором случае 1000 нулей добавится.

Если при вычислении возникнет большое (или маленькое) число, то.. будет полный ахтунг.
допустим exp ~ 2**31
std::string zero(exp, '0'); // создали строку размером 2 гигабайта
double_val.append(zero); // откопировали строку в другую. уже 4 гига оперативки.
..
при exp ~ -2**31
std::string zero(exp_abs - len_mantisa + 1, '0'); // создали строку размером 2 гигабайта
double_val.insert(0, zero); // сдвинули на 1 строку размером 2 гигабайта. (фактически компилятор создаст копию 2 гигов.)
double_val.insert(1, ".");  // еще раз сдвинули на 1 строку размером 2 гигабайта.
..
return double_val; // И под занавес откопировали еще разок.
итого 6 гигов оперативки на работу строль незамысловатой функции.

Это не программа, а бомба замедленного действия. И когда-нибудь она обязательно сработает.

PM MAIL   Вверх
mes
Дата 26.4.2011, 01:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 79
Всего: 250



Цитата(cupper @  25.4.2011,  21:06 Найти цитируемый пост)
if(Decimal_to_string(...) = "34.75"

нельзя ли уточнить, в чем проявляется разница при наличии/отсутствия const в примере ?

Цитата(cupper @  25.4.2011,  21:06 Найти цитируемый пост)
Об этом во многих книжках пишут.

 smile 
 smile 



--------------------
PM MAIL WWW   Вверх
volatile
Дата 26.4.2011, 02:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(mes @  26.4.2011,  01:11 Найти цитируемый пост)
нельзя ли уточнить, в чем проявляется разница при наличии/отсутствия const в примере ?

mes, при конст - компилер выдаст ошибку, что надо L-value и т.д.
При не конст - он проглотит, ну может выдаст воринг (хотя по умолчанию, напрмер, студия даже воринг не выдает в таких случаях)
Подразумевается, что здесь программер опечатался и хотел:  if(Decimal_to_string(...) == "34.75"
всмысле два ==, а не одно =  
PM MAIL   Вверх
volatile
Дата 26.4.2011, 03:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



mes, Вот покопался, нашел у Мейерса, ТС просто не совсем удачный пример с ифом привел.

Мейерс С. - Эффективное использование C++. 55 верных советов улучшить структуру и код ваших программ.(3-изд)
user posted image
PM MAIL   Вверх
mes
Дата 26.4.2011, 03:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 79
Всего: 250



Цитата(volatile @  26.4.2011,  02:09 Найти цитируемый пост)
Вот покопался, нашел у Мейерса, ТС просто не совсем удачный пример с ифом привел.

ага этот пример показательный, спасибо smile




--------------------
PM MAIL WWW   Вверх
cupper
Дата 26.4.2011, 08:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 525
Регистрация: 29.11.2006

Репутация: нет
Всего: 1



Цитата(volatile @ 25.4.2011,  23:54)
Цитата(cupper @  25.4.2011,  22:06 Найти цитируемый пост)
Decimal(3475, -1000) = 0.00000...003475
Decimal(3475, 1000) = 347500000...0000
где нулей в первом случаем будет 1000 - len("3475")
а во втором случае 1000 нулей добавится.

Если при вычислении возникнет большое (или маленькое) число, то.. будет полный ахтунг.
допустим exp ~ 2**31
std::string zero(exp, '0'); // создали строку размером 2 гигабайта
double_val.append(zero); // откопировали строку в другую. уже 4 гига оперативки.
..
при exp ~ -2**31
std::string zero(exp_abs - len_mantisa + 1, '0'); // создали строку размером 2 гигабайта
double_val.insert(0, zero); // сдвинули на 1 строку размером 2 гигабайта. (фактически компилятор создаст копию 2 гигов.)
double_val.insert(1, ".");  // еще раз сдвинули на 1 строку размером 2 гигабайта.
..
return double_val; // И под занавес откопировали еще разок.
итого 6 гигов оперативки на работу строль незамысловатой функции.

Это не программа, а бомба замедленного действия. И когда-нибудь она обязательно сработает.

В общем случае да. У меня же не стоит задача в которой такие числа хоть когда то смогли бы фигурировать. В общем мое решение для моей области применения, но в общем случае оно на врядли подойдет, вы правы.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0609 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.