Floating point error in c++ - c++

I have found a simple floating point error and I was wondering if there is a way around it. I'm compiling in Haiku OS. I'm in Haiku r1 Alpha 4
#include <iostream>
#include <cmath>
float P(float PV, float r, int t){
return(r * PV/1-pow((1+r),-t));
}
int main(void){
float PV = 100000;
float r = .005;
int t = 350;
std::cout << "A loan valued at $" << PV << " at a rate of %" << r << " with a payment period of " << t << "months would be $" << P(PV,r,t) << ", per-payment.\n";
return 0;
}
When I run it P(PV,r,t) comes out as 499.834 it should be 500. Though if I set r = 0.06 P is correct and comes out as P = 6000.
Maybe it's a compiler error. I'm using gcc version 2.95.3-haiku-121101.

The code:
return(r * PV/1-pow((1+r),-t));
should be:
return(r * PV/(1-pow((1+r),-t)));
and the expected result is about 605.718, not 500.

Related

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.

Specific right-angled Triangles are not being recognized as right-angled in Cpp

I have to take the coordinates of the vertices of a triangle from the user and tell if it is a right-angled triangle or not. I'm using Pythagoras Theorem to Find out i.e. h * h = b * b + p * p
But surprisingly this doesn't work for some specific right-angled triangles.
Here is one such Triangle:
Vertex A: (x, y) = (1, 3)
Vertex B: (x, y) = (1, 1)
Vertex C: (x, y) = (5, 1)
It calculates perfectly, which I figured out by printing the calculation, but still doesn't work.
Then I tried by using sqrt() function from the cmath library this way:
h = sqrt(b * b + p * p)
Logically it is the same, but it worked.
I want to understand, why the earlier method is not working?
Here is a simplified version of My Code:
#include <iostream>
#include <cmath>
using namespace std;
class Vertex {
double x, y;
public:
void take_input(char obj) {
cout << endl << " Taking Coordinates of Vertex " << obj << ": " << endl;
cout << " Enter the x component: ";
cin >> x;
cout << " Enter the y component: ";
cin >> y;
}
double distance(Vertex p) {
double dist = sqrt((x-p.x)*(x-p.x) + (y-p.y)*(y-p.y));
return dist;
}
};
class Triangle {
Vertex a, b, c;
public:
void take_inp(string obj) {
cout << endl << "Taking Vertices of the Triangle " << obj << ": " << endl;
cout << " Verteces should be in a counter clockwise order (as per convention)." << endl;
a.take_input('A');
b.take_input('B');
c.take_input('C');
}
void is_rt_ang() {
double h = a.distance(c)*a.distance(c);
double bp = a.distance(b)*a.distance(b) + b.distance(c)*b.distance(c);
/*
// Strangely this attempt works which is logically the same:
double h = a.distance(c);
double bp = sqrt(a.distance(b)*a.distance(b) + b.distance(c)*b.distance(c));
*/
if (h == bp) {
cout << "Angle is 90" << endl;
cout << h << " = " << bp << endl;
cout << "It is Right-Angled" << endl;
}
else {
cout << "Angle is not 90!" << endl;
cout << h << " != " << bp << endl;
cout << "It is Not a Right-Angled" << endl;
}
}
};
int main()
{
Triangle tri1, tri2;
tri1.take_inp("tri1");
tri1.is_rt_ang();
return 0;
}
The line
double dist = sqrt((x-p.x)*(x-p.x) + (y-p.y)*(y-p.y));
in the Vertex::distance method gives you an approximation of a square root which is rarely going to coincide with an exact answer. This is because most real numbers can't be represented in floating point arithmetic.
But in given code sample you can make do without sqrt. Replace Vertex::distance method with a method
double distance_square(Vertex p) {
double dist_square = (x-p.x)*(x-p.x) + (y-p.y)*(y-p.y);
return dist_square;
}
and call it like this in Triangle::is_rt_ang:
double h = a.distance_square(c);
double bp = a.distance_square(b) + b.distance_square(c);
This solution is still flawed because floating-point multiplication is also a subject to rounding errors. But if it is guaranteed that you are going to work only with integer coordinates, you can replace all doubles in your code with ints and for them there is no problem with multiplication (besides possibly going out of bounds for large numbers).
EDIT: Also a comment on printing
It calculates perfectly, which I figured out by printing the
calculation, but still doesn't work.
When you print doubles you need to set precision manually in order to avoid rounding. If in your code I replace a line
cout << h << " != " << bp << endl;
with
cout << std::setprecision(std::numeric_limits<double>::digits10) << std::fixed << h << " != " << bp << endl;
then for example triangle from the question I get the output
Angle is not 90!
20.000000000000004 != 20.000000000000000
It is Not a Right-Angled
For this to compile you will need to add #include <limits> and #include <iomanip>.
In your is_rt_ang function you're assuming that your hypotenuse is always going to be the edge AC, but it doesn't seem like you're doing anything to verify this.
double h = a.distance(c)*a.distance(c);
double bp = a.distance(b)*a.distance(b) + b.distance(c)*b.distance(c);
You could try getting the squares of all your distances first, (AC)^2, (AB)^2, and (BC)^2, then finding the candidate for hypotenuse by taking the max value out of the three, then do something like:
bool isRightTriangle = max == (min1 + min2)
You may also be running into some kind of round-off error with floating point numbers. It is common to use a an epsilon value when comparing floating point numbers because of the inherent round-off errors with them. If you don't need floating point values maybe use an integer, or if you do need floating point values try using an epsilon value in your equalities like:
abs(h - bp) <= epsilon
You should be able to find more information about floating point values, round-off errors, and machine epsilons on the web.
Here is a link to a SO Q/A that talks about floating point math that may be a good resource for you: Is floating point math broken?

