std::string to float (via std::stof) precision
Asked Answered
I

6

7

I am trying to figure this out, the market data returns money values as a string that is 8 places after the digit long.

money = "124.19000540"

I need this to be 124.19, any idea how to achieve this?

std::stof(money) = 124.19000244

How to overcome this?

Ignaz answered 14/7, 2015 at 19:58 Comment(7)
It might be better to solve the problem rather than to treat the symptoms.Deeplaid
Don't use floating point to store currency. Use fixed point or library for decimal type.Sidelight
sounds good, but all i get is string from the market, i need this in a float or int (best) to be able to send this to computing functionsIgnaz
Do you need the result as a string or as a float?Pirn
@Pirn i need this as a float (at least) or integer (cents - best) without loosing any cent while going from string (returned by market)Ignaz
Can you not keep all the decimal places and only round to 2 dp when printing out the figure?Pirn
@Galik, i am not only printing but doing calculations on these numbers - printing is not a case i could go with %.2f, i need to calculate some numbers based on these strings returned by market, and here comes the problem. That's why i need to ensure i convert properly to be able to perform math calcs without loss - as this means in most cases eventual loss of money for one side. if you look at what i have said in my question i already loose a bit of money after doing string to float conversion.Ignaz
H
6

Floating point types are not good for holding money values. If you're content with rounding to the cent, and storing money as an integer number of cents (which is one of the simplest solutions), you could do this:

long numCents = static_cast<long>(100 * std::stof(money))

This will do "truncating" rounding, which always rounds down. If you'd like to do rounding "to the nearest cent", try:

long numCents = static_cast<long>(100 * std::stof(money) + 0.5)

As others mentioned, you may want to go for a fixed point or decimal library instead of something this simple.

Hoey answered 14/7, 2015 at 20:10 Comment(1)
This is a method for performing rounding that I haven't seen before. I like it!Sorrel
P
1

You can use setprecision

#include <iostream> //for std::fixed
#include <sstream> //for std::stringstream
#include <iomanip> //for std::setprecision


int main()
{
  std::string money;
  std::cout << "Enter amount: ";
  getline(std::cin, money);

  std::stringstream out;
  out << std::fixed << std::setprecision(2) << std::stof(money);
  float fmoney = std::stof(out.str());
  std::cout << "Result: " << fmoney << std::endl;

  return 0;
}

Execution Output:

Enter amount: 124.19000540
Result: 124.19
Pilaf answered 9/11, 2017 at 18:36 Comment(0)
S
1

Instead of std::stof(), which converts the string to a float, you should use std::stod(), which converts it to a double (with higher precision).

But as others also said, even this way you often cannot get exactly the same digits, due to how floating point numbers are represented. When printing through std::cout, you can use << std::setprecision(<precision>) to control the number of digits to print.

Shrieval answered 18/2, 2021 at 17:3 Comment(0)
A
0

Make sure to #include <iomanip> for setprecision and check if the function is spelled properly.

std::ostringstream out;
out << std::setprecision(2) << std::stof(money);
float percise = std::stof(out.str())
Alessi answered 14/7, 2015 at 20:1 Comment(0)
S
0

If you are comfortable with the boost libraries then I suggest you use boost.Lexical_cast. It is a library that uses the same syntax as the c++ casts (static_cast, dynamic_cast)

Here is a code sample

#include <boost/lexical_cast.hpp>

...

double money = boost::lexical_cast<double>("4.82748");

It can also cast the other direction along with many others. Look at the docs.

Then In Order to get the precision, you could do this:

money = (int)(money * 100) * 100;
Succumb answered 14/7, 2015 at 20:3 Comment(0)
I
0

This is what i have came up with thanks to brenns10.

std::string strUSD          = "124.19129999";
double fUSD                 = std::stod(strUSD);
uint64_t uiCents            = USD2CENTS(fUSD);
double fUSDBack             = CENTS2USD(uiCents);

printf("USD / CENTS\n");
printf("(string)%s = (double)%lf = (uint cents)%llu\n", strUSD.data(), fUSD, uiCents);
printf("Present: %.2fUSD\n", fUSDBack);
printf("\n");

std::string strBTC          = "1.12345678";
double fBTC                 = std::stod(strBTC);
uint64_t uiSatoshi          = BTC2SATOSHI(fBTC);
double fBTCBack             = SATOSHI2BTC(uiSatoshi);
printf("BTC / SATOSHI\n");
printf("(string)%s = (double)%lf = (uint satoshi)%llu\n",strBTC.data(),fBTC,uiSatoshi);
printf("Present: %.8fBTC\n", fBTCBack);


// Convert BITCOIN to SATOSHIs
uint64_t CSystemUtil::BTC2SATOSHI(const double& value)
{
    return static_cast<uint64_t>(value * 1e8 + (value < 0.0 ? -.5 : .5));
}
// Convert SATOSHIS to BITCOIN
double CSystemUtil::SATOSHI2BTC(const uint64_t& value)
{
    return static_cast<double>(value/1e8);
}
// Convert CENT to USD
double CSystemUtil::CENTS2USD(const uint64_t& value)
{
    return static_cast<double>(value)/100;
}
// Convert USD to CENT
uint64_t CSystemUtil::USD2CENTS(const double& value)
{
    return static_cast<uint64_t>(value * 100);
}

Output:

USD => CENTS => USD (string)124.19129999 = (double)124.191300 = (uint cents)12419 Present: 124.19USD

BTC => SATOSHI => BTC (string)1.12345678 = (double)1.123457 = (uint satoshi)112345678 Present: 1.12345678BTC

Worth notice, look at the printf showing the double values.

Ignaz answered 15/7, 2015 at 12:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.