PI Approximation not approximating right - c++

i just started on C++ and i tried to convert my working PI approximation JS code to C++
But when compiling my C++ it doesn't approximate correctly...
I think it's because i'm not using double variables at the right way.
Here's my code:
#include <iostream>
using namespace std;
double four = 4, pi = 4, num = 1;
bool lever = false;
int calcpi() {
while (true) {
num = num +2;
if (lever) {
lever = false;
pi = (four/num) - pi;
} else if(lever == false){
lever = true;
pi = (four/num) + pi;
}
cout << pi <<"\n";
}
}
int main(){
calcpi();
}

It looks like you're implementing the approximation
π = 4 – 4/3 + 4/5 – 4/7 + 4/9 – …
In that case, the line pi = (four/num) - pi; is backwards. It should be pi = pi - (four/num);, which represents the subtraction terms.
Also, subtraction from the initial value of 4 should be the first operation, so the lever flag should be initialized to true.
Here's the modified version that I got working after a little bit of troubleshooting.
void calcpi() {
double pi = 4.0, num = 1.0;
bool lever = true;
for (int i = 0; i < 1000; i++) {
num = num + 2.0;
if (lever) {
lever = false;
pi = pi - (4.0 / num);
}
else {
lever = true;
pi = pi + (4.0 / num);
}
std::cout << pi << std::endl;
}
}
This does give a slowly converging approximation of Pi.

This should work:
#include <iostream>
using namespace std;
// changed values of constant and variable
// to comply with the mathematical formula:
// pi = 4 * (0 + 1/1 - 1/3 + 1/5 - 1/7 + ...)
// four = 4 was changed to one = 1, because
// we use it as our numerator, which is always 1
// pi = 4 was changed to pi = 0 (first element
// of our infinite series)
// num = 1 was changed to num = -1 (at the
// beginning of the while loop, before we
// manipulate pi, we add 2 to num, so
// -1 + 2 = 1 <- first value of our denominator
double one = 1, pi = 0, num = -1;
bool lever = false;
void calcpi() { // void instead of int, because this function doesn't return anything
while (true) {
num += 2; // I prefer x += y instead of x = x + y, doesn't really matter
if (lever) {
lever = false;
pi -= (one / num); // negative elements of the infinite series
} else if(lever == false){ // this is redundant: we know lever == false at this point
lever = true;
pi += (one / num); // positive elements of the infinite series
}
cout << 4 * pi << '\n'; // our variable 'pi' is actually pi/4
}
}
int main() {
calcpi();
}
I assumed you use the Leibniz formula for π and I tried not to modify your code too much, but be wary - it's quite wonky.
If I were to write something similar, it'd look something like this:
#include <iostream>
void calcpi(int iter) {
double pi = 0, denom = 1;
bool lever = false;
for (int i = 0; i < iter; i++) {
if (lever) {
lever = false;
pi -= (1 / denom);
} else {
lever = true;
pi += (1 / denom);
}
denom += 2;
std::cout << 4 * pi << '\n';
}
}
int main() {
calcpi(426200); // should be enough given the default cout precision
return 0;
}

Related

Finding a rational approximation of a real number when both the numerator and denominator have a restricted range

