MAG
MAG

Reputation: 3075

Double results differ on visual studio 2012 and visual studio 2015

I am working on a mathematical application on Windows 7, 64 bit. We have recently moved to c++11 via visual studio 2015 I have a problem which I have reduced to the following small program

#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;
}

When I compile and run the program 1) ON visual studio 2012 I get result as 1.1025000000000001e-036 2) ON visual studio 2015 with c++11 , I get result as 1.1025000000000000611e-36

Note the extra 0 in visual studio 2012. We need to have the same results. (note results are different not just an extra 0 but last shown digits too )

How can I make these same ( i.e. I need old results with an extra 0 )? This has caused a huge amount of issue for me and I wish to have the same results.

enter image description here

Reason for need of same results. This above program is a small explanation of difference . This difference resulted in my regression failures. Sometimes this difference adds up to give different results .

I hope visual studio has some compiler switch etc which may give me old results.

Upvotes: 1

Views: 126

Answers (1)

Michael Veksler
Michael Veksler

Reputation: 8475

The old way of Visual C++, with three digit exponent, seems to be the deprecated Visual C++ extension of _set_output_format. The documentation says:

Important

This function is obsolete. Beginning in Visual Studio 2015, it is not available in the CRT.

So basically, you are out of luck, but not hopeless.

You can define your own printing function for double, and link it to std::basic_ostream through std::ios_base::imbue. It means that you'd have to define a new locale only for your needs.

Here is a sketch of a solution. You must fill in the details so that the code works well with all iostream formatting options, and does not ignore things like setprecision(). The sample code below is just a sample, it does not do all these things. For a full solution you'd have to work a little (but not too much):

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:
}

Upvotes: 2

Related Questions