0

I am trying to convert a string to number(long double) in C++. The problem arises when the number of digits after decimal point is greater than 3. It automatically rounds-off the to the nearest third digit after the decimal.

Additional info:

  • compiler: mingw
  • os: win10

Here's the code (test.cpp):

#include<iostream>
#include <string>
#include <math.h>

using namespace std;

double long c2n(string n) {
    double long num=0;
    bool isdec = false, is_ve=false;
    // is_ve checks if number is negative
    // isdec checks if the decimal point is reached and numbers can be added after decimal
    char c;
    // to store the the character which needs to be checked
    short i = 0, count=1;
    if (n.at(0)=='-')
    {
        i=1;
        is_ve=true;
    }
    for (; i < n.length(); ++i)
    {
        c=n.at(i);
        if (c=='.'){
            isdec=true;
            continue;
        }

        if (!isdec)
            num=num*10+(c-'0');
        else{
            num = num + (c-'0')/pow(10,count);
            count++;
        }
    }
    if (is_ve)
    {
        return -num;
    }
    return num;
}

int main(int argc, char const *argv[])
{
    cout << c2n("-912.301956") << endl;
    return 0;
}

Here's the output:

D:\--path-->g++ -o test.exe test.cpp
D:\--path-->test.exe
-912.302

What I discovered later:

if in the main function, we pass "-912.3016"
cout<< c2n("-912.3016") <<endl;
then output comes out to be:

D:\--path-->g++ -o test.exe test.cpp
D:\--path-->test.exe
-912.302

but if we pass "-912.3015"
cout << c2n("-912.3015") <<endl;
then the o/p:

D:\--path-->g++ -o test.exe test.cpp
D:\--path-->test.exe
-912.301

Should I take double instead of long double or there is any other problem?

Someone
  • 126
  • 8
  • 4
    http://www.cplusplus.com/reference/iomanip/setprecision/ – L. Scott Johnson Jun 15 '21 at 17:33
  • You may also run into this: [https://stackoverflow.com/questions/588004/is-floating-point-math-broken](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – drescherjm Jun 15 '21 at 17:36
  • 1
    comparing doubles via `==` is problematic, but for proper testing you could write a function that converts the number back to string to see if you get the original string. Even putting your current issue aside testing via `cout` isnt that reliable – 463035818_is_not_an_ai Jun 15 '21 at 17:51
  • 2
    btw `pow` is not made to be called with integers. Anyhow calling `pow(x,count)` in a loop with loop index `count` is a waste of cpu cycles. It is much simpler to accumulate `*0.1` in each loop – 463035818_is_not_an_ai Jun 15 '21 at 17:54
  • Try `cout << -912.301956;`, and it will also print `-912.302`. – Ranoiaetep Jun 15 '21 at 19:31
  • OT: You should pass the string by reference or const reference if the string is not modified. Otherwise the compiler makes a copy before calling your function. – Thomas Matthews Jun 15 '21 at 19:56

1 Answers1

1

The default precision of std::cout is 6 as set by std::ios_base::init. So

auto val = 1234.56789;
std::cout<<val<<'\n`;

yields 1234.57 i.e. 6 digits (and rounds it accordingly). Set the precision accordingly using setprecision from the iomanip header and you should be able to see the correct value.

std::cout << std::setprecision(12) << c2n("-912.301956") << std::endl;
Zoso
  • 3,273
  • 1
  • 16
  • 27