0

I have been trying to do a very easy thing and it's taking me hours. I can't seem to find a good answer to this question.

I have various numbers, I need to keep only up until the third digit after the decimal. But, if there are trailing zero on the right, remove them. For example:

0.015356 -> 0.015
0.015000 -> 0.015
0.010320 -> 0.01
0.000320 -> 0

I have the numbers as float/double. I need to pass them into another function which will then print them. I don't have control over the other function. I can pass either numbers or strings, and they will get printed accordingly.

I suppose I need to pass on a string, cause otherwise it can't be achved?

I was able to remove the digits up until the third:

num = floor(num*1000)/1000;
0.015356 -> 0.015000
0.000320 -> 0.000000

But now I have the problem of the trailing zero.

In short, how can I achieve what I need?

Iam Spano
  • 31
  • 6

3 Answers3

0

Is something like this what you are after?

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


std::string To_String_With_Decimal_Precision( double value, int decimals )
{
    std::ostringstream ss;
    ss << std::fixed << std::setprecision(decimals) << value;
    std::string s = ss.str();
    if(decimals > 0 && s[s.find_last_not_of('0')] == '.') {
        s.erase(s.size() - decimals + 1);
    }
    return s;
}


int main()
{

    double number = 0.015356;

    //Round to 3d.p
    number = floor(number*1000)/1000;


    std::cout << number << std::endl;
    std::cout << To_String_With_Decimal_Precision(number, 3);


    return 0;
}

Output:

0.015
0.015

To be honest, i'm not sure why number = floor(number*1000)/1000; made the number equal to 0.015 without the trailing zeros, but if that line doesn't work when you compile the code, use To_String_With_Decimal_Precision it should work with any level of decimal precision

Ggsgn Hdjwngnf
  • 133
  • 2
  • 10
0

how about a routine that determines the precision value case by case which can then be utilized in setprecision: Here is one design but because it operates on a native float, precision errors abound. Try the commented code without the parentheses with the input 0.011 to start to see why. For something more robust, consider designing an alternative algorithm similar to this that parses the string and work on the components; alternatively, use a multiprecision library.

// a truthy zerotest indicates that there is a zero at the place of interest
// inputs                              process                           outputs
// value                               represent as mega value           precision up to
//                                     zerotest thousandths              
//                                     [t]prec=2 "don't want zero        3 decimals
//                                      zerotest hundredths
//                                      [t]prec=1
//                                       zerotest tenths
//                                       [t]prec=0
std::streamsize // setprecision takes a std::streamsize, prob aliased to long long
precision_cutoff_at_zero_for(double const input)
{
    int const inputMega = input *1000; // cast to int to discard decimals beyond 3
// WARNING float arithmetic e.g. input * 1000 is bad bad bad
// alt = input * (10.0*10.0*10.0) works but easy to forget parentheses losing precision
    int precisionRelative = 3; // assume not evenly divisible by 10 (first case)

    if (inputMega % 10 == 0) // evenly divisible by 10 (zerotest thousandth place)
    {
        --precisionRelative;
        if (inputMega % 100 == 0) // 0 at far right, followed by another to the left?
        {
            --precisionRelative;
            if (inputMega % 1000 == 0)
            {
                --precisionRelative; // etc
            }
        }
    }

    return precisionRelative;
}

then from main

// the number is stored in valueDouble and the case specific precision is returned from the routine defined above
std::cout << std::fixed << std::setprecision(precision_cutoff_at_zero_for(valueDouble)) << valueDouble << "\n";
-1

If you don't have control over the function, then you probably have no control over the stream that is used for the output in there. If this is the case, then the proper way is to pass the number as a string and generate the string on your own. A simple version could work as follows:

#include <sstream>

int main() {

    double f = 0.015356;
    std::stringstream result;
    result << "0.";
    for (int mask = 10; mask <= 1000; mask*=10) {
        int digit = ((int)(f * mask))%10;
        result << digit;
    }
    
    std::cout << result.str();
 }
Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58