Long double overflows but value smaller than maximum representable value - c++

I'm trying to compute a series using C++.
The series is:
(for those wondering)
My code is the following:
#include <iostream>
#include <fstream>
#include <cmath> // exp
#include <iomanip> //setprecision, setw
#include <limits> //numeric_limits (http://en.cppreference.com/w/cpp/types/numeric_limits)
long double SminOneCenter(long double gamma)
{
using std::endl; using std::cout;
long double result=0.0l;
for (long double k = 1; k < 1000 ; k++)
{
if(isinf(pow(1.0l+pow(gamma,k),6.0l/4.0l)))
{
cout << "infinity for reached for gamma equals: " << gamma << "value of k: " << k ;
cout << "maximum allowed: " << std::numeric_limits<long double>::max()<< endl;
break;
}
// CAS PAIR: -1^n = 1
if ((int)k%2 == 0)
{
result += pow(4.0l*pow(gamma,k),3.0l/4.0l) /(pow(1+pow(gamma,k)),6.0l/4.0l);
}
// CAS IMPAIR:-1^n = -1
else if ((int)k%2!=0)
{
result -= pow(4.0l*pow(gamma,k),3.0l/4.0l) /(pow(1+pow(gamma,k)),6.0l/4.0l);
//if (!isinf(pow(k,2.0l)*zeta/2.0l))
}
// cout << result << endl;
}
return 1.0l + 2.0l*result;
}
Output will be, for instance with gamma = 1.7 :
infinity reached for gamma equals: 1.7 value of k: 892
The maximum value a long double can represent, as provided by the STL numeric_limits, is: 1.18973e+4932.
However (1+1.7^892)= 2.19.... × 10^308 which is way lower than 10^4932, so it shouldn't be considered as infinity.
Provided my code is not wrong (but it very well might be), could anyone tell me why the discussed code evals to infinity when it should not?

You need to use powl rather than pow if you want to supply long double arguments.
Currently you are hitting the numeric_limits<double>::max() in your pow calls.
As an alternative, consider using std::pow which has appropriate overloads.
Reference http://en.cppreference.com/w/c/numeric/math/pow

Related

How ceil function works in c++?

When I execute this code the value of ans1, ans2 is 50002896 and 50005000.
I know there is some issues with ceil function but was not able to figure out the exact cause.
#include <bits/stdc++.h>
using namespace std;
int main()
{
long long ans1 = 0, ans2 = 0;
for (long long i = 1; i <= 10000; i++)
{
ans1 = ans1 + ceil((float)i / 1);
ans2 = ans2 + i;
}
cout << ans1 << " " << ans2 << endl;
}
The source of the problem is not the ceil function, but rather that not all integers can be represented accuratly as floating point values.
Some more info about floating point representation: Wikipedia IEEE 754. And a related post: Which is the first integer that an IEEE 754 float is incapable of representing exactly?.
The following code is a minimal demonstration of the same issue that causes your issue:
float f1 = 100000000;
f1++;
std::cout << std::to_string(f1) << std::endl;
[Wrong] Output (expected: +1):
100000000.000000
One approach would be to use double instead of float.
This will not solve the principle issue, but will make the range of representable integers a lot bigger:
double f1 = 100000000;
f1++;
std::cout << std::to_string(f1) << std::endl;
Output:
100000001.000000
Some side notes:
better to avoid #include <bits/stdc++.h> - see here: Why should I not #include <bits/stdc++.h>?.
better to avoid using namespace std - see here Why is "using namespace std;" considered bad practice?.
First, try to use specific headers like #include , in this case, .because #include <bits/stdc++.h> will bring lots of junk.
So the issue is with float not ceil explained below
floating-point values do not represent exact values.
Code:-
#include <iostream>
#include <iomanip>
using namespace std;
// Driver Code
int main()
{
float num1 = 10000.29;
float num2 = 10000.2;
// Output should be 0.0900000000
cout << std::setprecision(15)
<< (num1 - num2);
return 0;
}
Output :-
0.08984375

Auto Rounding From Something While Dividing and Multiplying