I'm trying to learn how to find a rational approximation of a real number when both the numerator and denominator are constrained. I've looked at many pages now, including the following two, and learned about the continued fractions method, the Farey sequence, and the Stern-Brocot tree. However, in all of these examples, either the numerator or denominator are unconstrained.
Algorithm for simplifying decimal to fractions
https://gist.github.com/mikeando/7073d62385a34a61a6f7
Here's my situation:
I'm testing mixed-signal ICs.
In one of our tests, in order to find the IC's maximum operating frequency, the clock signal going into the IC is set to 12 MHz and continually decreased until the IC is able to run a simple digital sequence.
The test platform's main clock has a range of 25 to 66 MHz, and the function that sets it takes in a double.
In the current version of the test, it's set to a constant 50.0 MHz, then a function that divides that frequency is called in a loop. The divisor is an integer that can be anywhere between 1 and 4096.
However, this results in imprecise measurements.
The devices always pass at:
50 / 5 = 10 Mhz
50 / 6 = 8.333 MHz
If possible, to get more precise measurements, I'd like to be able to change the main clock's frequency AND the clock divisor in each loop iteration. That's why I'm trying to learn how to write something like a continued fractions algorithm with constraints to both the numerator and denominator. I'm envisioning something like this:
while(dFmax > dFmin)
{
std::pair<double, int> bestSettings = GetBestClkSettings(dFmax);
double dFreq = bestSettings.first;
int iDiv = bestSettings.second;
// Set up clock and timesets
clkset(dFreq);
clkdivide(iDiv);
// Run pattern
// ...
// Get results
// ...
dFmax -= 0.1;
}
Not only have I spent hours experimenting with the code in the second link, but I also tried writing a function that uses something like binary searching just to see what would happen. I'm fully aware that this is terrible code that I can't use to achieve my goals; I just wanted to show that I have been trying.
#include <iostream>
#include <stdio.h>
#include <cmath>
// The fraction struct and the main() function were largely taken from:
// https://gist.github.com/mikeando/7073d62385a34a61a6f7
struct fraction {
int n;
int d;
fraction()
{
this->n = -1;
this->d = -1;
}
fraction(int n, int d)
{
this->n = n;
this->d = d;
}
double asDouble()
{
double dReal = static_cast<double>(n) / static_cast<double>(d);
return dReal;
}
};
fraction ApproximateFrequency(double dTargetFreqMHz, double dTol)
{
fraction result;
if (dTargetFreqMHz < (25.0 / 4096) || dTargetFreqMHz > 66.0)
{
return result;
}
else if (dTargetFreqMHz >= 25.0 && dTargetFreqMHz <= 66.0)
{
result.n = static_cast<int>(dTargetFreqMHz);
result.d = 1;
return result;
}
int iFrqLo = 25;
int iFrqHi = 66;
int iDivLo = 1;
int iDivHi = 4096;
int iFrqCurr = (iFrqLo + iFrqHi) / 2;
int iDivCurr = (iDivLo + iDivHi) / 2;
double dFreq = static_cast<double>(iFrqCurr) / static_cast<double>(iDivCurr);
double dPrevFreq = 0;
int iNumIters = 1;
while (fabs(dTargetFreqMHz - dFreq) > dTol && fabs(dFreq - dPrevFreq) > 1e-8 && iNumIters < 25)
{
dPrevFreq = dFreq;
if (dFreq < dTargetFreqMHz)
{
// The frequency needs to be increased.
// The clock frequency could be increased:
int iFrqNew = (iFrqCurr + iFrqHi) / 2;
double dFrqIfClkInc = static_cast<double>(iFrqNew) / static_cast<double>(iDivCurr);
double dClkIncDiff = fabs(dTargetFreqMHz - dFrqIfClkInc);
// Or the divider could be decreased:
int iDivNew = (iDivLo + iDivCurr) / 2;
double dFrqIfDivDec = static_cast<double>(iFrqCurr) / static_cast<double>(iDivNew);
double dDivDecDiff = fabs(dTargetFreqMHz - dFrqIfDivDec);
// Find the option that produces a better result:
if (dClkIncDiff < dDivDecDiff && iFrqNew >= 25 && iFrqNew <= 66)
{
iFrqCurr = iFrqNew;
}
else if (dDivDecDiff < dClkIncDiff && iDivNew >= 1 && iDivNew <= 4096)
{
iDivCurr = iDivNew;
}
}
else
{
// The frequency needs to be decreased.
// The clock frequency could be decreased:
int iFrqNew = (iFrqLo + iFrqCurr) / 2;
double dFrqIfClkDec = static_cast<double>(iFrqNew) / static_cast<double>(iDivCurr);
double dClkDecDiff = fabs(dTargetFreqMHz - dFrqIfClkDec);
// Or the divider could be increased:
int iDivNew = (iDivCurr + iDivHi) / 2;
double dFrqIfDivInc = static_cast<double>(iFrqCurr) / static_cast<double>(iDivNew);
double dDivIncDiff = fabs(dTargetFreqMHz - dFrqIfDivInc);
// Find the option that produces a better result:
if (dClkDecDiff < dDivIncDiff && iFrqNew >= 25 && iFrqNew <= 66)
{
iFrqCurr = iFrqNew;
}
else if (dDivIncDiff < dClkDecDiff && iDivNew >= 1 && iDivNew <= 4096)
{
iDivCurr = iDivNew;
}
}
// See the frequency attainable with the current settings
dFreq = static_cast<double>(iFrqCurr) / static_cast<double>(iDivCurr);
std::cout << "prev = " << dPrevFreq << ", current = " << dFreq << std::endl;
iNumIters++;
}
result.n = iFrqCurr;
result.d = iDivCurr;
return result;
}
int main(int argc, char* argv[])
{
double dTargetFreqMHz = 20.0;
std::cout << "Target: " << dTargetFreqMHz << "\n\n";
double dTol = 0.05;
fraction mcf = ApproximateFrequency(dTargetFreqMHz, dTol);
printf("tol=%f, n/d = %d/%d = %f (err=%f)\n", dTol, mcf.n, mcf.d, mcf.asDouble(), mcf.asDouble()-dTargetFreqMHz);
}
Any advice or hints would be greatly appreciated. Thank you in advance.
Since your range is so constrained, you could just brute force it. There's only 172,032 possible combinations of numerator and denominator to check. The algorithm could be made more efficient by iterating from 25 to 66 and calculating the closest two denominators, in which case you only have to check 84 possibilities:
fraction ApproximateFrequency(double dTargetFreqMHz, double dTol)
{
fraction result;
if (dTargetFreqMHz < (25.0 / 4096) || dTargetFreqMHz > 66.0)
{
return result;
}
else if (dTargetFreqMHz >= 33.0 && dTargetFreqMHz <= 66.0)
{
result.n = static_cast<int>(dTargetFreqMHz);
result.d = 1;
return result;
}
double smallestError = 66.0;
int closestNum = 0;
int closestDenom = 0;
for (int num = 25; num <= 66; num++)
{
int denom = floor((double)num / dTargetFreqMHz);
if (denom >= 1 && denom <= 4096)
{
double freq = (double)num / double(denom);
double err = fabs(dTargetFreqMHz - freq);
if (err < smallestError)
{
closestNum = num;
closestDenom = denom;
smallestError = err;
}
if (denom <= 4095)
{
freq = (double)num / double(denom + 1);
err = fabs(dTargetFreqMHz - freq);
if (err < smallestError)
{
closestNum = num;
closestDenom = denom + 1;
smallestError = err;
}
}
}
}
result.n = closestNum;
result.d = closestDenom;
return result;
}
the dTol parameter isn't used so you could get rid of it.

