patterncppModerate
The Term-inator: Pi edition
Viewed 0 times
editiontheterminator
Problem
The fourth project, continuing my C++ saga with terrible post names.
An approximate value of pi can be calculated using the series given
below:
$$ \pi \approx 4 \left[ 1 - \dfrac{1}{3} + \dfrac{1}{5} - \dfrac{1}{7} +
\dfrac{1}{9} - \cdots + \dfrac{\left( -1\right)^n}{2n + 1} \right] $$
Write a C++ program to calculate the approximate value of pi using
this series. The program takes an input \$ n \$ that determines the
number of terms in the approximation of the value of pi and outputs
the approximation. Include a loop that allows the user to repeat this
calculation for new values \$ n \$ until the user says she or he wants
to end the program.
Also, I am required to use a
```
/**
* @file pi.cpp
* @brief Calculates pi for the given number of terms
* @author syb0rg
* @date 10/3/14
*/
#include
#include
#include
#include
/**
* Makes sure data isn't malicious, and signals user to re-enter proper data if invalid
*/
void getSanitizedDouble(long double &input)
{
while (!(input = std::cin.peek()) && input != '\n')
{
if (std::isalpha(input) || std::isspace(input)) std::cin.ignore(); // ignore alphabetic and space characters from input
}
while(!(std::cin >> input) || input ::max(), '\n'); // skips to the next newline
std::cout << "Invalid input. Please enter a positive number: ";
}
}
int main()
{
long double num = 0.;
char again = '\0';
do
{
long double pi = 0.;
// get input for height, re-read input if not a positive number
std::cout << "Enter the number of terms to approximate π: ";
getSanitizedDouble(num);
for(auto i = 0; i < num; i++)
{
pi += std::pow(-1, i) / (2 * i + 1);
}
pi *= 4;
std::fprintf(stdout, "Approximated value of π for %Lg terms: %Lg\n", num, pi);
std::cout << "Run the program again (y/N): "; // signify n as defaul
:PAn approximate value of pi can be calculated using the series given
below:
$$ \pi \approx 4 \left[ 1 - \dfrac{1}{3} + \dfrac{1}{5} - \dfrac{1}{7} +
\dfrac{1}{9} - \cdots + \dfrac{\left( -1\right)^n}{2n + 1} \right] $$
Write a C++ program to calculate the approximate value of pi using
this series. The program takes an input \$ n \$ that determines the
number of terms in the approximation of the value of pi and outputs
the approximation. Include a loop that allows the user to repeat this
calculation for new values \$ n \$ until the user says she or he wants
to end the program.
Also, I am required to use a
for loop at least once in my code.pi.cpp:```
/**
* @file pi.cpp
* @brief Calculates pi for the given number of terms
* @author syb0rg
* @date 10/3/14
*/
#include
#include
#include
#include
/**
* Makes sure data isn't malicious, and signals user to re-enter proper data if invalid
*/
void getSanitizedDouble(long double &input)
{
while (!(input = std::cin.peek()) && input != '\n')
{
if (std::isalpha(input) || std::isspace(input)) std::cin.ignore(); // ignore alphabetic and space characters from input
}
while(!(std::cin >> input) || input ::max(), '\n'); // skips to the next newline
std::cout << "Invalid input. Please enter a positive number: ";
}
}
int main()
{
long double num = 0.;
char again = '\0';
do
{
long double pi = 0.;
// get input for height, re-read input if not a positive number
std::cout << "Enter the number of terms to approximate π: ";
getSanitizedDouble(num);
for(auto i = 0; i < num; i++)
{
pi += std::pow(-1, i) / (2 * i + 1);
}
pi *= 4;
std::fprintf(stdout, "Approximated value of π for %Lg terms: %Lg\n", num, pi);
std::cout << "Run the program again (y/N): "; // signify n as defaul
Solution
Out parameters in C++
In C++, you should almost never use out parameters (variables taken by reference and used to return a value from a function), you can read this excellent article by Eric Niebler. There are few cases where out parameters can make sense:
-
When you want your return to be fast. And even then, return value optimization and move semantics may still be faster.
-
When you have several output values. For example, you want to assign a value to a function and return whether it succeeded:
But even for this situation, there are better solutions such as
-
Input-output parameters: sometimes, you want to take a parameter, read from it, and then write to it again. That is still a valid use case (but these are not strict out parameters anymore).
In your case, it seems that
Type correctness
You could improve your type correctness:
-
That's also a naming issue: I don't expect a function named
-
The literal used in the expression
Order your includes
Alphabetical order is something you should always use to order your headers (at least in a logical group of headers). That allows a faster search to check whether some headers has already been included:
In C++, you should almost never use out parameters (variables taken by reference and used to return a value from a function), you can read this excellent article by Eric Niebler. There are few cases where out parameters can make sense:
-
When you want your return to be fast. And even then, return value optimization and move semantics may still be faster.
-
When you have several output values. For example, you want to assign a value to a function and return whether it succeeded:
bool assign(int from, int& to)
{
if (from != 0)
{
to = from;
return true;
}
return false;
}But even for this situation, there are better solutions such as
boost:optional to return both a value and whether it succeeded or not. And if you need several error values, use exceptions. And if you need to actually return several values, you general want to pack them into a dedicated struct or a std::tuple.-
Input-output parameters: sometimes, you want to take a parameter, read from it, and then write to it again. That is still a valid use case (but these are not strict out parameters anymore).
In your case, it seems that
getSanitizedDouble could simply return the read long double instead of having an out parameter.Type correctness
You could improve your type correctness:
-
That's also a naming issue: I don't expect a function named
getSanaitzeDouble to return a long double, but to return a double.-
The literal used in the expression
long double pi = 0.; is incorrect: 0. is a double. The correct long double literal should be 0.0L. We could also use 0.0l, but the l suffix is really too close to 1 not to be dangerous.Order your includes
Alphabetical order is something you should always use to order your headers (at least in a logical group of headers). That allows a faster search to check whether some headers has already been included:
#include
#include
#include
#include Code Snippets
bool assign(int from, int& to)
{
if (from != 0)
{
to = from;
return true;
}
return false;
}#include <cctype>
#include <cmath>
#include <iostream>
#include <limits>Context
StackExchange Code Review Q#64297, answer score: 12
Revisions (0)
No revisions yet.