How to get Real value precision in C++ Same as Fortran (Pararel Studio XE Compiler)

I have an almost large Fortran 77 code which I'm trying to write it in c++.
the Fortran code has too many math formulas and i have to get same parameter value in c++.
I have a code like this in Fortran :
implicit real*8 (a-h,o-z)
real *8 test
test=3.14159**2
print *,test
And output is : 9.86958772810000
In the c++ code (i use pow for just a sample i have this problem in every math formula):
// 1st Try
double test=pow(3.14159,2);
cout <<std::setprecision(std::numeric_limits<double>::digits10 + 1) <<fixed <<test;
And output is : 9.86958885192871
I know that i can specify the kind of a f-p number by suffixing the kind-selector like this (but it's for fortran i need to get same value in c++
0:
real test=3.14159_8**2
As is described in this question Different precision in C++ and Fortran
i also tried this in c++ and the output was :
// 2nd Try as users suggested in the comments
float test2 = pow(3.14159, 2);
the output 9.8695878982543945
and if i try :
// 3rd Try as users suggested in the comments
float test2 = pow(3.14159f, 2);
output will be : 9.8695888519287109
which still has differences.
** I need to get same value in c++ not Fortran** because the Fortran project uses this parameter all over the project and i have to get same output.
So is there anyway i get same Float/Double precision in c++?
For Fortran i use Pararel Studio XE Compiler 2017
For c++ Visual Studio 2017
Any help would be appreciated.(thank you all for helping).
as Kerndog73 Asked i tried
std::numeric_limits<double>::digits // value is 53
std::numeric_limits<double>::is_iec559 //value is 1
P.S: More Detail
It's one part of my original FORTRAN code, as you can see i need to have all 10 precision in c++ to get same values (this code draws a shape in a text file at the end of the code, and my c++ code is not similar to that shape because precision values are not the same):
// in the last loop i have a value like this 9292780397998.33
// all precision have used
dp=p2-p1
dr=(r2-r1)/(real(gx-1))
dfi=2*3.14159*zr/(real(gy-1))
test=3.14159**2
print *,test
r11=r1
print *,'dp , dr , dfi'
print *,dp,dr,dfi
do 11 i=1,gx
r(i)=r11
st(i)=dr*r(i)*dfi
r11=r11+dr
print *, r11,r(i),st(i)
11 continue
dh=h02-h01
do 1 i=1,gx
do 2 j=1,gy
h0=h01+dh*(r(i)-r1)/(r2-r1)
hkk=hk(i,j)
if (hkk.eq.10) then
hk(i,j)=hkkk
end if
h00=h0+hk(i,j)
h(i,j)=h00/1000000.
!print *, i,j, h(i,j)
!print*, h(i,j)
2 continue
1 continue
!
! write(30,501) ' '
do 12 i=1,gx
do 22 j=1,gy
h3=h(i,j)**3
h3r(i,j)=h3*r(i)
h3ur(i,j)=h3/r(i)
!print *,i,j, h3ur(i,j)
p0(i,j)=p1+dp*(r(i)-r1)/(r2-r1)
!print *,i,j, p0(i,j)
22 continue
12 continue
drfi=dr/(dfi*48*zmu)
dfir=dfi/(dr*48*zmu)
omr=om*dr/8.
print *,'drfi,dfir,omr,zmu'
print *,drfi,dfir,omr,zmu
!p1 = 10000
!do 100 k=1,giter
do 32 i=1,gx
do 42 j=1,gy
if (i.eq.1) then
pp(i,j)=p1**2
goto 242
end if
if (i.eq.gx) then
pp(i,j)=p2**2
goto 242
end if
if (j.eq.1.) then
temp1=drfi*(2*h3ur(i,1)+h3ur(i,(gy-1))+h3ur(i,2))
a=drfi*(2*h3ur(i,1)+h3ur(i,(gy-1))+h3ur(i,2))+
& dfir*(2*h3r(i,1)+h3r(i-1,1)+h3r(i+1,1))
& -omr*r(i)*(h(i,(gy-1))-h(i,2))/p0(i,1)
b=drfi*(h3ur(i,1)+h3ur(i,(gy-1)))+
& omr*r(i)*(h(i,(gy-1))+h(i,1))/p0(i,(gy-1))
c=drfi*(h3ur(i,1)+h3ur(i,2))-
& omr*r(i)*(h(i,1)+h(i,2))/p0(i,2)
d=dfir*(h3r(i,1)+h3r(i-1,1))
e=dfir*(h3r(i,1)+h3r(i+1,1))
pp(i,j)=(b*p0(i,(gy-1))**2+c*p0(i,2)**2+
& d*p0(i-1,1)**2+e*p0(i+1,1)**2)/a
goto 242
end if
if (j.eq.gy) then
a=drfi*(2*h3ur(i,gy)+h3ur(i,(gy-1))+h3ur(i,2))+
& dfir*(2*h3r(i,gy)+h3r(i-1,gy)+h3r(i+1,gy))
& -omr*r(i)*(h(i,(gy-1))-h(i,2))/p0(i,gy)
b=drfi*(h3ur(i,gy)+h3ur(i,(gy-1)))+
& omr*r(i)*(h(i,(gy-1))+h(i,gy))/p0(i,(gy-1))
c=drfi*(h3ur(i,gy)+h3ur(i,2))-
& omr*r(i)*(h(i,gy)+h(i,2))/p0(i,2)
d=dfir*(h3r(i,gy)+h3r(i-1,gy))
e=dfir*(h3r(i,gy)+h3r(i+1,gy))
pp(i,j)=(b*p0(i,(gy-1))**2+c*p0(i,2)**2+
& d*p0(i-1,gy)**2+e*p0(i+1,gy)**2)/a
goto 242
end if
a=drfi*(2*h3ur(i,j)+h3ur(i,j-1)+h3ur(i,j+1))+
& dfir*(2*h3r(i,j)+h3r(i-1,j)+h3r(i+1,j))
& -omr*r(i)*(h(i,j-1)-h(i,j+1))/p0(i,j)
b=drfi*(h3ur(i,j)+h3ur(i,j-1))+
& omr*r(i)*(h(i,j-1)+h(i,j))/p0(i,j-1)
c=drfi*(h3ur(i,j)+h3ur(i,j+1))-
& omr*r(i)*(h(i,j)+h(i,j+1))/p0(i,j+1)
d=dfir*(h3r(i,j)+h3r(i-1,j))
e=dfir*(h3r(i,j)+h3r(i+1,j))
pp(i,j)=(b*p0(i,j-1)**2+c*p0(i,j+1)**2+
& d*p0(i-1,j)**2+e*p0(i+1,j)**2)/a
242 continue
ppp=pp(i,j)
print *,ppp
pneu=sqrt(ppp)
palt=p0(i,j)
p0(i,j)=palt+(pneu-palt)/2.
!print *,p0(i,j)
wt(i,j)=zmu*om*om*((r(i)+dr)**2+r(i)**2)/(2*h(i,j))
!print *,r(i)
p00(i,j)=p0(i,j)/100000.
!print *, p00(i,j)
42 continue
32 continue
I wrote a program to output all possible results in the 3 formats, with casting done to each type at the various possible times:
#include <cmath>
#include <iomanip>
#include <iostream>
#include <limits>
// use `volatile` extensively to inhibit "float store" optimizations
template<class T>
void pp(volatile T val)
{
const size_t prec = std::numeric_limits<T>::digits10 + 1;
std::cout << std::setprecision(prec);
std::cout << std::left;
std::cout << std::setfill('0');
std::cout << std::setw(prec+2) << val;
}
int main()
{
using L = long double;
using D = double;
using F = float;
volatile L lp = 3.14159l;
volatile D dp = 3.14159;
volatile F fp = 3.14159f;
volatile L lpl = lp;
volatile D dpl = lp;
volatile F fpl = lp;
volatile L lpd = dp;
volatile D dpd = dp;
volatile F fpd = dp;
volatile L lpf = fp;
volatile D dpf = fp;
volatile F fpf = fp;
volatile L lpl2 = powl(lpl, 2);
volatile D dpl2 = pow(dpl, 2);
volatile F fpl2 = powf(fpl, 2);
volatile L lpd2 = powl(lpd, 2);
volatile D dpd2 = pow(dpd, 2);
volatile F fpd2 = powf(fpd, 2);
volatile L lpf2 = powl(lpf, 2);
volatile D dpf2 = pow(dpf, 2);
volatile F fpf2 = powf(fpf, 2);
std::cout << "lpl2: "; pp((L)lpl2); std::cout << " "; pp((D)lpl2); std::cout << " "; pp((F)lpl2); std::cout << '\n';
std::cout << "dpl2: "; pp((L)dpl2); std::cout << " "; pp((D)dpl2); std::cout << " "; pp((F)dpl2); std::cout << '\n';
std::cout << "fpl2: "; pp((L)fpl2); std::cout << " "; pp((D)fpl2); std::cout << " "; pp((F)fpl2); std::cout << '\n';
std::cout << "lpd2: "; pp((L)lpd2); std::cout << " "; pp((D)lpd2); std::cout << " "; pp((F)lpd2); std::cout << '\n';
std::cout << "dpd2: "; pp((L)dpd2); std::cout << " "; pp((D)dpd2); std::cout << " "; pp((F)dpd2); std::cout << '\n';
std::cout << "fpd2: "; pp((L)fpd2); std::cout << " "; pp((D)fpd2); std::cout << " "; pp((F)fpd2); std::cout << '\n';
std::cout << "lpf2: "; pp((L)lpf2); std::cout << " "; pp((D)lpf2); std::cout << " "; pp((F)lpf2); std::cout << '\n';
std::cout << "dpf2: "; pp((L)dpf2); std::cout << " "; pp((D)dpf2); std::cout << " "; pp((F)dpf2); std::cout << '\n';
std::cout << "fpf2: "; pp((L)fpf2); std::cout << " "; pp((D)fpf2); std::cout << " "; pp((F)fpf2); std::cout << '\n';
return 0;
}
On my Linux system, this outputs:
long double double float
lpl2: 9.869587728100000000 9.869587728100001 9.869588
dpl2: 9.869587728099999069 9.869587728099999 9.869588
fpl2: 9.869588851928710938 9.869588851928711 9.869589
lpd2: 9.869587728099999262 9.869587728099999 9.869588
dpd2: 9.869587728099999069 9.869587728099999 9.869588
fpd2: 9.869588851928710938 9.869588851928711 9.869589
lpf2: 9.869588472080067731 9.869588472080068 9.869589
dpf2: 9.869588472080067731 9.869588472080068 9.869589
fpf2: 9.869588851928710938 9.869588851928711 9.869589
Base on this, it's possible that you're showing too few digits but Intel's 80-bit format, which is long double on Linux (and, I believe, most x86 OSes), but normally unavailable on Windows.
It's also possible that you're using decimal floats.
But it's also possible your Fortran runtime was just plain broken, many float<->string libraries can generously be described as COMPLETE AND UTTER CRAP.
It's a good habit to use hexadecimal float I/O for reliability.
Use a multiprecision arithmetic library for C++ that gives you more control over the format of numeric values than float, double, etc. in C++.
For example, using Boost.Multiprecision the following code
#include <iostream>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <iomanip>
int main() {
using number = boost::multiprecision::number<boost::multiprecision::cpp_dec_float<8>>;
number pi_five_sig_digits{ 3.14159 };
number value = boost::multiprecision::pow(pi_five_sig_digits, number(2));
std::cout << "3.14159 ** 2 = " << std::setprecision(15) << value << std::endl;
return 0;
}
yields
3.14159 ** 2 = 9.8695877281
The way that can work in cout until now is what #kerndog73 suggested.(thank you so much)
but my poblem would not solve with cout
#include <cmath>
#include <iomanip>
#include <iostream>
constexpr int prec = std::numeric_limits<double>::digits10 - 1;
int main() {
const double testD = std::pow(3.14159, 2.0);
const float testF = std::pow(3.14159f, 2.0f);
std::cout << "Double: " << std::setprecision(prec) << std::fixed << testD << '\n';
std::cout << "Float: " << std::setprecision(prec) << std::fixed << testF << '\n';
}
and outputs are :
Double
9.86958772810000 // exactly same as FORTRAN 77 output
Float
9.86958885192871

int and double operations in C++

I am trying to convert latitude and longitude locations from degrees, minutes, seconds to a decimal degree number. However, when I try to do this in C++ it rounds the numbers off and doesn't give the decimal form. I think this is because of the double and int mixed operations but I can't seem to find the problem. I have included my code below. Any help would be greatly appreciated.
#include <iomanip>
#include <cmath>
#include <iostream>
#include <string>
using namespace std;
int main()
{
int user_degrees_latitude, user_minutes_latitude, user_seconds_latitude, user_degrees_longitude, user_minutes_longitude, user_seconds_longitude;
double total_minutes_latitude, total_degrees_latitude, total_minutes_longitude, total_degrees_longitude;
const double sixtieth = (1/60);
cout<< "Input latitude in degrees, minutes, seconds:";
cin >> user_degrees_latitude >> user_minutes_latitude >> user_seconds_latitude;
cout << "Input longitude in degrees, minutes, seconds:";
cin >> user_degrees_longitude >> user_minutes_longitude >> user_seconds_longitude;
total_minutes_latitude = (user_minutes_latitude + (((sixtieth)*user_seconds_latitude));
total_degrees_latitude = (abs(user_degrees_latitude) + ((sixtieth)*total_minutes_latitude));
total_minutes_longitude = (user_minutes_longitude + ((sixtieth)*user_seconds_longitude));
total_degrees_longitude = (abs(user_degrees_longitude) + ((sixtieth)*total_minutes_longitude));
cout << user_degrees_latitude << " deg " << user_minutes_latitude << "\' " << user_seconds_latitude << "\" latitude, " << user_degrees_longitude << " deg " << user_minutes_longitude << "\' " << user_seconds_longitude << "\"";
cout << " is (" << total_degrees_latitude << "," << total_degrees_longitude << ")"<<endl;
return 0;
}
1/60 is integer division, which rounds toward zero. That means your sixtieth variable is 0. You may be doing integer division in other places, too. If you want your division to be floating-point, make sure at least one argument is floating-point.
I haven't looked through all the code, but this is wrong:
const double sixtieth = (1/60);
1/60 is 0, always. This is not a mixed operation, it is integer only. You should write:
const double sixtieth = (1.0/60);
Could also do the job:
const double sixtieth = (double)1/60;
Or preferred in C++
const double sixtieth = static_cast<double>(1)/60;
const double sixtieth = 1.0/60; Is preferred here though as your are working with rvalues.
You would need double or static_cast in case of lvalues:
int numerator = 1;
int denominator = 60;
const double sixtieth = (double) numerator/denominator;
const double sixtieth = static_cast<double>(numerator)/denominator;

Convert radians to degrees like Google

Im trying to convert radians to degrees, but im not getting the same results as google
calculator and the Pi i defined dosent output all number.
If you type in google search: (1 * 180) / 3.14159265 then you get 57.2957796, but my program is
outputting: 57.2958 and if you type in google search Pi you get: 3.14159265, but mine
dosent output the rest, it output: 3.14159
My code is:
#include <iostream>
#define SHOW(X) cout << # X " = " << (X) << endl
using namespace std;
double Pi_test = 3.14159265;
float radian_to_degree(double ENTER) {
double Pi = 3.14159265;
float degrees = (ENTER * 180) / Pi;
return degrees;
}
int main (int argc, char * const argv[]) {
SHOW( radian_to_degree(1) ); // 57.2958 not 57.2957795 like google, why?
SHOW( Pi_test ); // output 3.14159' not 3.14159265, why?
return 0;
}
Please help me fix this, what wrong? any example?
You need to change the default precision:
cout.precision(15);
cout << d << endl;
As stated here, it may be that cout in C++ is rounding your number before displaying it. Try this:
#define SHOW(X) cout << setprecision(some_number) << # X " = " << (X) << endl
Change radian_to_degree to operate on double not float, since double has more precision.
Output the result using std::setprecision
#include <iomanip>
std::cout << std::setprecision(9) << result << "\n";
Even after you change cout's precision, note that double only contains so much data; if you expect your program to spit out 1000 decimal places, a double is not going to give you that much. You'd have to create a data type of your own.
Also, don't define macro functions unless you have to.