Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > Число с плавающей строкой в строку


Автор: cupper 25.4.2011, 09:47
Нужно преобразовывать число с плавающей точкой (представленное в виде класса, мантиса + экспонента) в строку. В классе есть метод перевода числа в 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, то нужно производить отсчет с права на лево в мантиссе на абсолютное значение мантиссы, дополняя его с лева нулями, и после первого нуля с левой стороны ставить запятую.

Вроде больше нету других вариантов ?

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

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

Автор: borisbn 25.4.2011, 12:59
вроде всё правильно. Я б переделал последний 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();

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

Автор: cupper 25.4.2011, 22:06
Цитата(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

Цитата

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

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




Автор: borisbn 25.4.2011, 23:02
Цитата(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

Автор: 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 гигов оперативки на работу строль незамысловатой функции.

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

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

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

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

 smile 
 smile 

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

mes, при конст - компилер выдаст ошибку, что надо L-value и т.д.
При не конст - он проглотит, ну может выдаст воринг (хотя по умолчанию, напрмер, студия даже воринг не выдает в таких случаях)
Подразумевается, что здесь программер опечатался и хотел:  if(Decimal_to_string(...) == "34.75"
всмысле два ==, а не одно =  

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

Мейерс С. - Эффективное использование C++. 55 верных советов улучшить структуру и код ваших программ.(3-изд)
user posted image

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

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


Автор: cupper 26.4.2011, 08:34
Цитата(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 гигов оперативки на работу строль незамысловатой функции.

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

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

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)