PI number calculating with c++ program [duplicate]

This question already has an answer here:
Dividing two integers to produce a float result [duplicate]
(1 answer)
Closed 2 years ago.
// PI = 4 - (4/3) + (4/5) - (4/7) ... for 100 first statements
#include <iostream>
#include <conio.h>
using namespace std;
int main() {
double PI = 0.0;
int a = 1;
for (int i = 1; i <= 100; i++) {
if (i % 2 == 1) {
PI += double(4 / a);
}
else {
PI -= double(4 / a);
}
a += 2;
}
cout << "PI Number is : " << PI;
cout << endl;
return 0;
}
I tried this code in visual studio 2015 to give me the answer of PI number value but it returns "PI Number is : 3" and I want it to return a float or a double number.
What should I do?
In double(4 / a), the 4 / a part evaluates to an integer and it is already truncated by the time you cast it to double. What you want to do is 4.0 / a instead, and no need for an explicit cast.
4 / a is an integer division and your conversion double(…) happens after that division, so the result will never have something after the decimal point. e.g. 4/5 results in 0.
You need to change 4 from an integer to a double 4.
The issue in your code is when it's computing the value:
double PI = 0.0;
int a = 1;
for (int i = 1; i <= 100; i++) {
if (i % 2 == 1) {
PI += double(4 / a);
}
else {
PI -= double(4 / a);
}
a += 2;
}
You shouldn't do double(4 / a) but rather (double)4 / a or 4.0 / a
double PI = 0.0;
int a = 1;
for (int i = 1; i <= 100; i++) {
if (i % 2 == 1) {
PI += (double)4 / a;
}
else {
PI -= (double)4 / a;
}
a += 2;
}

How do I fix this bug with arctanx function in c++

