Loop with float iteration - c++

First Situation
for (int i = 0 ; i <=2 ; i++)
{
cout << i << endl ;
}
output:
1
2
Second Situation
for (float i = 0 ; i <= 2 ; i+=.2)
{
cout << i << endl;
}
output
1
1.2
1.4
1.6
1.8
The question is why in the second situation he didn't take the 2 even i said ( <= )
and the funny thing if i remove the = the output will be even the same ?
Constrains
i have to use the float DataType
and i want to use the <= Operator

Because 0.2 doesn't fit exactly in a float and you accumulate floating point errors in your loop. On my computer accumulating 10 times 0.2 is 2.38419e-07 above 2.0f

You cannot compare float or double variables using == because of possible arithmetic rounding errors. You should use epsilon.
const float EPSILON = 0.00001f;
for (float f = 0.0f; EPSILON > std::fabs(f - 2.0f); f += 0.2f)
{
std::cout << f << std::endl;
}
Also try use lireral f when you are using float type (float my_float = 12.4f;).

Related

how to improve the precision of computing float numbers?

I write a code snippet in Microsoft Visual Studio Community 2019 in C++ like this:
int m = 11;
int p = 3;
float step = 1.0 / (m - 2 * p);
the variable step is 0.200003, 0.2 is what i wanted. Is there any suggestion to improve the precision?
This problem comes from UNIFORM KNOT VECTOR. Knot vector is a concept in NURBS. You can think it is just an array of numbers like this: U[] = {0, 0.2, 0.4, 0.6, 0.8, 1.0}; The span between two adjacent numbers is a constant. The size of knot vector can be changed accroding to some condition, but the range is in [0, 1].
the whole function is:
typedef float NURBS_FLOAT;
void CreateKnotVector(int m, int p, bool clamped, NURBS_FLOAT* U)
{
if (clamped)
{
for (int i = 0; i <= p; i++)
{
U[i] = 0;
}
NURBS_FLOAT step = 1.0 / (m - 2 * p);
for (int i = p+1; i < m-p; i++)
{
U[i] = U[i - 1] + step;
}
for (int i = m-p; i <= m; i++)
{
U[i] = 1;
}
}
else
{
U[0] = 0;
NURBS_FLOAT step = 1.0 / m;
for (int i = 1; i <= m; i++)
{
U[i] = U[i - 1] + step;
}
}
}
Let's follow what's going on in your code:
The expression 1.0 / (m - 2 * p) yields 0.2, to which the closest representable double value is 0.200000000000000011102230246251565404236316680908203125. Notice how precise it is – to 16 significant decimal digits. It's because, due to 1.0 being a double literal, the denominator is promoted to double, and the whole calculation is done in double precision, thus yielding a double value.
The value obtained in the previous step is written to step, which has type float. So the value has to be rounded to the closest representable value, which happens to be 0.20000000298023223876953125.
So your cited result of 0.200003 is not what you should get. Instead, it should be closer to 0.200000003.
Is there any suggestion to improve the precision?
Yes. Store the value in a higher-precision variable. E.g., instead of float step, use double step. In this case the value you've calculated won't be rounded once more, so precision will be higher.
Can you get the exact 0.2 value to work with it in the subsequent calculations? With binary floating-point arithmetic, unfortunately, no. In binary, the number 0.2 is a periodic fraction:
0.210 = 0.0̅0̅1̅1̅2 = 0.0011 0011 0011...2
See Is floating point math broken? question and its answers for more details.
If you really need decimal calculations, you should use a library solution, e.g. Boost's cpp_dec_float. Or, if you need arbitrary-precision calculations, you can use e.g. cpp_bin_float from the same library. Note that both variants will be orders of magnitude slower than using bulit-in C++ binary floating-point types.
When dealing with floating point math a certain amount of rounding errors are expected.
For starters, values like 0.2 aren't exactly represented by a float, or even a double:
std::cout << std::setprecision(60) << 0.2 << '\n';
// ^^^ It outputs something like: 0.200000000000000011102230246251565404236316680908203125
Besides, the errors may accumulate when a sequence of operations are performed on imprecise values. Some operations, like summation and subctraction, are more sensitive to this kind of errors than others, so it'd be better to avoid them if possible.
That seems to be the case, here, where we can rewrite OP's function into something like the following
#include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <cassert>
#include <type_traits>
template <typename T = double>
auto make_knots(int m, int p = 0) // <- Note that I've changed the signature.
{
static_assert(std::is_floating_point_v<T>);
std::vector<T> knots(m + 1);
int range = m - 2 * p;
assert(range > 0);
for (int i = 1; i < m - p; i++)
{
knots[i + p] = T(i) / range; // <- Less prone to accumulate rounding errors
}
std::fill(knots.begin() + m - p, knots.end(), 1.0);
return knots;
}
template <typename T>
void verify(std::vector<T> const& v)
{
bool sum_is_one = true;
for (int i = 0, j = v.size() - 1; i <= j; ++i, --j)
{
if (v[i] + v[j] != 1.0) // <- That's a bold request for a floating point type
{
sum_is_one = false;
break;
}
}
std::cout << (sum_is_one ? "\n" : "Rounding errors.\n");
}
int main()
{
// For presentation purposes only
std::cout << std::setprecision(60) << 0.2 << '\n';
std::cout << std::setprecision(60) << 0.4 << '\n';
std::cout << std::setprecision(60) << 0.6 << '\n';
std::cout << std::setprecision(60) << 0.8 << "\n\n";
auto k1 = make_knots(11, 3);
for (auto i : k1)
{
std::cout << std::setprecision(60) << i << '\n';
}
verify(k1);
auto k2 = make_knots<float>(10);
for (auto i : k2)
{
std::cout << std::setprecision(60) << i << '\n';
}
verify(k2);
}
Testable here.
One solution to avoid drift (which I guess is your worry?) is to manually use rational numbers, for example in this case you might have:
// your input values for determining step
int m = 11;
int p = 3;
// pre-calculate any intermediate values, which won't have rounding issues
int divider = (m - 2 * p); // could be float or double instead of int
// input
int stepnumber = 1234; // could also be float or double instead of int
// output
float stepped_value = stepnumber * 1.0f / divider;
In other words, formulate your problem so that step of your original code is always 1 (or whatever rational number you can represent exactly using 2 integers) internally, so there is no rounding issue. If you need to display the value for user, then you can do it just for display: 1.0 / divider and round to suitable number of digits.

