1

With python3 round(x, n) function we can round a float number to fixed decimal places. For example round(2.675, 2) = 2.67, round(2.685, 2) = 2.69. How can I implement such a function in C++? round(x*100.0)/100.0 gives different result with python3. Python's result is the same as printf("%.2f", 2.675). So one way is to store result in a char array using sprintf function. Then convert the char array back to double. But this is very slow. Is there a better way? Thank you.

I was thinking since printf function can do round automatically, is there a way to directly store the printf function rounded result into a double variable?

edit: I would like to explain why I need to do this rounding to 2 decimal places. Because I was translating my colleague's python program to C++. In the python program he uses round(2.675, 2)=>2.67. And there is not a corresponding round function in C++ to give the exact same result. If the round result differ in 0.01 (if cpp_round(2.675, 2)=>2.68), it will trigger a totally different process in the computation.

Maybe it is easier to ask my colleague to change to a self-written round function. But since his programm is in use, it is difficult to for his to make this change.

Paultant
  • 11
  • 2
  • 3
    Is the goal to use the rounded number in calculations, or only to display it? What is your original and underlying problem that your rounding would solve? And why do you think the rounding would solve that problem? Please take some time to read about [the XY problem](https://en.wikipedia.org/wiki/XY_problem), because I'm sorry to say that your question is one. – Some programmer dude Feb 28 '23 at 11:50
  • 2
    You can see the Python `round` implementation [here](https://github.com/python/cpython/blob/4624987b296108c2dc1e6e3a24e65d2de7afd451/Objects/floatobject.c#L957). As far as I understand, it converts a float to a string by using the [`_Py_dg_dtoa`](https://github.com/python/cpython/blob/91a8e002c21a5388c5152c5a4871b9a2d85f0fc1/Python/dtoa.c#L2239) function, which does the rounding, and then converts the string back to a float. – mkrieger1 Feb 28 '23 at 11:50
  • And for future questions (and to learn how to improve this question), please take some time to read [the help pages](http://stackoverflow.com/help), take the SO [tour], read [ask], as well as [this question checklist](https://codeblog.jonskeet.uk/2012/11/24/stack-overflow-question-checklist/). – Some programmer dude Feb 28 '23 at 11:51
  • 1
    *round(x*100.0)/100.0 gives different result with python3* how different? – kiner_shah Feb 28 '23 at 11:51
  • Oh, and due to the way that binary floating point works, some numbers may not actually be possible to store in a `double` variable, so rounding won't really help there. See [Why does floating-point arithmetic not give exact results when adding decimal fractions?](https://stackoverflow.com/questions/21895756/why-are-floating-point-numbers-inaccurate) I think that Python uses their own system to store floating point values and do arithmetic to overcome this. – Some programmer dude Feb 28 '23 at 11:55
  • 2
    Note from the Python documentation: "The behavior of round() for floats can be surprising: for example, round(2.675, 2) gives 2.67 instead of the expected 2.68. This is not a bug: it’s a result of the fact that most decimal fractions can’t be represented exactly as a float." (Specifically, it's because `2.675` is actually a little bit smaller than 2.675, and `2.685` is slightly larger than 2.685.) There is almost never any reason to round floats to anything other than an integer except for display purposes. – molbdnilo Feb 28 '23 at 12:08
  • 1
    do you want to round a floating point number or do you want to print a rounded representation of a floating point number? – 463035818_is_not_an_ai Feb 28 '23 at 12:09
  • And even the Python docs is not telling the full truth; the "rounded" result `2.67` isn't actually 2.67 but slightly smaller. – molbdnilo Feb 28 '23 at 12:15
  • *So one way is to store result in a char array using sprintf function.* That will have the same problem, for the same reason, that `round(x*100.0)/100.0` has. – Eljay Feb 28 '23 at 12:17
  • If you want to explore how floating point numbers are stored in your computer, you can try to play around with this IEEE-754 Floating Point Converter: https://www.h-schmidt.net/FloatConverter/IEEE754.html - unfortunately it is only for 32 bit floats, but the same principle applies to 64 bit versions too – Frodyne Feb 28 '23 at 12:21
  • I believe the proper course of action is to fix the mistake your colleague made when they wrote code that depends on "rounding" floating-point numbers (which is futile). – molbdnilo Feb 28 '23 at 13:12
  • the IEEE-754 Floating Point Converter is very helpful. Is there a way to write a function to compute "the Value actually stored in float" in the converter? @Frodyne – Paultant Feb 28 '23 at 13:15

1 Answers1

0

You'll want to first create an output buffer, then cast the char array to a double using the string std lib:

#include <iostream>
#include <string>

double round(double val) {
    char buffer[100];
    snprintf(buffer, sizeof(buffer), "%.2f", val);
    return std::stod(buffer);
}

int main()
{
    double rounded = round(3.14159);
    std:: cout << rounded;
}

EDIT: Try this:

#include <iostream>
#include <string>
#include <cmath>

double stupid_round(double val) {
    char buffer[100];
    snprintf(buffer, sizeof(buffer), "%.2f", val);
    return std::stod(buffer);
}

double round_x(double x, int precision)
{
    double multiplier = (1 / pow(10, precision));
    return std::round(x / multiplier) * multiplier;
}

int main()
{
    double rounded = round_x(3.14159, 2);
    std:: cout << rounded;
}
Designly
  • 266
  • 1
  • 9
  • Yes,this gives exactly the result I want. Only it is quite slower then python's round(val, 2) (maybe 20 times slower). Since I think converting char array to double cost much time. – Paultant Feb 28 '23 at 12:37
  • If you print all the decimals you will find that the value is actually 3.140000000000000124344978758017532527446746826171875 – molbdnilo Feb 28 '23 at 13:04
  • Yeah that's super dumb. Try the other solution. So much simpler. Let me know how fast it runs. – Designly Feb 28 '23 at 13:13
  • also, can't call it round because that's a function in cmath. – Designly Feb 28 '23 at 13:13
  • stupid_round(2.675, 2)=>2.67. But round_x(2.675, 2)=>2.68 which is differnt from python3' result and printf("%.2f", 2.675) – Paultant Feb 28 '23 at 13:28
  • 2.675 should round to 2.68. That is correct function. Round should always round up on the 5. – Designly Feb 28 '23 at 16:04