I've recently been given a problem by my teacher about some mathematical equation / formula called the arctanx formula. The question is:
According to the Arctanx(x) = x - ((x ^ 3) / 3) + ((x ^ 5) / 5) - ((x ^
7) / 7) + ...and π = 6 * arctanx(1 / sqrt(3)), Create function arctanx(x)
, and find pi when the last "number"(like this ((x ^ y) / y)) is right before
and bigger than 10 ^ -6, or you can say that no "number" can be smaller than
that number without being smaller than 10 ^ -6.
I tried to code it out, but there is a bug in it.
# include<iostream>
# include<math.h>
using namespace std;
float arctanx() {
long double pi = 3.1415926535897;
int i = 0; // 0 = +, 1 = -
float sum = 0;
float lsum;
for (int y = 1; y < pi; y += 2) {
if (lsum > 0.000001) {
if (i == 0) {
lsum = pow(1 / sqrt(3), y) / y;
sum += pow(1 / sqrt(3), y) / y;
i++;
} else if (i == 1) {
lsum = pow(1 / sqrt(3), y) / y;
sum -= pow(1 / sqrt(3), y) / y;
i--;
}
} else {
break;
}
}
sum = sum * 6;
return sum;
}
int main() {
cout << arctanx();
return 0;
}
It should have a output of some number not equal to zero, but I got 0 from running this.
Your program has Undefined Behavior because you are using the uninitialized float lsum; in the comparison if (lsum > 0.000001).
What probably happens in your case is that lsum happens to be less than or equal to 0.000001 and your for immediately breaks without doing anything causing your function to return 0 * 6 which is obviously 0.
Create function arctanx(x)
The function defined in the posted code doesn't accept any parameter, it just uses the hardwired (and repeated) value 1 / sqrt(3) and tries to return an approximated value of π instead of the arctangent of x.
It also has undefined behavior, beeing lsum uninitialized (therefore having an indeterminate value) when it is first used in the comparison inside the loop.
Consider this implementation, but be advised that this particular polinomial expansion diverges for values of x greater than 1.
#include <iostream>
#include <iomanip>
#include <cmath>
double arctanx(double x);
int main()
{
double pi = 6.0 * arctanx(1.0 / std::sqrt(3));
std::cout << std::setprecision(8) << pi << '\n';
}
double arctanx(double x)
{
// You can take advantage of a running power, instad of calculating
// pow(x, i) at every iteration
double sq_x = x * x;
double pow_x = x * sq_x;
double err = 1e-6;
// Instead of keeping track of the alternating sign, you can use
// two separate partial sums
double sum_pos_term = x;
double sum_neg_term = 0.0;
for (int i = 3; i < 33; i += 2) // <- Limit the number of iterations
{
if (pow_x < err * i)
break;
sum_neg_term += pow_x / i;
i += 2;
pow_x *= sq_x;
if (pow_x < err * i)
break;
sum_pos_term += pow_x / i;
pow_x *= sq_x;
}
return sum_pos_term - sum_neg_term;
}

Sin algorithm not working

I made a c++ program that calculates sin without math.h. Im using this algorithm for my program https://ibb.co/bTnQnS. I enter 45 degrees, the program converts degrees to radians, the program uses the algorithm, and the program outputs -0.868597. The program should output 0.70710678 or √2/2. What am I doing wrong with the algorithm?
Code:
#include "stdafx.h"
#include <iostream>
using namespace std;
double sin(int input, int decimal_count);
int factorial(int n);
double deg_to_rad(int deg);
double power(double base, int power);
int main(){
double angle;
int decimal;
cout << sin(45,8) << endl;
//end
system("pause");
return 0;
}
double sin(int input, int accuracy) {
int odds = 3;
double sin;
double rads = deg_to_rad(input);
for (int i = 1; i <= accuracy; i += 1) {
if (i==1) {
sin = power(rads, odds) / factorial(odds);
}
else if (i%2==0) {
sin = (power(rads, odds) / factorial(odds)) + sin;
}
else {
sin = (power(rads, odds) / factorial(odds)) - sin;
}
odds = odds + 2;
}
sin = sin - rads;
return sin;
}
int factorial(int n) {
int fact = 1;
for (int j = 1; j <= n; j+=1) {
fact = fact * j;
}
return fact;
}
double deg_to_rad(int deg) {
return deg*(3.14159265/180);
}
double power(double base, int power) {
double ans = 1;
for (int k = 1; k <= power; k+=1) {
ans = ans * base;
}
return ans;
}
your taylor series expansion function is incorrect. :)
you have to disregard all even terms.
I have fixed it for you (i removed some windows specific stuff as I don;t have a windows machine: the stdfax.h header and the calls to pause were removed)
# include <cstdlib>
# include <iostream>
using namespace std;
double sin(int input, int decimal_count);
int factorial(int n);
double deg_to_rad(int deg);
double power(double base, int power);
int main(){
double angle;
int decimal;
cout << "The sine value is: " << sin(45,8) << endl;
//end
system("sleep 2");
return 0;
}
double sin(int input, int accuracy) {
int odds = 3;
double sin;
double rads = deg_to_rad(input);
bool negative_flag = true;
cout << "You entered " << input << " degrees" << endl;
cout << "This is " << rads << " radians" << endl;
sin = rads;
for (int taylor_term = 3; taylor_term <= 7; taylor_term += 2) {
double term = (double)(power(rads, taylor_term) / factorial(taylor_term));
if (negative_flag) {
term = -1 * term;
}
negative_flag = !(negative_flag);
sin += term;
}
return sin;
}
int factorial(int n) {
int fact = 1;
for (int j = 1; j <= n; j+=1) {
fact = fact * j;
}
return fact;
}
Running this output
You entered 45 degrees
This is 0.785398 radians
The sine value is: 0.707106
Explanation
The taylor series expansion for sine is a series of terms with odd taylor's coefficients that alternate in sign. In my code the alternating signs is effected by the flag. I've also taken into account only the first 3 terms of the taylor series expansion.
Other than that, the line double term = (double)(power(rads, taylor_term) / factorial(taylor_term)); calculates every term in the taylor series expansion.
negative_flag = !(negative_flag); resets the flag sign for the next term.
Addressing your comment and where your code was a bit wrong
Below is your sin func with minimal changes to make it work.
What you were doing wrong
These are just minimal edits, performing these edits would naturally be followed up with some code style cleanup. eg: the if and else block(not else if) have almost the exact same code
sin was not being initialized before being modified
the attribution to correct signs the taylor terms in the if blocks was not correct.
the extra subtraction of rads at the end from sin was not required. Once these things were fixed, your code works :)
int odds = 3;
double sin ;
double rads = deg_to_rad(input);
sin = rads;
for (int i = 1; i <= accuracy; i += 1) {
if (i==1) {
sin = sin - power(rads, odds) / factorial(odds);
}
else if (i%2==0) {
sin = (power(rads, odds) / factorial(odds)) + sin;
}
else {
sin = -(power(rads, odds) / factorial(odds)) + sin;
}
odds = odds + 2;
}
return sin;

