【问题标题】:Double results differ on visual studio 2012 and visual studio 2015Visual Studio 2012 和 Visual Studio 2015 的双重结果不同
【发布时间】:2023-04-04 16:41:01
【问题描述】:

我正在 64 位 Windows 7 上开发一个数学应用程序。我们最近通过 Visual Studio 2015 迁移到了 c++11 我有一个问题我简化为以下小程序

#include "stdafx.h"
#include "iostream"

using namespace std;


int main()
{
    const double OM = 1.10250000000000000E-36;
    std::cout.precision(20);
    std::cout <<   OM;

    int y;
    std::cin >> y;
    return 0;
}

当我编译并运行程序时 1) 在 Visual Studio 2012 上,我得到的结果为 1.1025000000000001e-036 2) 在 Visual Studio 2015 上使用 c++11 ,我得到的结果为 1.1025000000000000611e-36

注意 Visual Studio 2012 中额外的 0。我们需要得到相同的结果。 (注意结果不同,不仅仅是一个额外的 0,还有最后显示的数字)

我怎样才能使这些相同(即我需要带有额外 0 的旧结果)?这给我带来了很多问题,我希望得到同样的结果。

需要相同结果的原因。上面这个程序是对差异的一个小解释。这种差异导致我的回归失败。有时这种差异加起来会产生不同的结果。

我希望 Visual Studio 有一些编译器开关等可能会给我旧的结果。

【问题讨论】:

  • 您比较过OM 变量的位吗?换句话说,是改变了值的表示,还是只是字符串的格式?
  • 你只是被e-036困扰,而不是精确1 vs 0611
  • 只是检查:您想要旧结果,尽管它们错误?数一下位数,只有VS2015输出请求的20位数。
  • 请注意,这两个结果实际上是相同的:ideone.com/XGhPAb
  • 为什么需要两个值相同?任何依赖具有完全相同值的浮点数的东西都相当脆弱

标签: c++ visual-studio visual-studio-2012 visual-studio-2015


【解决方案1】:

Visual C++ 的旧方式,具有三位指数,似乎是 _set_output_format 已弃用的 Visual C++ 扩展。文档说:

重要

此功能已过时。从 Visual Studio 2015 开始,它在 CRT 中不可用。

所以基本上,你运气不好,但并非没有希望。

您可以为 double 定义自己的打印函数,并将其链接到 std::basic_ostreamstd::ios_base::imbue。这意味着您必须仅为您的需要定义一个新的locale

这是一个解决方案的草图。您必须填写详细信息,以便代码与所有iostream 格式选项一起工作,并且不会忽略setprecision() 之类的内容。下面的示例代码只是一个示例,它并没有做所有这些事情。要获得完整的解决方案,您必须做一些工作(但不要太多):

template <class Char>
class my_double : public std::num_put<Char>
{
public:
    static my_double * get()
    {

        static my_double * singleton = new my_double;
        return singleton;
    }
private:
    using base = std::num_put<Char>;
    //
    // This method will format your double according to your needs.
    // Refine the code so that it reads and uses all the flags from `str`
    // and uses the `fill` character.
    //
    iter_type do_put(iter_type out, std::ios_base& str, Char fill, double v) const override
    {
        if (v < 0)
        {
            v *= -1;
            *out = '-';
            ++out;
        }
        if (v == 0.0 || std::isnan(v))
        {
            return base::do_put(out, str, fill, v);
        }
        auto exponent = static_cast<int>(std::floor(std::log10(v)));
        auto significand = v / std::pow(10.0, exponent);
        // TODO: Format according to the flags in `str`
        out = base::do_put(out, str, fill, significand);
        *(out++) = 'e';
        if (exponent < 0)
        {
            *(out++) = '-';
            exponent *= -1;
        }
        *(out++) = '0' + ( (exponent / 100) % 10);
        *(out++) = '0' + ((exponent / 10) % 10);
        *(out++) = '0' + (exponent % 10);
        return out;
    }
};

int main()
{

    // !!!
    // This is how you register your formatting function for `double`
    // !!!
    std::cout.imbue(std::locale(cout.getloc(), my_double<char>::get()));
    /// your code goes here:
}

【讨论】:

    猜你喜欢
    • 2017-11-24
    • 2017-09-30
    • 2015-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-21
    • 2015-12-13
    相关资源
    最近更新 更多