I'm trying to print a max of 4 digits after the decimal point in C++ (Using streams). So if the number does not need 4 digits after the decimal I want it to use only the number of decimals it actually needs.
Examples:
1.12345 -> 1.1234
1.0 -> 1
1.12 -> 1.12
1.12345789 -> 1.1234
123.123 -> 123.123
123.123456 -> 123.1234
I tried std::setprecision(4) but that sets the number of significant digits and fails in the test case:
123.123456 gives 123.1
I also tried giving std::fixed along with std::setprecision(4) but that gives a fixed number of digits after decimal even if not needed:
1.0 gives 1.0000
It seems like std::defaultfloat is the one I need and not fixed nor exponential. But it does not seem to be printing the number of digits after the decimal appropriately and only has an option for significant digits.
We can do this using a std::stringstream and a std::string. We pass the double to the stream formatting it like we would if we are sending it to cout. Then we examine the string we get from the stream to see if there are trailing zeros. If there are we get rid of them. Once we do that we check to see if we are left with just a decimal point, if we are then we get rid of that as well. You could use something like this:
int main()
{
double values[] = { 1.12345, 1.0, 1.12, 1.12345789, 123.123, 123.123456, 123456789, 123.001 };
std::vector<std::string> converted;
for (auto e : values)
{
std::stringstream ss;
ss << std::fixed << std::setprecision(4) << e;
std::string value(ss.str());
if (value.find(".") != std::string::npos)
{
// erase trailing zeros
while (value.back() == '0')
value.erase(value.end() - 1);
// if we are left with a . at the end then get rid of it
if (value.back() == '.')
value.erase(value.end() - 1);
converted.push_back(value);
}
else
converted.push_back(value);
}
for (const auto& e : converted)
std::cout << e << "\n";
}
Which when made into a running example gives
1.1235
1
1.12
1.1235
123.123
123.1235
123456789
123.001
Using the answer from here along with custom logic to remove the zeros and the point:
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
std::string remove_zeros(std::string numberstring)
{
auto it = numberstring.end() - 1;
while(*it == '0') {
numberstring.erase(it);
it = numberstring.end() - 1;
}
if(*it == '.') numberstring.erase(it);
return numberstring;
}
std::string convert(float number)
{
std::stringstream ss{};
ss << std::setprecision(4) << std::fixed << std::showpoint << number;
std::string numberstring{ss.str()};
return remove_zeros(numberstring);
}
int main()
{
const float values[]{1.12345, 1.0, 1.12, 1.12345789, 147323.123, 123.123456};
for(auto i : values)
std::cout << convert(i) << '\n';
}
produces:
1.1235
1
1.12
1.1235
147323.125
123.1235
Related
I have a project to write a program that receives a polynomial string from the user up to the 5th power (ex. x^3+6x^2+9x+24) and prints out all the real and imaginary roots. The coefficients should be stored in a dynamic array.
The problem is getting these coefficients from the string. One of the coefficients can be a 0 (ex. 2x^2-18) so I can't store the coefficients from left to right by using an increment, because in this case a=2, b=-18, and c has no value, which is wrong.
Another problem is if the coefficient is 1, because in this case nothing will be written beside the x for the program to read (ex. x^2-x+14). Another problem is if the user adds a space, several, or none (ex. x ^3 +4x^ 2- 12 x + 1 3).
I have been thinking of pseudocode for a long time now, but nothing is coming to mind. I thought of detecting numbers from left to right and reading numbers and stopping at x, but the first and second problems occur. I thought of finding each x and then checking the numbers before it, but the second problem occurs, and also I don't know how big the number the user inputs.
Here is another Regex that you can use to get your coefficients after deleting whitespace characters:
(\d*)(x?\^?)(\d*)
It uses groups (indicated by the brackets). Every match has 3 groups:
Your coefficient
x^n, x or nothing
The exponent
If (1) is null (e.g. does not exist), it means your coefficient is 1.
If (2) and (3) are null, you have the last single number without x.
If only (3) is null, you have a single x without ^n.
You can try some examples on online regex sites like this one, where you can see the results on the right.
There are many tutorials online how to use Regex with C++.
You should normalize your input string, for example, remove all space then parse coefficients.
Let see my example. Please change it for your case.
#include <iostream>
#include <regex>
#include <iterator>
#include <string>
#include <vector>
#include <algorithm>
int main(int argc, char *argv[]) {
std::string input {argv[1]};
input.erase(remove_if(input.begin(), input.end(), isspace), input.end());
std::cout << input << std::endl;
std::vector<int> coeffs;
std::regex poly_regex(R"(\s*\+?\-?\s*\d*\s*x*\^*\s*\d*)");
auto coeff_begin = std::sregex_iterator(input.begin(), input.end(), poly_regex);
auto coeff_end = std::sregex_iterator();
for (std::sregex_iterator i = coeff_begin; i != coeff_end; ++i) {
std::smatch match = *i;
std::string match_str = match.str();
// std::cout << " " << match_str << "\n";
std::size_t plus_pos = match_str.find('+');
std::size_t minus_pos = match_str.find('-');
std::size_t x_pos = match_str.find('x');
if (x_pos == std::string::npos) {
std::cout << match_str.substr(plus_pos + 1) << std::endl;
} else if (x_pos == 0) {
std::cout << 1 << std::endl;
} else if (minus_pos != std::string::npos) {
if (x_pos - minus_pos == 1) std::cout << -1 << std::endl;
else std::cout << match_str.substr(minus_pos, x_pos - minus_pos) << std::endl;
}
else {
std::cout << match_str.substr(plus_pos + 1, x_pos - plus_pos - 1) << std::endl;
}
}
for (auto i: coeffs) std::cout << i << " ";
return 0;
}
I have a float number ranging from 0.001 up to 999.999
The question: how I can format all the range numbers like this:
0.001 becomes 000.001
0.002 becomes 000.002
0.2 becomes 000.200
1.001 becoes 001.001
9.090 becomes 009.090
99.100 becomes 099.100
Thanks
Please inspect documentation of of stream manipulators.
There couple tools which will let you do it:
while (std::cin >> x) {
std::cout
<< std::setfill('0') << std::setw(7)
<< std::fixed << std::setprecision(3)
<< x << '\n';
}
std::fixed forces fixed format (decimal separator in same place)
std::setprecision(3) defines how many digits should be after a decimal separator.
std::setw(7) - defines minimum space number should occupy
std::setfill('0') defines what should be used to fill extra space introduced by std::setw(7).
https://godbolt.org/z/zf6q8n97r
Extra note:
C++20 introduces nice type safe and clean equivalent of printf from C: format, but there is no compiler which already supports that.
use std stream formatters from iomanip.
Stop using printf : Why not use printf() in C++
#include <iostream>
#include <iomanip>
#include <vector>
int main()
{
std::vector<double> values{ 0.001, 0.002, 0.2, 1.001, 9.090, 99.100 };
for (const auto value : values)
{
std::cout << std::fixed;
std::cout << std::setprecision(3);
std::cout << std::setfill('0') << std::setw(7);
std::cout << value << std::endl;
}
return 0;
}
With std::printf:
#include <cstdio>
int main(void)
{
float f = 99.01f;
std::printf("%07.03f", f);
}
07 specifies that if the number takes up less space than 7 characters it'll be padded with leading 0s while 03 specifies that the if the numbers after the decimal point take up less space than 3 characters then it'll be padded with trailing 0s.
As of C++20 you can use similar formatting in std::format:
std::cout << std::format("{:07.03f}", f);
I have always found iomanip confusing and counter intuitive. I need help.
A quick internet search finds (https://www.vedantu.com/maths/precision) "We thus consider precision as the maximum number of significant digits after the decimal point in a decimal number" (the emphasis is mine). That matches my understanding too. However I wrote a test program and:
stm << std::setprecision(3) << 5.12345678;
std::cout << "5.12345678: " << stm.str() << std::endl;
stm.str("");
stm << std::setprecision(3) << 25.12345678;
std::cout << "25.12345678: " << stm.str() << std::endl;
stm.str("");
stm << std::setprecision(3) << 5.1;
std::cout << "5.1: " << stm.str() << std::endl;
stm.str("");
outputs:
5.12345678: 5.12
25.12345678: 25.1
5.1: 5.1
If the precision is 3 then the output should be:
5.12345678: 5.123
25.12345678: 25.123
5.1: 5.1
Clearly the C++ standard has a different interpretation of the meaning of "precision" as relates to floating point numbers.
If I do:
stm.setf(std::ios::fixed, std::ios::floatfield);
then the first two values are formatted correctly, but the last comes out as 5.100.
How do I set the precision without padding?
You can try using this workaround:
decltype(std::setprecision(1)) setp(double number, int p) {
int e = static_cast<int>(std::abs(number));
e = e != 0? static_cast<int>(std::log10(e)) + 1 + p : p;
while(number != 0.0 && static_cast<int>(number*=10) == 0 && e > 1)
e--; // for numbers like 0.001: those zeros are not treated as digits by setprecision.
return std::setprecision(e);
}
And then:
auto v = 5.12345678;
stm << setp(v, 3) << v;
Another more verbose and elegant solution is to create a struct like this:
struct __setp {
double number;
bool fixed = false;
int prec;
};
std::ostream& operator<<(std::ostream& os, const __setp& obj)
{
if(obj.fixed)
os << std::fixed;
else os << std::defaultfloat;
os.precision(obj.prec);
os << obj.number; // comment this if you do not want to print immediately the number
return os;
}
__setp setp(double number, int p) {
__setp setter;
setter.number = number;
int e = static_cast<int>(std::abs(number));
e = e != 0? static_cast<int>(std::log10(e)) + 1 + p : p;
while(number != 0.0 && static_cast<int>(number*=10) == 0)
e--; // for numbers like 0.001: those zeros are not treated as digits by setprecision.
if(e <= 0) {
setter.fixed = true;
setter.prec = 1;
} else
setter.prec = e;
return setter;
}
Using it like this:
auto v = 5.12345678;
stm << setp(v, 3);
I don't think you can do it nicely. There are two candidate formats: defaultfloat and fixed. For the former, "precision" is the maximum number of digits, where both sides of the decimal separator count. For the latter "precision" is the exact number of digits after the decimal separator.
So your solution, I think, is to use fixed format and then manually clear trailing zeros:
#include <iostream>
#include <iomanip>
#include <sstream>
void print(const double number)
{
std::ostringstream stream;
stream << std::fixed << std::setprecision(3) << number;
auto string=stream.str();
while(string.back()=='0')
string.pop_back();
if(string.back()=='.') // in case number is integral; beware of localization issues
string.pop_back();
std::cout << string << "\n";
}
int main()
{
print(5.12345678);
print(25.12345678);
print(5.1);
}
The fixed format gives almost what you want except that it preserves trailing zeros. There is no built-in way to avoid that but you can easily remove those zeros manually. For example, in C++20 you can do the following using std::format:
std::string format_fixed(double d) {
auto s = fmt::format("{:.3f}", d);
auto end = s.find_last_not_of('0');
return end != std::string::npos ? std::string(s.c_str(), end + 1) : s;
}
std::cout << "5.12345678: " << format_fixed(5.12345678) << "\n";
std::cout << "25.12345678: " << format_fixed(25.12345678) << "\n";
std::cout << "5.1: " << format_fixed(5.1) << "\n";
Output:
5.12345678: 5.123
25.12345678: 25.123
5.1: 5.1
The same example with the {fmt} library, std::format is based on: godbolt.
Disclaimer: I'm the author of {fmt} and C++20 std::format.
I am trying to print the average in Cpp up to 2 decimal points of the float num. avg is float, sum is float, count is int.
Currently if I have 10/1 for example it outputs 10.00. I want the output to be just 10. if avg gets value 3.1467665 for example, it should be displayed as 3.14.
avg = sum/count;
std::cout << std::fixed << std::setprecision(2) << avg;
The rounding should be just for the output. No need to change avg but if it is easier, its value can be changed.
Looking for a solution using a standard before c++11.
UPD: the output is 27.50 when I want it to be 27.5.
You could choose precision according to the floating modulus of the avg value. The following works:
int main() {
double sum = 10;
double count = 3;
double avg = sum/count;
double mod;
std::cout << std::fixed
<< std::setprecision((modf(avg, &mod) != 0.0) ? 2 : 0)
<< avg
<< std::endl;
}
Considering the added specifications:
Write 2.5 instead of 2.50
Write 3.14 for 3.1421783921, rather than 3.15
Here is a possible implementation using #IInspectable's suggested method:
std::stringstream ss;
ss << std::fixed << avg;
size_t pos = ss.str().find('.');
if (pos + 2 < ss.str().size()) // If there is a '.' and more than 2 digits after it
pos += 3;
std::string s = ss.str().substr(0, pos); // Leave only two digits
s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { return ch != '0'; }).base(), s.end()); // Remove trailing zeros
s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { return ch != '.'; }).base(), s.end()); // Remove trailing '.' when needed
std::cout << s << std::endl;
This will output:
10/4 -> 2.5
10/3 -> 3.33
10/2 -> 5
10/7 -> 1.42
3.9999 -> 3.99
Let's say that you have a function:
string function(){
double f = 2.48452
double g = 2
double h = 5482.48552
double i = -78.00
double j = 2.10
return x; // ***
}
* for x we insert:
if we will insert f, function returns: 2.48
if we will insert g, function returns: 2
if we will insert h, function returns: 5482.49
if we will insert i, function returns:-78
if we will insert j, function returns: 2.1
They are only example, who shows how the funcion() works. To precise:
The function for double k return rounded it to: k.XX,
but for:
k=2.20
it return 2.2 as string.
How it implements?
1) Just because you see two digits, it doesn't mean the underlying value was necessarily rounded to two digits.
The precision of the VALUE and the number of digits displayed in the FORMATTED OUTPUT are two completely different things.
2) If you're using cout, you can control formatting with "setprecision()":
http://www.cplusplus.com/reference/iomanip/setprecision/
EXAMPLE (from the above link):
// setprecision example
#include <iostream> // std::cout, std::fixed
#include <iomanip> // std::setprecision
int main () {
double f =3.14159;
std::cout << std::setprecision(5) << f << '\n';
std::cout << std::setprecision(9) << f << '\n';
std::cout << std::fixed;
std::cout << std::setprecision(5) << f << '\n';
std::cout << std::setprecision(9) << f << '\n';
return 0;
}
sample output:
3.1416
3.14159
3.14159
3.141590000
Mathematically, 2.2 is exactly the same as 2.20, 2.200, 2.2000, and so on. If you want to see more insignificant zeros, use [setprecision][1]:
cout << fixed << setprecision(2);
cout << 2.2 << endl; // Prints 2.20
To show up to 2 decimal places, but not showing trailing zeros you can do something such as:
std::string function(double value)
{
// get fractional part
double fracpart = value - static_cast<long>(value);
// compute fractional part rounded to 2 decimal places as an int
int decimal = static_cast<int>(100*fabs(fracpart) + 0.5);
if (decimal >= 100) decimal -= 100;
// adjust precision based on the number of trailing zeros
int precision = 2; // default 2 digits precision
if (0 == decimal) precision = 0; // 2 trailing zeros, don't show decimals
else if (0 == (decimal % 10)) precision = 1; // 1 trailing zero, keep 1 decimal place
// convert value to string
std::stringstream str;
str << std::fixed << std::setprecision(precision) << value;
return str.str();
}