I'm writing a program that is using the functions sin() and cos() from the math.h library. However, I noticed I was getting funky results. After searching around and checking my math multiple times, I decided to do a simple check with this:
int main()
{
cout << "sin(45.0) = " << sin(45) << endl;
cout << "cos(45.0) = " << cos(45) << endl;
return 0;
}
And I get this output:
sin(45) = 0.850904
cos(45) = 0.525322
These should be equal right? Is there something special about the math.h library? Am I doing something wrong?
Here are the equations in WolframAlpha:
sin(45)
cos(45)
You should use cmath in C++, rather than the old C header.
std::sin() and std::cos() both take a floating point value representing an angle in radian.
The GCC version of this file includes a handy constant for π, (which does not exist in the C++ standard but) which will make it easier for you to convert degrees to radian:
#include <cmath>
#include <iostream>
double degrees_to_radian(double deg)
{
return deg * M_PI / 180.0;
}
int main()
{
std::cout << "sin(45.0) = " << std::sin(degrees_to_radian(45)) << std::endl;
std::cout << "cos(45.0) = " << std::cos(degrees_to_radian(45)) << std::endl;
}
See it run!
sin and cos expect input in radians not degrees.
try this:
sin(degrees * pi / 180)
Trigonometric functions use radians, not degrees.
sin() and cos() treat your parameter as Radians not Degrees.
Its strange because I cannot get 0 when using cos(1.5707963267948966) which is the radian value for 90 degrees.
long double degrees = 90.0;
long double radians = glm::radians(degrees);
long double result = cos(radians);
The result is equal to 6.1232339957367660e-017 - not kidding.
glm is calculating radians correctly as well, checked it against google.
I used long doubles to make sure it wasn't somehow rounding problems but its not. Just thought this info might help somehow
Related
So I am doing a C++ question about sine.
It says that sin x can be approximated via the polynomial x-(x^3/6)+(x^5/120)-(x^7/5040), and it tells me to output both the approximated sin value and the sin value calculated via cmath.
The input is in degrees, and we have to first convert it to radians then find out sin.
Sample run (only 45 is the input, other our output):
Angle: 45
approxSin = 0.70710647
cmath sin = 0.70710678
I have attempted to write a code for this. When I pressed command+R, nothing happens despite the program saying "build successful". I am new to Xcode, so I am not sure whether I used Xcode incorrectly or I wrote the program incorrectly. Can anyone help?
#define _USE_MATH_DEFINES
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
double approxSin(double angleDeg) {
if (-180<angleDeg<180) return approxSin(angleDeg-(angleDeg*angleDeg*angleDeg)/6+(angleDeg*angleDeg*angleDeg*angleDeg*angleDeg)/120-(angleDeg*angleDeg*angleDeg*angleDeg*angleDeg*angleDeg*angleDeg)/5040);
}
int main(){
float angleDeg;
cin >> angleDeg;
if (angleDeg>180) {
while (angleDeg>180) {
angleDeg = angleDeg-360;
}
} else if (angleDeg<-180) {
while (angleDeg<-180) {
angleDeg = angleDeg+360;
}
}
cout << "approxSin = " << &approxSin << endl;
cout << "cmath sin = " << setprecision(8) << sin(angleDeg);
return 0;
}
my code
My guess about your problem: You run the program, and it patiently waits for your input.
With
cin >> angleDeg;
your program seemingly halts, while it's waiting for you to give some input in the IDE console window. Since you haven't written any prompt there's no output to tell you it's waiting for input.
I suggest you add some output first to ask for the input:
cout << "Please enter angle in degrees: ";
cin >> angleDeg;
When I pressed command+R, nothing happens despite the program saying "build successful".
I guess that the answer by Some programmer dude should solve this issue, but, as noted in the comments, there are much worse problems in the posted code, probably depending by a misunderstanding of how functions should be declared and called in C++.
Consider this:
double approxSin(double angleDeg) {
if (-180<angleDeg<180) return approxSin(/* Some unreadable expression */);
}
It's enough to generate a couple of warning:
prog.cc:7:22: warning: result of comparison of constant 180 with expression of type 'bool'
is always true [-Wtautological-constant-out-of-range-compare]
if (-180<angleDeg<180) return approxSin(angleDeg-(...));
~~~~~~~~~~~~~^~~~
prog.cc:6:35: warning: all paths through this function will call itself [-Winfinite-recursion]
double approxSin(double angleDeg) {
^
The relational operators are evaluated left-to-right, so that an expressions like -180<angleDeg<180 is read by the compiler as (-180 < angleDeg) < 180. The result of -180 < angleDeg is a bool which leads to the kind warning by the compiler about that expression beeing always true.
It could be written as -180 < angle && angle < 180, but given the OP's assignment, the angle should be tested against plus or minus pi. Also, the alternative branch should be written as well.
The second warning is about the recursive call of the function, which makes no sense, without any alternative path. I can only guess that the OP has misinterpreted how values are returned from a function.
The polynomial itself could be evaluated in a more readable way using std::pow or applying Horner's method. I'll show an example later.
The other big problem (specular, someway) is in the "call" site, which isn't a call at all:
cout << "approxSin = " << &approxSin << endl;
It ends up printing 1 and the reasons can be found in this Q&A: How to print function pointers with cout?
Last, I'd note that while the assignment specifically requires to convert the inputted angle from degrees to radians (as the argument of std::sin is), the posted code only checks the range in degrees, without any conversion.
The following implementation compares different methods for evaluating the sin() function
#define _USE_MATH_DEFINES
#include <iostream>
#include <iomanip>
#include <cmath>
namespace my {
// M_PI while widespread, isn't part of the ISO standard
#ifndef M_PI
constexpr double pi = 3.141592653589793115997963468544185161590576171875;
#else
constexpr double pi = M_PI;
#endif
constexpr double radians_from_degrees(double degrees)
{
return degrees * pi / 180.0;
}
constexpr double convert_angle_to_plus_minus_pi(double angle)
{
while ( angle < -pi )
angle += 2.0 * pi;
while ( angle > pi ) {
angle -= 2.0 * pi;
}
return angle;
}
// Approximates sin(angle), with angle between [-pi, pi], using a polynomial
// Evaluate the polynomial using Horner's method
constexpr double sin_a(double angle)
{
// A radian is passed, but the approximation is good only in [-pi, pi]
angle = convert_angle_to_plus_minus_pi(angle);
// Evaluates p(a) = a - a^3 / 6 + a^5 / 120 - a^7 / 5040
double sq_angle = angle * angle;
return angle * ( 1.0 + sq_angle * (-1.0/6.0 + sq_angle * ( 1.0/120.0 - sq_angle / 5040.0)));
}
double sin_b(double angle) {
angle = convert_angle_to_plus_minus_pi(angle);
return angle - pow(angle, 3) / 6.0 + pow(angle, 5) / 120.0 - pow(angle, 7) / 5040.0;
}
} // End of namespace 'my'
int main()
{
std::cout << " angle std::sin my::sin_a my::sin_b\n"
<< "-----------------------------------------------\n"
<< std::setprecision(8) << std::fixed;
for (int i = -90; i < 475; i += 15)
{
double angle = my::radians_from_degrees(i);
std::cout << std::setw(5) << i
<< std::setw(14) << std::sin(angle)
<< std::setw(14) << my::sin_a(angle)
<< std::setw(14) << my::sin_b(angle) << '\n';
}
return 0;
}
Given a float, I want to round the result to 4 decimal places using half-even rounding, i.e., rounding to the next even number method. For example, when I have the following code snippet:
#include <iostream>
#include <iomanip>
int main(){
float x = 70.04535;
std::cout << std::fixed << std::setprecision(4) << x << std::endl;
}
The output is 70.0453, but I want to be 70.0454. I could not find anything in the standard library, is there any function to achieve this? If not, what would a custom function look like?
If you use float, you're kind of screwed here. There is no such value as 70.04535, because it's not representable in IEEE 754 binary floating point.
Easy demonstration with Python's decimal.Decimal class, which will try to reproduce the actual float (well, Python float is a C double, but it's the same principle) value out to 30 digits of precision:
>>> import decimal
>>> decimal.Decimal(70.04535)
Decimal('70.0453499999999991132426657713949680328369140625')
So your actual value doesn't end in a 5, it ends in 49999... (the closest to 70.04535 a C double can get; C float is even less precise); even banker's rounding would round it down. If this is important to your program, you need to use an equivalent C or C++ library that matches "human" (base-10) math expectations, e.g. libmpdec (which is what Python's decimal.Decimal uses under the hood).
I'm sure someone can improve this, but it gets the job done.
double round_p( double x, int p ){
double d = std::pow(10,p+1);
return ((x*d)+5)/d;
}
void main(int argc, const char**argv){
double x = 70.04535;
{
std::cout << "value " << x << " rounded " << round_p(x,4) << std::endl;
std::cout << "CHECK " << (bool)(round_p(x,4) == 70.0454) << std::endl;
}
}
This is not a question about template hacks or dealing with compiler quirks. I understand why the Boost libraries are the way they are. This is about the actual algorithm used for the sinc_pi function in the Boost math library.
The function sinc(x) is equivalent to sin(x)/x.
In the documentation for the Boost math library's sinc_pi(), it says "Taylor series are used at the origin to ensure accuracy". This seems nonsensical since division of floating point numbers will not cause any more loss of precision than a multiplication would. Unless there's a bug in a particular implementation of sin, the naive approach of
double sinc(double x) {if(x == 0) return 1; else return sin(x)/x;}
seems like it would be fine.
I've tested this, and the maximum relative difference between the naive version and the one in the Boost math toolkit is only about half the epsilon for the type used, for both float and double, which puts it at the same scale as a discretization error. Furthermore, this maximum difference does not occur near 0, but near the end of the interval where the Boost version uses a partial Taylor series (i.e. abs(x) < epsilon**(1/4)). This makes it look like it is actually the Taylor series approximation which is (very slightly) wrong, either through loss of accuracy near the ends of the interval or through the repeated rounding from multiple operations.
Here are the results of the program I wrote to test this, which iterates through every float between 0 and 1 and calculates the relative difference between the Boost result and the naive one:
Test for type float:
Max deviation from Boost result is 5.96081e-08 relative difference
equals 0.500029 * epsilon
at x = 0.0185723
which is epsilon ** 0.25003
And here is the code for the program. It can be used to perform the same test for any floating-point type, and takes about a minute to run.
#include <cmath>
#include <iostream>
#include "boost/math/special_functions/sinc.hpp"
template <class T>
T sinc_naive(T x) { using namespace std; if (x == 0) return 1; else return sin(x) / x; }
template <class T>
void run_sinc_test()
{
using namespace std;
T eps = std::numeric_limits<T>::epsilon();
T max_rel_err = 0;
T x_at_max_rel_err = 0;
for (T x = 0; x < 1; x = nextafter(static_cast<float>(x), 1.0f))
{
T boost_result = boost::math::sinc_pi(x);
T naive_result = sinc_naive(x);
if (boost_result != naive_result)
{
T rel_err = abs(boost_result - naive_result) / boost_result;
if (rel_err > max_rel_err)
{
max_rel_err = rel_err;
x_at_max_rel_err = x;
}
}
}
cout << "Max deviation from Boost result is " << max_rel_err << " relative difference" << endl;
cout << "equals " << max_rel_err / eps << " * epsilon" << endl;
cout << "at x = " << x_at_max_rel_err << endl;
cout << "which is epsilon ** " << log(x_at_max_rel_err) / log(eps) << endl;
cout << endl;
}
int main()
{
using namespace std;
cout << "Test for type float:" << endl << endl;
run_sinc_test<float>();
cout << endl;
cin.ignore();
}
After some sleuthing, I dug up a discussion from the original authors.
[sin(x)] is well behaved at x=0, and so is sinc(x). […] my solution
will have better performance or small argument, i.e.|x| < pow(x, 1/6),
since most processor need much more time to evaluate sin(x) than
1- (1/6) * x *x.
From https://lists.boost.org/Archives/boost/2001/05/12421.php.
The earliest reference I found to using Taylor expansion to ensure accuracy is from much later, and committed by a different person. So it seems like this is about performance, not accuracy. If you want to make sure, you might want to get in touch with the people involved.
Regarding sinc_pi specifically, I found the following exchange. Note that they use sinc_a to refer to the family of functions of the form sin(x*a)/(x*a).
What is the advatage of sinc_a(x) ? To address rounding problems for very
large x ? Then it would be more important to improve sin(x) for very large
arguments.
The main interest of this particular member of the family is that it requires fewer computations, and that, in itself it
is a special function as it is far more common than its brethren.
From https://lists.boost.org/Archives/boost/2001/05/12485.php.
I am novice at programming in C++. I want to write a program using while loop which displays the trigonometric table for sin, cos and Tan. It takes angles in degrees with a difference of 5 and displays the result. This it what I tried,
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
int main()
{
int num;
cout<< "Angle Sin Cos Tan"<<endl;
cout<< "..........................."<<endl;
num=0;
while (num<=360)
{
cout <<setw(3)<<num<<" "
<<setw(3)<<setprecision(3)<<sin(num)<<" "
<<setw(3)<<setprecision(3)<<cos(num)<<" "
<<setw(5)<<setprecision(3)<<tan(num)<<endl;
num=num+5;
}
}
Unfortunately, I could not change radians into degrees in while loop and the display does not look promising even for radians. How can I resolve it ?
To convert degrees to radiant you have to multiply by pi and to divide by 180.0:
#define M_PI 3.14159265358979323846
int num = 0;
while (num<=360)
{
double numRad = num * M_PI/180.0;
std::cout <<std::setw(3)<<num<<" "
<<std::setprecision(3)<<std::fixed
<<std::setw(6)<< std::sin( numRad ) <<" "
<<std::setw(6)<< std::cos( numRad ) <<" ";
if ( num != 90 && num != 270 )
std::cout<<std::setw(6)<< std::tan( numRad ) <<std::endl;
else
std::cout<< "infinitely" <<std::endl;
num=num+5;
}
To use constant M_PI see How to use the PI constant in C++
To convert degrees to radians, use numRad = M_PI / 180.0 where M_PI should be a constant that holds the value od Pi. If you do not have such a constant defined in a header file, just define it yourself, like #define PI 3.14159265
The functions sin, cos and tan always require arguments in radians.
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.