I used both the Leibniz and the Wallis formulas for estimating π but am getting wrong output numbers, I couldn't figure out where did I go wrong

#include <cmath> \\not sure if I need cmath
#include <iostream>
using namespace std;
this while loop serves to loop the " enter number of terms to approximate.
while (a != 0)
{
here is the Leibniz formula:
double c = 0.00, d = 0.00;
for (int i = 1; i <= a)
{
if (i % 2 != 0)
{
d = 1 / (1 + 2 * (i - 1));
}
else
{
d = -1 / (1 + 2 * (i - 1));
}
c = c + d;
i = i + 1
}
cout.setf(ios::fixed);
cout.setf(ios::showpoint);
cout.precision(5);
cout << "The approximation for Leibniz's Formula is " << c << "
using "<< a <<" terms." << endl;
here is the Wallis formula:
double e = 1.00;
for (int u = 0; u<a; u++)
{
e = e * (2 * a / (2 * a - 1))*(2 * a / (2 * a + 1));
}
cout << "The approximation for Wallis' Formula is " << e << " using
"<< a <<" terms." << endl;
cout << endl;
cout << "Enter the number of terms to approximate (or zero to
quit):" << endl;
cin >> a;
}
For a=1 I am getting 1.0000 in the first formula output and 0.00000 in the second formula output
A line like this
d = 1 / (1 + 2 * (i - 1));
will use integer arithmetics to calculate the result, and then convert the int result to a double.
Change it to
d = 1.0 / (1 + 2 * (i - 1));
or even
d = 1.0 / (1.0 + 2.0 * (i - 1.0));
There are many mistakes in this code. First, comments in c++ use //, not \\.
#include <cmath> //not sure if I need cmath
You have to have two semicolons in for statements, even if you don't need loop-expression.
for (int i = 1; i <= a;)
The d will evaluate to 0 for every i that is greater than 1. You are using integer division, when you clearly want floating point division. You have to tell that to the compiler like this.
d = 1.0 / (1 + 2 * (i - 1));
When the left argument of division operator is double compiler will know, that you want to perform a floating point division. If it would be int as in your code, integer division would be performed and result converted to double.
Also in the Wallis formula you misplaced a for u, and also u parameter should start at 1, not 0. Also the integer division problem persists here.
double e = 1.00;
for (int u = 1; u<a; u++)
{
e = e * (2.0 * u / (2.0 * u - 1))*(2.0 * u / (2.0 * u + 1));
}
If you fix this all, the program starts to output valid results.

