简体   繁体   中英

C++ set precision of a double (not for output)

Alright so I am trying to truncate actual values from a double with a given number of digits precision (total digits before and after, or without, decimal), not just output them, not just round them. The only built in functions I found for this truncates all decimals, or rounds to given decimal precision. Other solutions I have found online, can only do it when you know the number of digits before the decimal, or the entire number. This solution should be dynamic enough to handle any number. I whipped up some code that does the trick below, however I can't shake the feeling there is a better way to do it. Does anyone know of something more elegant? Maybe a built in function that I don't know about?

I should mention the reason for this. There are 3 different sources of observed values. All 3 of these sources agree to some level in precision. Such as below, they all agree within 10 digits. 4659.96751751236 4659.96751721355 4659.96751764253 However I need to only pull from 1 of the sources. So the best approach, is to only use up to the precision all 3 sources agree on. So its not like I am manipulating numbers and then need to truncate precision, they are observed values. The desired result is 4659.967517

double truncate(double num, int digits) {

// check valid digits
if (digits < 0)
    return num;

// create string stream for full precision (string conversion rounds at 10)
ostringstream numO;

// read in number to stream, at 17+ precision things get wonky
numO << setprecision(16) << num;

// convert to string, for character manipulation
string numS = numO.str();

// check if we have a decimal
int decimalIndex = numS.find('.');

// if we have a decimal, erase it for now, logging its position
if(decimalIndex != -1)
    numS.erase(decimalIndex, 1);

// make sure our target precision is not higher than current precision
digits = min((int)numS.size(), digits);

// replace unwanted precision with zeroes
numS.replace(digits, numS.size() - digits, numS.size() - digits, '0');

// if we had a decimal, add it back
if (decimalIndex != -1)
    numS.insert(numS.begin() + decimalIndex, '.');

return atof(numS.c_str());

}

This will never work since a double is not a decimal type. Truncating what you think are a certain number of decimal digits will merely introduce a new set of joke digits at the end. It could even be pernicious: eg 0.125 is an exact double , but neither 0.12 nor 0.13 are.

If you want to work in decimals, then use a decimal type, or a large integral type with a convention that part of it holds a decimal portion.

I disagree with "So the best approach, is to only use up to the precision all 3 sources agree on."

If these are different measurements of a physical quantity, or represent rounding error due to different ways of calculating from measurements, you will get a better estimate of the true value by taking their mean than by forcing the digits they disagree about to any arbitrary value, including zero.

The ultimate justification for taking the mean is the Central Limit Theorem , which suggests treating your measurements as a sample from a normal distribution. If so, the sample mean is the best available estimate of the population mean. Your truncation process will tend to underestimate the actual value.

It is generally better to keep every scrap of information you have through the calculations, and then remember you have limited precision when outputting results.

As well as giving a better estimate, taking the mean of three numbers is an extremely simple calculation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM