11

我正在研究用 g++ 的 std::decimal::decimal32/64/128 类型替换我们的代码中的双精度,以达到货币数量和价格的目的,但是我陷入了如何最好地输入和输出的问题上数据。具体来说,似乎没有任何用于与字符串进行转换的例程,并且字符串流机制不会针对这些类型进行编译。我看到这样做的唯一方法是使用 double 作为中间类型,但是如果我们总是通过双精度输入和输出,这肯定至少部分违背了使用小数类型的目的?

我确定我在这里不了解某些内容,因此欢迎就如何最好地使用这些类型提供一些反馈。

编辑:

我已经破解了几个输入/输出例程,但是我对任何一个都不满意。输入几乎没有鲁棒性(不支持科学记数法),输出例程过于简单,更不用说由于双重转换而导致的低效。

#define MAX_DEC_LEN 17

std::decimal::decimal64 FromString(const char* str)
{
    if (strlen(str) > MAX_DEC_LEN)
        throw std::runtime_error("bad input");
    char buf[MAX_DEC_LEN+1];
    strncpy(buf, str, MAX_DEC_LEN+1);
    char* point(NULL); 
    if ((point = strchr(buf, '.')) != NULL)
        *(point++) = '\0';
    std::decimal::decimal64 ret(atoi(buf));
    if (point != NULL && *point != '\0')
    {
        int exponent(strlen(point));
        long long unsigned coeff(atoi(point));
        std::decimal::decimal64 d2(std::decimal::make_decimal64(coeff, -exponent));
        if (*buf == '-')
            ret -= d2;
        else
            ret += d2;
    }
    return ret;    
}

std::string ToString(std::decimal::decimal64 dec)
{
    double d(std::decimal::decimal_to_double(dec));
    std::ostringstream oss;
    oss << std::fixed << std::setprecision(6) << d;
    return oss.str();
}

我真的对这两个方面都有更好的追求,再加上一轮(以特定的精度)来四舍五入(请原谅双关语)

4

1 回答 1

6

Decimal TR分别在第 3.2.10 节和第 3.2.11 节中定义了输入和输出的重载。从外观上看,它们不是由 gcc 实现的。gcc 中的十进制支持是根据 libdecnum 实现的,它提供了从字符串转换为字符串的例程。我将使用 I/O 运算符创建一个简单的实现来开始。

编辑于 2012-10-17:查看格式化 gcc 库(std::decimal::decimal64和系列)中的十进制值显示,不幸的是 gcc 没有安装 decNumber 库头文件或库。此外,decNumber的其他来源与 gcc 附带的版本不太一致。结果,到目前为止,我发现格式化十进制数字的唯一方法是使用显式声明并在编译 gcc 期间使用库构建。

简单的部分是源代码,尽管实现相当简单。首先,将进入合适标题的声明,例如<decimal/decimal>

std::ostream& operator<< (std::ostream&, std::decimal::decimal32 const&);
std::ostream& operator<< (std::ostream&, std::decimal::decimal64 const&);
std::ostream& operator<< (std::ostream&, std::decimal::decimal128 const&);

一个相当简单的实现一些格式化的东西,虽然没有任何选项可能看起来像这样:

extern "C" char* decimal32ToString(std::decimal::decimal32 const*, char*);
extern "C" char* decimal64ToString(std::decimal::decimal64 const*, char*);
extern "C" char* decimal128ToString(std::decimal::decimal128 const*, char*);

std::ostream& operator<< (std::ostream& out,
                          std::decimal::decimal32 const& value)
{
    char buffer[128];
    decimal32ToString(&value, buffer);
    return out << buffer;
}

std::ostream& operator<< (std::ostream& out,
                          std::decimal::decimal64 const& value)
{
    char buffer[128];
    decimal64ToString(&value, buffer);
    return out << buffer;
}

std::ostream& operator<< (std::ostream& out,
                          std::decimal::decimal128 const& value)
{
    char buffer[128];
    decimal128ToString(&value, buffer);
    return out << buffer;
}

有了这个,仍然存在一个问题,除非使用某种程度的优化,即-O1(或更高),否则我无法使用小数构建任何东西。除非使用优化,否则存在未引用的符号,但这与打印值完全无关。为了获得实现中使用的函数的定义,我需要链接到在libdecnumber.a构建 gcc 时创建的库:

g++ -o prog decimal-io.cpp main.cpp <gcc-build-root>/libdecnumber/libdecnumber.a

除此之外,我有自己的Decimal TR实现,带有一些扩展,并基于 decnumber 库并正确实现 I/O。我的实现有望在某个时候公开发布,但不会很快。

于 2012-10-12T19:22:41.307 回答