【问题标题】:std::decimal::decimal64 correct usage, g++ 4.6.3std::decimal::decimal64 正确用法,g++ 4.6.3
【发布时间】:2012-10-12 19:11:21
【问题描述】:

出于货币数量和价格的目的,我正在研究用 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();
}

我真的在追求更好的东西,再加上一轮(以特定的精度)来四舍五入(请原谅双关语)

【问题讨论】:

标签: c++ g++ decimal


【解决方案1】:

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 期间使用库构建。

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

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(或更高)。除非使用优化,否则存在未引用的符号,但这与打印值完全无关。要获得实现中使用的函数的定义,我需要链接到在构建 gcc 时创建的 libdecnumber.a 库:

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

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

【讨论】:

  • 谢谢。这听起来很简单。但是,我一生都无法弄清楚如何使用我的 gcc 编译器(ubuntu 12.04 附带的标准 gcc 4.6.3)访问 libdecnum 例程。找不到任何要包含的标题。我希望这不需要特殊的 gcc 构建......有什么想法吗?
  • 我正在查看 gcc 实现,它很有趣,尽管对您的目标也毫无帮助:它没有引用 libdecnumber 的标头,也没有将它们安装在任何地方!更糟糕的是,即使手动声明该函数,它似乎也没有在使用的库中定义,C 扩展也不支持打印。这似乎使十进制数支持相对无用。
  • 考虑到保留数字的保证,只要不使用超过 15 个十进制数字,就可以将十进制值读入 double 并将其转换为 std::decimal::decimal64通过转换回double 来打印它。但是,这是对 CPU 周期的浪费。我将仔细研究如何让 I/O 为小数工作。
  • 听起来很有希望!希望你能做出比我的尝试更好的东西。
  • 干得好迪特玛。我还在网上找到了这个,launchpad.net/std-decimal,这可能就足够了,直到出现更完整的东西。这包含了英特尔的 FP 库 (software.intel.com/en-us/articles/…)。似乎工作得很好,并且有我需要的输入/输出和舍入(又名量化)例程。
猜你喜欢
  • 1970-01-01
  • 2019-10-10
  • 2012-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-25
  • 2021-11-18
  • 2016-08-03
相关资源
最近更新 更多