Rounding double values in C++ like MS Excel does it

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;

modf returns 1 as the fractional:

I have this static method, it receives a double and "cuts" its fractional tail leaving two digits after the dot. works almost all the time. I have noticed that when
it receives 2.3 it turns it to 2.29. This does not happen for 0.3, 1.3, 3.3, 4.3 and 102.3.
Code basically multiplies the number by 100 uses modf divides the integer value by 100 and returns it.
Here the code catches this one specific number and prints out:
static double dRound(double number) {
bool c = false;
if (number == 2.3)
c = true;
int factor = pow(10, 2);
number *= factor;
if (c) {
cout << " number *= factor : " << number << endl;
//number = 230;// When this is not marked as comment the code works well.
}
double returnVal;
if (c){
cout << " fractional : " << modf(number, &returnVal) << endl;
cout << " integer : " <<returnVal << endl;
}
modf(number, &returnVal);
return returnVal / factor;
}
it prints out:
number *= factor : 230
fractional : 1
integer : 229
Does anybody know why this is happening and how can i fix this?
Thank you, and have a great weekend.
Remember floating point number cannot represent decimal numbers exactly. 2.3 * 100 actually gives 229.99999999999997. Thus modf returns 229 and 0.9999999999999716.
However, cout's format will only display floating point numbers to 6 decimal places by default. So the 0.9999999999999716 is shown as 1.
You could use (roughly) the upper error limit that a value represents in floating point to avoid the 2.3 error:
#include <cmath>
#include <limits>
static double dRound(double d) {
double inf = copysign(std::numeric_limits<double>::infinity(), d);
double theNumberAfter = nextafter(d, inf);
double epsilon = theNumberAfter - d;
int factor = 100;
d *= factor;
epsilon *= factor/2;
d += epsilon;
double returnVal;
modf(number, &returnVal);
return returnVal / factor;
}
Result: http://www.ideone.com/ywmua
Here is a way without rounding:
double double_cut(double d)
{
long long x = d * 100;
return x/100.0;
}
Even if you want rounding according to 3rd digit after decimal point, here is a solution:
double double_cut_round(double d)
{
long long x = d * 1000;
if (x > 0)
x += 5;
else
x -= 5;
return x / 1000.0;
}

Calculating the value of pi-what is wrong with my code