#include <iostream>
#include <iomanip>
#include <vector>
using namespace std;
int(main){
std::vector<int> vObj;
float n = 0.59392;
int nCopy = n;
int temNum = 0;;
while (fmod(nCopy, 1) != 0) {
temNum = (nCopy * 10); cout << endl << nCopy << endl;
nCopy *= 10;
vObj.push_back(temNum);
cout << "\n\n Cycle\n\n";
cout << "Temp Num: " << temNum << "\n\nN: " << nCopy << endl;
}
return 0;
}
For example, I input 0.59392 but eventually when the code reaches the bottom, where it should be going
5939.2 and then go to
59392 and stop but for some reason
it keeps going.
yeah , so you have 3 major problems in your code , first of all : it's int main() not int(main) . second : the variable named **nCopy ** is not supposed to be a integer data type , third one : you have to know what the actual representation of the float number , but first this is my solution for your problem , it's not the best one , but it works for this case :
#include <iostream>
#include <iomanip>
#include <vector>
using namespace std;
int main() {
std::vector<int> vObj;
double n = 0.59392;
double nCopy = n;
int temNum = 0;;
while (fmod(nCopy, 1) != 0) {
temNum = (nCopy * 10); cout << endl << nCopy << endl;
nCopy *= 10;
vObj.push_back(temNum);
cout << "\n\n Cycle\n\n";
cout << "Temp Num: " << temNum << "\n\nN: " << nCopy << endl;
}
return 0;
}
so the explanation is as follow , the double data types gives higher precision than float , that's why I used double instead of float , but it will lack accuracy when the number becomes big .
second of : you have to how is float or double is represented , as the value 0.59392 is actually stored in the memory as value 0.593900024890899658203125 when using float according to IEEE 754 standard , so there are other types of decimals to solve this problem where the difference between them is as follow
Decimal representation gives lower accuracy but higher range with big numbers and high accuracy when talking about small numbers, most 2 used standards are binary integer decimal (BID) and densely packed decimal (DPD)
float and doubles gives higher accuracy than Decimal when talking about big numbers but lower range ,they follow IEEE 754 standard
Fixed-Point types have the lowest range but they are the most accurate one and they are the fastest ones
but unfortunately , C++ only supports float and double types of numbers , but I believe there is external libraries out there to define a decimal data type.

Is there a limit on the number of values added to a boost::accumulator?

Is there a limit on how many values that can be added to a boost::accumulator? If a large number of entries were added, is there any point in which the accumulator would cease to work properly or is the internal algorithm robust enough to account for a set of values approaching infinity?
#include <iostream>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/mean.hpp>
#include <boost/accumulators/statistics/moment.hpp>
using namespace boost::accumulators;
int main()
{
// Define an accumulator set for calculating the mean and the
// 2nd moment ...
accumulator_set<double, stats<tag::mean, tag::moment<2> > > acc;
// push in some data ...
for (std::size_t i=0; i<VERY_LARGE_NUMBER; i++)
{
acc(i);
}
// Display the results ...
std::cout << "Mean: " << mean(acc) << std::endl;
std::cout << "Moment: " << moment<2>(acc) << std::endl;
return 0;
}
If your int is a 32 bit integer, you'll get a signed integer overflow at 46341 * 46341 when calculating moment<2> and your program therefore has undefined behavior.
To avoid that, cast i to the type you're using in the accumulator:
acc(static_cast<double>(i));
This will now have the same limits as a normal double. You can add as many elements as you'd like to it as long as you don't exceed the limit (std::numeric_limits<double>::max()) for a double in the internal moment calculations (x2 for moment<2> or a sum that exceeds the limit).
The accumulator statistics do not account for overflow, so you need to select the accumulator type carefully. It doesn't need to match the initial type of the objects you are adding—you can cast it when accumulating, then get the statistics and cast it back to the original type.
You can see it with this simple example:
#include <bits/stdc++.h>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics.hpp>
using namespace boost::accumulators;
int main(void) {
accumulator_set<int8_t, features<tag::mean>> accInt8;
accumulator_set<double, features<tag::mean>> accDouble;
int8_t sum = 0; // range of int8_t: -128 to 127
for (int8_t i = 1; i <= 100; i++) {
sum += i; // this will overflow!
accInt8(i); // this will also overflow
accDouble((double)i);
}
std::cout << "sum from 1 to 100: " << (int)sum << " (overflow)\n";
std::cout << "mean(<int8_t>): " << extract::mean(accInt8) << " (overflow)\n";
std::cout << "mean(<double>): " << (int)extract::mean(accDouble) << "\n";
return 0;
}
I used int8_t which has a very small range (-128 to 127) to demonstrate that getting the mean from values 1 to 100 (which should be 50) overflows if you use int8_t as the internal type for the accumulator_set.
The output is:
sum from 1 to 100: -70 (overflow)
mean(<int8_t>): -7 (overflow)
mean(<double>): 50

How to find first pi beginning with 3.14159

