如何对包含c ++中的double值的字符串强制执行精度

时间:2012-04-04 13:55:57

标签: c++ c string double precision

示例输入字符串:

char *str = "12345.567675";

如果我需要小数点后3位的精度,那么所需的输出:

str = "12345.568";

有没有办法在不将字符串转换为double并返回字符串?

的情况下执行此操作

5 个答案:

答案 0 :(得分:2)

是的,在高层次上:
1.搜索'。'在字符串中。
2.如果'。'的位置+ 3小于你所做的长度。
3.否则,将字符串连接到'。'的位置。 + 3.
4.这里很棘手:你需要检查下一个字符是否存在,('。'+ 4),如果它的值> gt = = 5 goto 4.1(否则转到5)
4.1。将字符串复制到左侧有一个空格的新字符串(因为9.9999将在'4'循环中更改为10.0000)并将指针(P)设置为该字符串中的最后一个字符。
4.2。如果* P在0到8之间加1,则转到5 4.3。如果* P为9,则将其设置为零,将指针向左移动(-1)并转到4.2
4.4。如果* P为'。',则将指针向左移动(-1)并转到4.2 5.删除小数点右边的所有0(如果需要,还有自己的小数点),你完成了!!! 6.删除所有内容,并使用双转换方法...

答案 1 :(得分:1)

您可以使用递归来完成此操作。

void roundstr(std::string& strp) {
    char clast;
    char nlast;
    int sl(strp.length()), ipos(0);

    if (strp[sl - 1] == '.') { // skip the dot
        strp.erase(strp.end() - 1);
        nlast='.';
        roundstr(strp);
        return;
    }

    if (strp[sl - 2] == '.') { // handle dot is next char
        ipos = 1;
    }

    if (sl == 1) { // handle first char
        nlast = '0'; // virtual 0 in front of first char
        clast = strp[1];
    } else {
        clast = strp[sl - 1]; // current (last) char
        nlast = strp[sl - 2 - ipos]; // next to last char
    }

    if (clast >= '5') { // need to operate only if meet 5 or larger, otherwise stop
        nlast++;
        strp.erase(strp.end() - 1); // remove the last char from the string
        if (nlast == ':') { // if need to round further
            strp.replace(strp.end() - 1 - ipos, strp.end() - ipos, 1, nlast);
            clast = '0'; // keep current char value
            roundstr(strp);
        } else {
            strp.replace(strp.end() - 1 - ipos, strp.end() - ipos, 1, nlast);
            if(clast==':') clast = '0';
        }
    }

    sl = strp.length();
    if (nlast == ':') {
        if (ipos == 1) {
            strp += '.';
        } else {
            strp += '0';
        }
    } else if (nlast=='.' && strp[sl-1] != '.') {
        strp += '.';
    } else {
        if (ipos == 1 && strp[sl-1]!='.') {
            strp += '.';
        } else {
            strp += clast;
        }
    }

    return;
}

你这样称呼它:

#include <string>
#include <iostream>
#include <iterator>
#include <stdlib.h>

void roundstr(std::string&);
int main(int argc, char* argv[]) {
    int p;
    std::string strp;

    switch (argc) {
    case 2:
        p = 2;
        break;
    case 3:
        p = atoi(argv[2]);
        strp = argv[1];
        break;
    default:
        return 1;
        break;
    }

    std::cout << strp << " " << p << std::endl;
    roundstr(strp);
    strp.erase(strp.end()-p, strp.end());
    std::cout << strp << std::endl;
    return 0;
}

你可以看到你必须处理删除多余的数字,但是编写一个包装函数,甚至是一个类在构造过程中自动执行此类操作并不困难。

如果使用c-strings而不是std::string,这可能会更快。如果您计划执行重型符号算术,我建议将所有std::stringchar替换为char *,但在删除添加值时应该更加小心。

答案 2 :(得分:0)

在字符串中找到点。然后,找到该位置后的第四个字符。将子字符串从0返回到点+3的位置,然后调整最后一个字符 - 如果原始字符串中的点后第四个字符大于或等于5,则增加最后一个字符(或设置为'0',如果'9 '并增加prievous等等)。如果它小于5 - 什么都不做,只返回原始字符串的子串。

虽然,我认为如果你只是将它转换为浮点数就不会达到性能,请使用(例如)boost::format将其四舍五入。

答案 3 :(得分:0)

首先将它转换为浮动。

int main()
{
    std::string f = "12345.567675";

    std::ostringstream ss;
    float x = boost::lexical_cast<float>(f);
    ss << std::fixed << std::setprecision(3);
    ss << x;
    std::string s = ss.str();

    std::cout << s << "\n";

    return 0;
}

结果如下:

./a.out 
12345.567

答案 4 :(得分:-2)

假设你总是有一个点,后面至少有3位数字:

char *str = "12345.567675";
char *p = str;

while ( *p != '.' )
{
    printf( "%c", *p++ );
    // find a dot
}

for ( int i = 0; i < 4; i++ )
{
    printf( "%c", *p++ );
}