Solving an equation with d&c method

I want to calculate value of x in this equation to 4 digits after the decimal with divide and conquer method.Values of p,q,r,s,t,u are input. How to do it in?
Time limits: 1 sec
Memory limits: 64 MB
float results[10000];
int n = 0;
for( float step = 0; i < 1; i+=0.00001 )
{
results[n] = callProblem( i );
}
some divide and conquer approach
float x = 0;
float diff = 1;//Startvalue
while( )
{
result = callProblem(x);
if( result > 0 )
{
x -= diff;
diff = diff/2;
result = callProblem(x);
}
else
{
x += diff;
diff = diff/2;
result = callProblem(x);
}
}
I have generalized the bisection method into an untested recursive multi-section method:
#include <math.h>
#include <stdio.h>
#include <time.h>
#define P 1.0
#define q 2.0
#define r 3.0
#define s 1.0
#define t 5.0
#define u -6.0
// number of sub-intervals in search interval
#define INTERVALS 10
// accuracy limit for recursion
#define EPSILON 1.0e-4
double f(double x) {
double y = P * exp(-x) + q*sin(x) + r*cos(x) + s*tan(x) + t*x*x + u;
return y;
}
// sign macro: -1 for val < 0, +1 for val > 0
#define SGN(val) ((0.0 < val) - (val < 0.0))
// return approximate x for function(x)==0.0
// "function" points to the function to be solved
double solve(double xMin, double xMax, double (*function)(double)) {
double arguments[INTERVALS + 1];
double values[INTERVALS + 1];
int prevSign;
int sign;
if (fabs(xMax - xMin) < EPSILON) {
// interval quite tight already
return (xMax + xMin) / 2.0;
}
// split the interval into sub-intervals
// evaluate the function for INTERVALS+1 equidistant points
// across our search interval
for (int i = 0; i <= INTERVALS; i++) {
double x = xMin + i*((xMax - xMin) / INTERVALS);
arguments[i] = x;
values[i] = function(x);
}
// look for adjacent intervals with opposite function value signs
// if f(Xi) and f(Xi+1) have different signs, the root must be
// between Xi and Xi+1
prevSign = SGN(values[0]);
for (int i = 1; i <= INTERVALS; i++) {
sign = SGN(values[i]);
if (sign * prevSign == -1) {
// different signs! There must be a solution
// Shrink search interval to the detected sub-interval
double x = solve(arguments[i - 1], arguments[i], function);
return x;
}
// remember sign for next round
prevSign = sign;
}
// no solution found: return not-a-number
return NAN;
}
int main(unsigned argc, char **argv) {
clock_t started = clock();
clock_t stopped;
double x = solve(0.0, 1.0, &f);
if (isnan(x)) {
printf("\nSorry! No solution found.\n");
} else {
printf("\nOK! Solution found at f(%f)=%f\n", x, f(x));
}
stopped = clock();
printf("\nElapsed: %gs", (stopped - started) / (double)CLOCKS_PER_SEC);
// wait for user input
getchar();
}