For determining how many terms are required for the first time getting pi that begins with 3.14159 I wrote the following program that calculates terms as (pi = 4 - 4/3 + 4/5 - 4/7 + ...).
My problem is that I reached 146063 terms as the result but when I checked, there are many pis that begin similarly before that.
//piEstimation.cpp
//estima mathematical pi and detrmin when
//to get a value beganing with 3.14159
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
int main(){
//initialize vars
double denominator{1.0};
double pi{0};
string piString;
double desiredPi;
int terms;
int firstDesiredTerm;
//format output floating point numbers to show 10 digits after
// decimal poin
cout << setprecision (10) <<fixed;
for (terms = 1; ; terms++){
if(0 == terms % 2){ //if term is even
pi -= 4/denominator;
}
else{ //if term is odd
pi += 4/denominator;
}
// draw table
cout << terms << "\t" << pi << endl;
//determin first time the pi begains with 3.14159
piString = to_string(pi).substr(0,7);
if(piString == "3.14159"){
firstDesiredTerm = terms;
desiredPi = pi;
break;
}
denominator += 2;
}//end for
cout << "The first time that pi value begans with 3.14159 "
<< "the number of terms are " << firstDesiredTerm << " and pi value is "<< desiredPi <<endl;
}//end main
A number x begins with 3.14159 if x >= 3.14159 && x < 3.1416. There is no need to use strings and compare characters. to_string has to use some kind of round operation. Without the string the algorithm finds the result after 136121 steps
#include <iostream>
#include <iomanip>
int main(){
//initialize vars
double denominator{1.0};
double pi{0};
double desiredPi;
int terms;
int firstDesiredTerm;
//format output floating point numbers to show 10 digits after
// decimal poin
std::cout << std::setprecision (20) << std::fixed;
for (terms = 1; ; terms++){
if(0 == terms % 2){ //if term is even
pi -= 4/denominator;
}
else{ //if term is odd
pi += 4/denominator;
}
// draw table
std::cout << terms << "\t" << pi << std::endl;
if(pi >= 3.14159 && pi < 3.1416){
firstDesiredTerm = terms;
desiredPi = pi;
break;
}
denominator += 2;
}//end for
std::cout << "The first time that pi value begans with 3.14159 "
<< "the number of terms are " << firstDesiredTerm
<< " and pi value is "<< desiredPi << std::endl;
}
Output:
The first time that pi value begans with 3.14159 the number of terms are 136121 and pi value is 3.14159999999478589672
Here you can see how to_string rounds the result:
#include <iostream>
#include <iomanip>
#include <string>
int main(){
std::cout << std::setprecision (20) << std::fixed;
std::cout << std::to_string(3.14159999999478589672) << '\n';
}
Output:
3.141600
You can read on cppreference
std::string to_string( double value ); Converts a floating point value to a string with the same content as what std::sprintf(buf, "%f", value) would produce for sufficiently large buf.
You can read on cppreference
f F Precision specifies the exact number of digits to appear after the decimal point character. The default precision is 6
That means that std::to_string rounds after 6 digits.

What does double store?

I'm sending the value 4 *cos( fmod( acos(2.0/4.0), 2*3.14159265) ) as double to this function but I get output as
2
1k1
What is wrong here?
void convert_d_to_f(double n)
{
cout<<n<<" ";
double mantissa;
double fractional_part;
fractional_part = modf(n,&mantissa);
double x = fractional_part;
cout<<mantissa<<"k"<<fractional_part<<'\n';
}
The problem is that cout truncates and rounds double while printing. You can print the desired number of decimal places usingiomanip library.
#include <iostream>
#include <cmath>
#include <iomanip>
void convert_d_to_f(double n)
{
cout<<std::fixed<<std::setprecision(20); //number of decimal places you need to print to
cout<<n<<" ";
double mantissa;
double fractional_part;
fractional_part = modf(n,&mantissa);
double x = fractional_part;
cout<<mantissa<<"k"<<fractional_part<<'\n';
}
int main() {
convert_d_to_f(4 *cos( fmod( acos(2.0/4.0), 2*3.14159265) ));
return 0;
}
For all practical intents and purposes, your number n evaluates to 2. If you want it to display as 1.9999999... etc. then follow Kapil's solution and set the floating point precision for std::cout to many decimal places. Keep in mind the difference between precision and accuracy if you are going to go that route.
That being said, your void convert_d_to_f(double n) function is replicating the functionality of std::frexp(double arg, int* exp) with a limitation where your results are going out of scope after you print them to the screen. If you desire to use your exponent and mantissa values after computing them, then you can do it like this.
#include <iostream>
#include <cmath>
int main()
{
double n = 4 *cos( fmod( acos(2.0/4.0), 2*3.14159265) );
std::cout << "Given the number " << n << std::endl;
// convert the given floating point value `n` into a
// normalized fraction and an integral power of two
int exp;
double mantissa = std::frexp(n, &exp);
// display results as Mantissa x 2^Exponent
std::cout << "We have " << n << " = "
<< mantissa << " * 2^" << exp << std::endl;
return 0;
}