I'm doing another C++ exercise. I have to calculate the value of pi from the infinite series:
pi=4 - 4/3 + 4/5 – 4/7 + 4/9 -4/11+ . . .
The program has to print the approximate value of pi after each of the first 1,000 terms of this series.
Here is my code:
#include <iostream>
using namespace std;
int main()
{
double pi=0.0;
int counter=1;
for (int i=1;;i+=2)//infinite loop, should "break" when pi=3.14159
{
double a=4.0;
double b=0.0;
b=a/static_cast<double>(i);
if(counter%2==0)
pi-=b;
else
pi+=b;
if(i%1000==0)//should print pi value after 1000 terms,but it doesn't
cout<<pi<<endl;
if(pi==3.14159)//this if statement doesn't work as well
break;
counter++;
}
return 0;
}
It compiles without errors and warnings, but only the empty console window appears after execution. If I remove line” if(i%1000==0)” , I can see it does run and print every pi value, but it doesn’t stop, which means the second if statement doesn’t work either. I’m not sure what else to do. I’m assuming it is probably a simple logical error.
Well, i % 1000 will never = 0, as your counter runs from i = 1, then in increments of 2. Hence, i is always odd, and will never be a multiple of 1000.
The reason it never terminates is that the algorithm doesn't converge to exactly 3.14157 - it'll be a higher precision either under or over approximation. You want to say "When within a given delta of 3.14157", so write
if (fabs(pi - 3.14157) < 0.001)
break
or something similar, for however "close" you want to get before you stop.
Since you start i at 1 and increment by 2, i is always an odd number, so i % 1000 will never be 0.
you have more than one problem:
A. i%1000==0 will never be true because you're iterating only odd numbers.
B. pi==3.14159 : you cannot compare double values just like that because the way floating point numbers are represented (you can read about it here in another question). in order for it to work you should compare the values in another way - one way is to subtract them from each other and check that the absolute result is lower than 0.0000001.
You have floating point precision issues. Try if(abs(pi - 3.14159) < 0.000005).
i%1000 will never be 0 because i is always odd.
Shouldn't it be:
if (counter%1000==0)
i starts at 1 and then increments by 2. Therefore i is always odd and will never be a multiple of 1000, which is why if (i % 1000 == 0) never passes.
Directly comparing floats doesn't work, due to floating precision issues. You will need to compare that the difference between the values is close enough.
pi=4 - 4/3 + 4/5 – 4/7 + 4/9 -4/11 + ...
Generalising
pi = Σi=0∞ (-1)i 4 / (2i+1)
Which gives us a cleaner approach to each term; the i'th term is given by:
double term = pow(-1,i%2) * 4 / (2*i+1);
where i=0,1,2,...,N
So, our loop can be fairly simple, given some number of iterations N
int N=2000;
double pi=0;
for(int i=0; i<N; i++)
{
double term = pow(-1,i%2) * 4 / (2*(double)i+1);
pi += term;
cout << i << "\t" << pi <<endl;
}
Your original question stated "The program has to print the approximate value of pi after each of the first 1,000 terms of this series". This does not imply any need to check whether 3.14159 has been reached, so I have not included this here. The pow(-1,i%2) call is just to avoid if statements (which are slow) and prevent any complications with large i.
Be aware that after a number of iterations, the difference between the magnitude of pi and the magnitude of the correcting term (say -4/25) will be so small that it will go beyond the precision of a double, so you would need higher precision types to deal with it.
By default abs uses the abs macro which is for int. For doubles, use the cmath library.
#include <iostream>
#include <cmath>
int main()
{
double pi=0.0;
double a=4.0;
int i = 1;
for (i=1;;i+=2)
{
pi += (1 - 2 * ((i/2)%2)) * a/static_cast<double>(i);
if( std::abs(pi - 3.14159) < 0.000001 )
break;
if (i > 2000) //1k iterations
break;
}
std::cout<<pi<<std::endl;
return 0;
}
Here is the corrected code. I thought it may be helpful in the future if somebody has similar problem.
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
double pi=0.0;
int counter=1;
for (int i=1;;i+=2)
{
double a=4.0;
double b=0.0;
b=a/static_cast<double>(i);
if(counter%2==0)
pi-=b;
else
pi+=b;
if(counter%1000==0)
cout<<pi<<" "<<counter<<endl;
if (fabs(pi - 3.14159) < 0.000001)
break;
counter++;
}
cout<<pi;
return 0;
}
Here is a better one:
class pi_1000
{
public:
double doLeibniz( int i ) // Leibniz famous formula for pi, source: Calculus II :)
{
return ( ( pow( -1, i ) ) * 4 ) / ( ( 2 * i ) + 1 );
}
void piCalc()
{
double pi = 4;
int i;
cout << "\npi calculated each iteration from 1 to 1000\n"; //wording was a bit confusing.
//I wasn't sure which one is the right one: 0-1000 or each 1000th.
for( i = 1; i < 1000; i++ )
{
pi = pi + doLeibniz( i );
cout << fixed << setprecision( 5 ) << pi << "\t" << i + 1 << "\n";
}
pi = 4;
cout << "\npi calculated each 1000th iteration from 1 to 20000\n";
for( i = 1; i < 21000; i++ )
{
pi = pi + doLeibniz( i );
if( ( ( i - 1 ) % 1000 ) == 0 )
cout << fixed << setprecision( 5 ) << pi << "\t" << i - 1 << "\n";
}
}