4

示例输入字符串:

char *str = "12345.567675";

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

str = "12345.568";

有没有办法在不将字符串转换为字符串的情况下做到这一点double

4

5 回答 5

2

是的,在高层次上:
1. 搜索 '.' 在字符串中。
2.如果'.'的位置 + 3 小于您所做的长度。
3. 否则,将字符串连接到 '.' 的位置 + 3.
4. 这里很棘手:您需要检查下一个字符是否存在,('.' + 4),如果它的值 >= 5,则转到 4.1(否则转到 5)
4.1。将字符串复制到一个在左侧多出一个空格的新字符串(因为在 '4' 循环中 9.9999 将更改为 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.删除所有内容,并使用双重转换方法...

于 2012-04-04T14:03:40.923 回答
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. 如果您打算执行繁重的符号运算,我建议您替换 allstd::stringcharwithchar *但在删除添加值时应该更加小心。

于 2012-04-09T20:57:42.797 回答
0

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

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

于 2012-04-04T14:02:30.783 回答
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
于 2012-04-04T14:15:05.330 回答
-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++ );
}
于 2012-04-04T14:15:22.570 回答