I'm having issues with my adaptive trapezoidal rule algorithm in C++ -- basically, regardless of the tolerance specified, I get the same exact approximation. The recursion is supposed to stop very early for large tolerances (since abs(coarse-fine) is going to be smaller than 3.0*large tolerance and minLevel of recursion is about 5).
However, what this function does is run the maximum number of times regardless of choice of tolerance. Where did I mess up?
EDIT: Perhaps there are issues in my helper functions?
double trap_rule(double a, double b, double (*f)(double),double tolerance, int count)
{
double coarse = coarse_helper(a,b, f); //getting the coarse and fine approximations from the helper functions
double fine = fine_helper(a,b,f);
if ((abs(coarse - fine) <= 3.0*tolerance) && (count >= minLevel))
//return fine if |c-f| <3*tol, (fine is "good") and if count above
//required minimum level
{
return fine;
}
else if (count >= maxLevel)
//maxLevel is the maximum number of recursion we can go through
{
return fine;
}
else
{
//if none of these conditions are satisfied, split [a,b] into [a,c] and [c,b] performing trap_rule
//on these intervals -- using recursion to adaptively approach a tolerable |coarse-fine| level
//here, (a+b)/2 = c
++count;
return (trap_rule(a, (a+b)/2.0, f, tolerance/2.0, count) + trap_rule((a+b)/2.0, b, f, tolerance/2.0, count));
}
}
EDIT: Helper and test functions:
//test function
double function_1(double a)
{
return pow(a,2);
}
//"true" integral for comparison and tolerances
//helper functions
double coarse_helper(double a, double b, double (*f)(double))
{
return 0.5*(b - a)*(f(a) + f(b)); //by definition of coarse approx
}
double fine_helper(double a, double b, double (*f)(double))
{
double c = (a+b)/2.0;
return 0.25*(b - a)*(f(a) + 2*f(c) + f(b)); //by definition of fine approx
}
double helper(double a, double b, double (*f)(double x), double tol)
{
return trap_rule(a, b, f, tol, 1);
}
And here's what's in main():
std::cout << "First we approximate the integral of f(x) = x^2 on [0,2]" << std::endl;
std::cout << "Enter a: ";
std::cin >> a;
std::cout << "Enter b: ";
std::cin >> b;
true_value1 = analytic_first(a,b);
for (int i = 0; i<=8; i++)
{
result1 [i] = helper(a, b, function_1, tolerance[i]);
error1 [i] = fabs(true_value1 - result1 [i]);
}
std::cout << "(Approximate integral of x^2, tolerance, error )" << std::endl;
for (int i = 0; i<=8; i++)
{
std::cout << "(" << result1 [i] << "," << tolerance[i] << "," << error1[i] << ")" << std::endl;
}
I find that exactly the opposite of what you suggest is happening --- the algorithm is terminating after only minLevel steps --- and the reason is due to your usage of abs, rather than fabs in the tolerance test. The abs is converting its argument to an int and thus any error less than 1 is getting rounded to zero.
With the abs in place I get this output from a very similar program:
(0.333496,0.001,0.00016276)
(0.333496,0.0001,0.00016276)
(0.333496,1e-05,0.00016276)
(0.333496,1e-06,0.00016276)
(0.333496,1e-07,0.00016276)
(0.333496,1e-08,0.00016276)
(0.333496,1e-09,0.00016276)
(0.333496,1e-10,0.00016276)
(0.333496,1e-11,0.00016276)
Replacing with fabs I get this:
(0.333496,0.001,0.00016276)
(0.333374,0.0001,4.06901e-05)
(0.333336,1e-05,2.54313e-06)
(0.333334,1e-06,6.35783e-07)
(0.333333,1e-07,3.97364e-08)
(0.333333,1e-08,9.93411e-09)
(0.333333,1e-09,6.20882e-10)
(0.333333,1e-10,3.88051e-11)
(0.333333,1e-11,9.7013e-12)
Related
/*I need to use the result from the (delta) function inside the (sol_ec_II) function for a school assignment.*/
#include <iostream>
#include <ctgmath>
using namespace std;
double delta(double a, double b, double c) {
return (b * b) - (4 * a * c);/* so I need to take this value [(b * b) - (4 * a * c)]
and use it in sol_ec_II in the places where I wrote "delta". */
}
void sol_ec_II(double a, double b, double c) {
if (delta < 0) {//here
cout << endl << "Polinomul NU are solutii.";
}
else {
double x1 = -1 * b - sqrt(delta);//here
double x2 = -1 * b + sqrt(delta);//here
}
}
// I would also need to use the (delta) function inside the (sol_ec_II) so they use the same
a, b, c values like this:
void sol_ec_II(double a, double b, double c) {
delta(a, b, c);
if (delta < 0) {
cout << endl << "Polinomul NU are solutii.";
}
else {
double x1 = -1 * b - sqrt(delta);
double x2 = -1 * b + sqrt(delta);
}
}
//so I don't understand how to get the value that results from delta(a, b, c) and use it inside the if statement and sqrt.
The result "comes out" of the function call at the time you call it. Look, you already know how sqrt works. sqrt is a function! You write sqrt(something) and that calls the function sqrt and it calls the function sqrt with the argument something and then the return value from sqrt gets used in the place where you wrote sqrt(something). e.g. 1 + sqrt(4) calculates 3.
Likewise the return value from delta gets used in the place where you wrote delta(a, b, c). If you want to call delta and then call sqrt (i.e. calculate the square root of the delta) you write sqrt(delta(a, b, c)).
Obviously, just calculating a number is pretty useless. You probably want to do something with the number, like saving it in a variable or printing it. Examples:
cout << "the square root of the delta is " << sqrt(delta(a,b,c)) << endl;
cout << "the delta plus one is " << (delta(a,b,c) + 1) << endl;
double the_delta = delta(a,b,c);
cout << "the delta is " << the_delta << " and the square root of the delta is " << sqrt(the_delta) << endl;
if (delta(a,b,c) < 0)
cout << "the delta is negative" << endl;
else
cout << "the delta isn't negative" << endl;
Note: Every time the computer runs delta(a,b,c) it calls the delta function. It doesn't remember the calculation from last time. You can see this because if you put cout instructions inside the delta function, they get printed every time the computer runs delta(a,b,c).
Of course I will not give you the solution for your program. I hope this helps you understand how functions work.
here you should pass parameters to deleta function in order to execute it:
void sol_ec_II(double a, double b, double c) {
if (delta(a,b,c) < 0) {//here
cout << endl << "Polinomul NU are solutii.";
}
else {
double x1 = -1 * b - sqrt(delta);//here
double x2 = -1 * b + sqrt(delta);//here
}
}
or you could save the result in a new variable called result for example, and after that use it, like that:
void sol_ec_II(double a, double b, double c) {
double result = delta(a,b,c);
if (result < 0) {//here
cout << endl << "Polinomul NU are solutii.";
}
else {
double x1 = -1 * b - sqrt(delta);//here
double x2 = -1 * b + sqrt(delta);//here
}
}
The Same thing for the second function, always to execute a function use parenthesis and pass between them the arguments that the function expects.
To reuse the value you get from calling a function multiple time use a variable:
double delta(double,double,double) { return 1.2; /*ignore this for now*/ }
void sol_ec_II(double a, double b, double c) {
const auto kDelta = delta(a, b, c);
if (kDelta < 0.0) {
// do stuff
} else {
const auto kRootD = sqrt(kDelta); // same idea
const auto x1 = -b - kRootD;
const auto x2 = -b + kRootD;
// use the variables
}
}
I use auto out of habit, you don't need to, double is fine.
I have a working Integrator class that will compute the definite Integral of basic functions of a single variable. I have tested the integrations of some basic functions and it appears to be working correctly.
I'm now at the point where I would like to expand this class to be able to perform multiple Integrals of the same function... and this is where I've hit a roadblock...
Here is my Integrator Class and some basic usage examples:
Integrator.h
#pragma once
#include <algorithm>
#include <utility>
#include <functional>
struct Limits {
double lower;
double upper;
Limits() : lower{ 0 }, upper{ 0 } {}
Limits(double a, double b) : lower{ a }, upper{ b } {
if (a > b) std::swap(lower, upper);
}
void applyLimits(double a, double b) {
lower = a;
upper = b;
if (a > b) std::swap(lower, upper);
}
};
class Integrator {
private:
Limits limits_;
std::function<double(double)> integrand_;
double dx_;
double dy_;
double integral_;
int step_size_;
public:
Integrator(Limits limits, int stepSize, std::function<double(double)> integrand, double dy = 0)
: limits_{ limits },
step_size_{ stepSize },
integrand_{ integrand },
dx_{ 0 }, dy_{ 0 }
{}
~Integrator() = default;
constexpr double dx() const { return this->dx_; }
constexpr double dy() const { return this->dy_; }
constexpr double integral() const { return this->integral_; }
Limits limits() const { return limits_; }
std::function<double(double)>* integrand() { return &this->integrand_; }
// This is always a 1st order of integration!
constexpr double evaluate() {
double distance = limits_.upper - limits_.lower; // Distance is defined as X0 to XN. (upperLimit - lowerLimit)
dx_ = distance / step_size_; // Calculate the amount of iterations by dividing
// the x-distance by the dx stepsize
integral_ = 0; // Initialize area to zero
for (auto i = 0; i < step_size_; i++) { // For each dx step or iteration calculate the area at Xi
dy_ = integrand_(limits_.lower + i * dx_);
double area = dy_ * dx_; // Where the width along x is defines as dxStepSize*i
integral_ += area; // and height(dy) is f(x) at Xi. Sum all of the results
}
return integral_;
}
};
main.cpp
#include <iostream>
#include <exception>
#include <cmath>
#include "Integrator.h"
constexpr double PI = 3.14159265358979;
constexpr double funcA(double x) {
return x;
}
constexpr double funcB(double x) {
return (x*x);
}
constexpr double funcC(double x) {
return ((0.5*(x*x)) + (3*x) - (1/x));
}
double funcD(double x) {
return sin(x);
}
int main() {
try {
std::cout << "Integration of f(x) = x from a=3.0 to b=5.0\nwith an expected output of 8\n";
Integrator integratorA(Limits(3.0, 5.0), 10000, &funcA);
std::cout << integratorA.evaluate() << '\n';
std::cout << "\n\nIntegration of f(x) = x^2 from a=2.0 to b=20.0\nwith an expected output of 2664\n";
Integrator integratorB(Limits(2.0, 20.0), 10000, &funcB);
std::cout << integratorB.evaluate() << '\n';
std::cout << "\n\nIntegration of f(x) = (1\\2)x^2 + 3x - (1\\x) from a=1.0 to b=10.0\nwith an expected output of 312.6974\n";
Integrator integratorC(Limits(1.0, 10.0), 10000, &funcC);
std::cout << integratorC.evaluate() << '\n';
std::cout << "\n\nIntegration of f(x) = sin(x) from a=0.0 to b=" <<PI<< "\nwith an expected output of 2\n";
Integrator integratorD(Limits(0.0, PI), 10000, &funcD);
std::cout << integratorD.evaluate() << '\n';
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Output
Integration of f(x) = x from a=3.0 to b=5.0
with an expected output of 8
7.9998
Integration of f(x) = x^2 from a=2.0 to b=20.0
with an expected output of 2664
2663.64
Integration of f(x) = (1\2)x^2 + 3x - (1\x) from a=1.0 to b=10.0
with an expected output of 312.6974
312.663
Integration of f(x) = sin(x) from a=0.0 to b=3.14159
with an expected output of 2
2
I was thinking of adding another function to this class similar to its evaluate() function... It currently looks something like this:
double integrate(Limits limits, double dy) {
double total = 0;
dy_ = dy;
for (int i = 0; i < step_size_; i++) {
double yi = limits_.lower*i*dy_;
double dx = static_cast<double>(yi - limits.lower) / stepSize;
double innerArea = 0;
for (int j = 0; j < step_size_; j++) {
Integrator inner(limits, step_size_, integrand_, dy_);
innerArea += inner.evaluate();
}
double outerArea = innerArea * dy_;
total += outerArea;
}
integral_ = total;
return integral_;
}
And this is where I'm getting confused or stumped... I'm not sure how to implement this function properly when it comes to the limits of integration with respect to the inner and outer integrals.
Take for example the following integral below:
The inner integral's upper limit is based on y for each iteration of computation... This has to be done dynamically. The outer integral is straight forward as it goes from [3,5] as opposed to [1,y].
I think I'm on the right track, but something in the above approach is totally off... I'm getting completely wrong values from expected or intended values...
Any and all suggestions and or tips are highly welcomed!
Edit - Note - I supplied the wrong image above, that has been updated...
The expected output should be: 65.582 with the correctly supplied function f(x) = 1/2x^2 + 3x - (1/x). And when I try to compute the double integral I end up getting this...
And here is the added code to the driver program or main.cpp...
std::cout << "\n\nTesting Double Integration of f(x) = (1\\2)x^2 + 3x - (1\\x) from [3,5] and [1,y]\nwith an expected output of 65.582\n";
Integrator integratorE(Limits(3, 5), 1000, &funcC);
double dy = integratorE.limits().upper - integratorE.limits().lower;
integratorE.integrate(Limits(1, integratorE.integral()), dy);
std::cout << integratorE.integral() << '\n';
However, it is not printing anything to the console...
Edit
I wasn't getting output for I wasn't waiting long enough. The iterations were defined as 1000 by the step_size. This will end up generating 1000^1000 total iterations... I had overlooked this in the construction of the Integrator object. I had changed this in my code to have a step_size of 100. And now my application is outputting a value of 2.68306e+189 which is clearly wrong! When I increase the step_size to 500 it is giving me something on the order of 6.62804e+190 which is still wrong.
After going back and watching the video again... I started to break down the double looping structure in my class's integrate() function.
I removed some unneeded parameters from both the constructor and this function's signature. I removed the dependency of passing in the dy since I'm able to calculate and store this value internally.
I had done a minor overhaul of my integrate member function. I'm now calculating both the dy and dx at the appropriate times using the appropriate limits of integration with respect to the step_size.
Instead of creating an instance of an Integrator within this function and using that instance's evaluate() function. I completely removed this behavior since I don't need to do this as this class stores an instance of the function of integration called integrand where this is an std::function<T> object. With this, I can just calculate the current y by passing in the xi into that integrand. Then I can use that to calculate the inner area for the summation.
My updated function looks like this:
double integrate(double lower = 0.0, double upper = 0.0) {
// Since we are not using the inner upper limit directly
// make sure that it is still greater than the lower limit
if (upper <= lower) {
upper = lower + 1;
}
Limits limits(lower, upper);
double outerSum = 0;
dy_ = static_cast<double>(limits_.upper - limits_.lower) / step_size_;
for (int i = 0; i < step_size_; i++) {
double yi = limits_.lower+i*dy_;
double dx_ = static_cast<double>(yi - limits.lower) / step_size_;
double innerSum = 0;
for (int j = 0; j < step_size_; j++) {
double xi = limits.lower + dx_ * j;
double fx = integrand_(xi);
double innerArea = fx*dx_;
innerSum += innerArea;
}
double outerArea = innerSum * dy_;
outerSum += outerArea;
}
integral_ = outerSum;
return integral_;
}
And here is the usage of this function within my main class:
std::cout << "\n\nTesting Double Integration of f(x) = (1\\2)x^2 + 3x - (1\\x) from [3,5] and [1,y]\nwith an expected output of 65.582\n";
Integrator integratorE(Limits(3, 5), 100, &funcC);
//double dy = integratorE.limits().upper - integratorE.limits().lower;
integratorE.integrate(1);
std::cout << integratorE.integral() << '\n';
And this is giving me an output of:
Testing Double Integration of f(x) = (1\2)x^2 + 3x - (1\x) from [3,5] and [1,y]
with an expected output of 65.582
64.6426
With a step_size of 100 iterations and an output of:
Testing Double Integration of f(x) = (1\2)x^2 + 3x - (1\x) from [3,5] and [1,y]
with an expected output of 65.582
65.3933
With a step_size of 500 iterations.
So as this class now stands, I can use evaluate() to perform a single definite integration of a single variable and I can use integrate(lower,upper) to perform at least a double definite integration of a single variable.
I need to count how many cubes of values between a and b (2 and 9 in this example) end with numbers between 2 and 5. Everything has to be done with recursion.
The output of this code is
part c = recc = 4
32767
0
It does not make sense to me. It calculates the value of n correctly, but then once asked to return it, returns either 0 or 32767, as if it was not defined.
Can anyone pinpoint the issue?
#include <iostream>
#include <string>
using namespace std;
void partb(int a, int b){
if(a<=b){
int p = (a*a*a)%10;
else if(p>=2 && p<=5){
cout<<a*a*a<<" ";
}
partb(a+1, b);
}
}
int recc(int n, int a, int b){
int p = (a*a*a)%10;
if(a>b){
cout<<"recc = " << n << endl;
return n;
}
else if(a<=b){
if(p>=2 && p<=5){
n++;
}
recc(n, a+1, b);
}
}
int partc(int a, int b){
int n = recc(0, a, b);
cout<<endl<< "part c = " << recc(0, a, b) << endl;
return n;
}
int main(){
int n=partc(2,9);
cout << n << endl;
return 0;
}
Not all control paths in your function return a value, so you were getting undefined behaviour when using the return value.
Now, this wasn't helped by the fact that the function itself is needlessly complicated. Let's rewrite it to use common practice for recursion:
int recc(int a, int b)
{
if (a > b) return 0;
int p = (a*a*a)%10;
int n = (p>=2 && p<=5) ? 1 : 0;
return n + recc(a+1, b);
}
Now your function is simpler. The recursion termination condition is right at the top. The function then decides whether a will contribute 1 or 0 to the count. And finally you return that value plus the count for a smaller range.
Notice how return n + recc(a+1, b); has broken the problem into a simple local solution combined with the recursive result of a reduced scope.
The invocation becomes simpler too, because you no longer have to pass in a redundant argument:
int partc(int a, int b)
{
int n = recc(a, b);
cout << endl << "part c = " << n << endl;
return n;
}
I would like to ask a very short question, and it is as follows: in finding the cube root of a number (both neg. and pos.) in C++, how does one restrict the output to real solutions only?
I am currently writing a program to solve a cubic with Cardano's formula, and one of the intermediate variables I am using randomly outputs the complex and real cube roots - and I only need the real roots.
(E.g. in evaluating the cube root of -0.0127378, the three roots would be 0.11677095+0.202253218i, −0.2335419, 0.11677095−0.202253218i - I wish to ignore the complex ones for substitution into a later formula)
Thank you!
EDIT: Solved it! :) I created a signum function and tweaked the sign after taking the power of the absolute value of SPrime and TPrime, so now it carries forward only the real cube root.
/* ... */
#include <iostream>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cassert>
using namespace std;
int signum(std::complex<double> z)
{
if (z.real() < 0 || z.imag() < 0) return -1;
else if (z.real() >= 0 || z.imag() >= 0) return 1;
}
// POST: The function is intended to solve a cubic equation with coefficients a, b, c and d., such that
// ax^3 + bx^2 + cx + d = 0. If there exist infinitely many solutions, we output -1, i.e. if a=b=c=d=0
// (trivial solution).
void solve(std::complex<double> a, std::complex<double> b, std::complex<double> c, std::complex<double> d, std::complex<double>& x1, std::complex<double>& x2, std::complex<double>& x3)
{
complex<double> i = complex<double> (0, 1.0);
// Consider implementing Cardano's method for obtaining the solution of a degree 3 polynomial, as suggested
// We must hence define the discriminant D of such an equation through complex doubles Q and R
std::complex<double> Q;
Q = (3.0*a*c - pow(b, 2)) / (9.0*pow(a, 2));
cout << "Q=" << Q << endl;
std::complex<double> R;
R = (9.0*a*b*c - 27.0*d*pow(a, 2) - 2.0*pow(b, 3)) / (54.0*pow(a, 3));
cout << "R=" << R << endl;
std::complex<double> D;
D = pow(Q, 3) + pow(R, 2);
// Possible types of output for discriminant
if (abs(D) < 0.0)
{
cout << "The cubic has three distinct, real roots." << endl;
}
else if (abs(D) == 0.0)
{
cout << "The cubic has three real roots, at least two of which are equal." << endl;
}
else if (abs(D) > 0.0)
{
cout << "The cubic has one real root and two complex conjugate roots." << endl;
}
// Defining two further complex double variables S and T, which are required to obtain the final solution for x1, x2 and x3
std::complex<double> S;
std::complex<double> SPrime;
SPrime = R+sqrt(Q*Q*Q + R*R);
cout << "SPrime=" << SPrime << endl;
if (signum(SPrime) == -1)
{
S = (-1)*pow(abs(SPrime), 0.3333333333333);
}
else if (signum(SPrime) == 1)
{
S = pow(abs(SPrime), 0.3333333333333);
}
cout << "S=" << S << endl;
std::complex<double> T;
std::complex<double> TPrime;
TPrime = (R-sqrt(Q*Q*Q + R*R));
if (signum(TPrime) == -1)
{
T = (-1)*pow(abs(TPrime), 0.3333333333333);
}
else if (signum(TPrime) == 1)
{
T = pow(abs(TPrime), 0.3333333333333);
}
cout << "T=" << T << endl;
cout << "TPrime= " << TPrime << endl;
// Expressions for the solutions
x1 = S + T - (b/(3.0*a));
x2 = (-0.5)*(S + T) - (b/(3.0*a)) + (sqrt(3.0)*0.5)*(S - T)*i;
x3 = conj(x2);
if (abs(x1) < 0.000000000001)
{
x1 = 0;
}
}
// Driver code
int main ()
{
// Taking user input for a, b, c and d
std::complex<double> a, b, c, d, x1, x2, x3;
cout << "Please enter the coefficients of the polynomial in successive order." << endl;
cin >> a >> b >> c >> d;
solve (a, b, c, d, x1, x2, x3);
cout << x1 << ", " << x2 << ", " << x3 << "." << endl;
return 0;
}
The problem as you're stating it can be solved trivially (with real numbers the cubic root of -x is the opposite of the cubic root of x):
double cuberoot(double x) {
if (x < 0) {
return -pow(-x, 1.0/3.0);
} else if (x > 0) {
return pow(x, 1.0/3.0);
} else {
return 0;
}
}
If the input is instead in general complex z and you're looking for the "most real" (principal) cubic root the same reasoning can be applied using complex pow version to either z or -z depending on the sign of the real part:
std::complex<double> cuberoot(std::complex<double> z) {
if (z.real() < 0) {
return -pow(-z, 1.0/3.0);
} else {
return pow(z, 1.0/3.0);
}
}
Problems with your code:
As you allow complex coefficients, the discussion of the discriminant becomes slightly meaningless, it is only of value for real coefficients.
abs(D) is always non-negative. If D==0, then there is a double root, more can not be said in the case of complex coefficients.
You can avoid a lot of code by utilizing that S*T=-Q. One would have to care that the computation of u=T^3 returns the larger of the roots of 0==u^2 - 2*R*u - Q^3 or (u-R)^2 = D = R^2+Q^3
rtD = sqrt(D);
T = cuberoot( R + (abs(R+rtD)>=abs(R-rtD)) ? rtD : -rtD );
S = (abs(T)<epsilon) ? 0 : -Q/T;
Because of abs(R)<=abs(T)^3 and abs(D)<=abs(T)^6
one gets also abs(Q)<=2^(1/3)*abs(T)^2 resulting in
abs(S)=abs(Q/T) <= 2^(1/3)*abs(T)
For S=-Q/T to fail one would thus need a serious case
of extremely small floating point numbers in R, Q
and thus T. Quantitatively, for double even
the threshold epsilon=1e-150 should be safe.
On cube root variants:
For esthetic reasons one might want T as close to a coordinate axis as possible. A cube root function achieving this would be
std::complex<double> cuberoot(std::complex<double> z) {
double r=abs(z), phi=arg(z);
double k = round(2*phi/pi);
// closest multiple of pi/2
// an equivalent angle is (phi-k*pi/2) - k*3*pi/2
return std::polar( pow(r,1.0/3), (phi-k*pi/2)/3 - k*pi/2 );
}
so that abs(phi-k*pi/2)<=pi/4, and thus the angle to the next coordinate axis of the cube root is smaller than pi/12=15°. cuberoot(i) returns -i, cuberoot(-1) returns -1, a point at 60° returns a cube root at (60°-90°)/3-90°=-100°, etc.
I've searched all over the net, but I could not find a solution to my problem. I simply want a function that rounds double values like MS Excel does. Here is my code:
#include <iostream>
#include "math.h"
using namespace std;
double Round(double value, int precision) {
return floor(((value * pow(10.0, precision)) + 0.5)) / pow(10.0, precision);
}
int main(int argc, char *argv[]) {
/* The way MS Excel does it:
1.27815 1.27840 -> 1.27828
1.27813 1.27840 -> 1.27827
1.27819 1.27843 -> 1.27831
1.27999 1.28024 -> 1.28012
1.27839 1.27866 -> 1.27853
*/
cout << Round((1.27815 + 1.27840)/2, 5) << "\n"; // *
cout << Round((1.27813 + 1.27840)/2, 5) << "\n";
cout << Round((1.27819 + 1.27843)/2, 5) << "\n";
cout << Round((1.27999 + 1.28024)/2, 5) << "\n"; // *
cout << Round((1.27839 + 1.27866)/2, 5) << "\n"; // *
if(Round((1.27815 + 1.27840)/2, 5) == 1.27828) {
cout << "Hurray...\n";
}
system("PAUSE");
return EXIT_SUCCESS;
}
I have found the function here at stackoverflow, the answer states that it works like the built-in excel rounding routine, but it does not. Could you tell me what I'm missing?
In a sense what you are asking for is not possible:
Floating point values on most common platforms do not have a notion of a "number of decimal places". Numbers like 2.3 or 8.71 simply cannot be represented precisely. Therefore, it makes no sense to ask for any function that will return a floating point value with a given number of non-zero decimal places -- such numbers simply do not exist.
The only thing you can do with floating point types is to compute the nearest representable approximation, and then print the result with the desired precision, which will give you the textual form of the number that you desire. To compute the representation, you can do this:
double round(double x, int n)
{
int e;
double d;
std::frexp(x, &e);
if (e >= 0) return x; // number is an integer, nothing to do
double const f = std::pow(10.0, n);
std::modf(x * f, &d); // d == integral part of 10^n * x
return d / f;
}
(You can also use modf instead of frexp to determine whether x is already an integer. You should also check that n is non-negative, or otherwise define semantics for negative "precision".)
Alternatively to using floating point types, you could perform fixed point arithmetic. That is, you store everything as integers, but you treat them as units of, say, 1/1000. Then you could print such a number as follows:
std::cout << n / 1000 << "." << n % 1000;
Addition works as expected, though you have to write your own multiplication function.
To compare double values, you must specify a range of comparison, where the result could be considered "safe". You could use a macro for that.
Here is one example of what you could use:
#define COMPARE( A, B, PRECISION ) ( ( A >= B - PRECISION ) && ( A <= B + PRECISION ) )
int main()
{
double a = 12.34567;
bool equal = COMPARE( a, 12.34567F, 0.0002 );
equal = COMPARE( a, 15.34567F, 0.0002 );
return 0;
}
Thank you all for your answers! After considering the possible solutions I changed the original Round() function in my code to adding 0.6 instead of 0.5 to the value.
The value "127827.5" (I do understand that this is not an exact representation!) becomes "127828.1" and finally through floor() and dividing it becomes "1.27828" (or something more like 1.2782800..001). Using COMPARE suggested by Renan Greinert with a correctly chosen precision I can safely compare the values now.
Here is the final version:
#include <iostream>
#include "math.h"
#define COMPARE(A, B, PRECISION) ((A >= B-PRECISION) && (A <= B+PRECISION))
using namespace std;
double Round(double value, int precision) {
return floor(value * pow(10.0, precision) + 0.6) / pow(10.0, precision);
}
int main(int argc, char *argv[]) {
/* The way MS Excel does it:
1.27815 1.27840 // 1.27828
1.27813 1.27840 -> 1.27827
1.27819 1.27843 -> 1.27831
1.27999 1.28024 -> 1.28012
1.27839 1.27866 -> 1.27853
*/
cout << Round((1.27815 + 1.27840)/2, 5) << "\n";
cout << Round((1.27813 + 1.27840)/2, 5) << "\n";
cout << Round((1.27819 + 1.27843)/2, 5) << "\n";
cout << Round((1.27999 + 1.28024)/2, 5) << "\n";
cout << Round((1.27839 + 1.27866)/2, 5) << "\n";
//Comparing the rounded value against a fixed one
if(COMPARE(Round((1.27815 + 1.27840)/2, 5), 1.27828, 0.000001)) {
cout << "Hurray!\n";
}
//Comparing two rounded values
if(COMPARE(Round((1.27815 + 1.27840)/2, 5), Round((1.27814 + 1.27841)/2, 5), 0.000001)) {
cout << "Hurray!\n";
}
system("PAUSE");
return EXIT_SUCCESS;
}
I've tested it by rounding a hundred double values and than comparing the results to what Excel gives. They were all the same.
I'm afraid the answer is that Round cannot perform magic.
Since 1.27828 is not exactly representable as a double, you cannot compare some double with 1.27828 and hope it will match.
You need to do the maths without the decimal part, to get that numbers... so something like this.
double dPow = pow(10.0, 5.0);
double a = 1.27815;
double b = 1.27840;
double a2 = 1.27815 * dPow;
double b2 = 1.27840 * dPow;
double c = (a2 + b2) / 2 + 0.5;
Using your function...
double c = (Round(a) + Round(b)) / 2 + 0.5;