0

im making this game and i encountered a problem. Well the game is basically two players come up, and the computer will ask you questions in this format:

What is the [sin/cos/tan] of [number] [degrees/radians]

Well right now im almost done with radians but for some reason the tangent decides to screw up... When i was checking for bugs, it told me the tan(pi) was -1.22465e-16 ...??? What tan(pi) is actually 0. It also told me the same in cpp.sh : http://cpp.sh/6m5q3 .. My Code for the game in the dictonary class source file is:

#include<vector>
#include "../Header Files/Dictonary.h"

#ifndef PI
    #define PI 3.14159265358979323846  
#endif    

Dictonary::Dictonary()
{
}

int myRand(int low, int high) 
{
   return rand() % (high - low + 1) + low;
}


string Dictonary::randomArray(const string &opt)
{
    short ran = myRand(0,16);
    if(opt.compare("degree") == 0)
        return ( (arrayPossibledegrees[ran]) );
    else
        return ( (arrayPossibleRandians[ran]) );
}

string Dictonary::radOrDegRAND()
{
    return(radDeg[myRand(0,1)]);
}

string Dictonary::getPossibleArethemtic()
{
    return(possibleArethemtic[myRand(0,2)]);
}


double Dictonary::getComputedValue()
{
    string unit = this -> radOrDegRAND();
    string arethemtic = this -> getPossibleArethemtic();
    string userAnswer;
    double userAnwserDoub, AIANWSERDOUB;
    //Ex; pi/2
    string val = randomArray(unit);
    cout << "\n\nWhat is the " << arethemtic <<  " Of " <<val << " " << unit << endl;
    std::cin >> userAnswer;

    checkUserAnwser(userAnswer,userAnwserDoub);


    //VALUE
    if(unit == "radian")
    {
        checkVAL(val,AIANWSERDOUB);
        if(arethemtic.compare("sin") == 0)
        {
             cout << "USER ANWSER : " << userAnwserDoub << endl;
             cout << "The Sin of " << AIANWSERDOUB <<  "Is " << sin(AIANWSERDOUB) << endl;
        }

        else if(arethemtic.compare("cos") == 0)
        {
            cout << "USER ANWSER : " << userAnwserDoub << endl;
            cout << "The Cos of " << AIANWSERDOUB << " Is " << cos(AIANWSERDOUB) << endl;
        }
        else
        {
            cout << "USER ANWSER : " << userAnwserDoub << endl;
            cout << "The Tan of " << AIANWSERDOUB  << " Is " << tan(AIANWSERDOUB) << endl;
        }

    }
}

double Dictonary::conversionPItoREAL(string piNONREAL)
{
    short PIREAL;
    //Conversion "pi/2" to PI/2 MATH FORM
    //"11pi/2" to 11PI/2
    //"3pi/2" to 3PI/2
    if(piNONREAL.find("p"))
    {

    }
}

//Check Anwser
void Dictonary::checkUserAnwser(string &userAnswer, double &userAnwserDoub)
{
    if(userAnswer.compare("s(3)/2"))
        userAnwserDoub = (sqrt(3)/2);
    else if(userAnswer.compare("-s(3)/2"))
        userAnwserDoub = (-(sqrt(3)/2));
    else if(userAnswer.compare("s(2)/2"))
        userAnwserDoub = (sqrt(2)/2);
    else if(userAnswer.compare("-s(2)/2"))  
        userAnwserDoub = (-(sqrt(2)/2));
    else if(userAnswer.compare("-1/2"))
        userAnwserDoub = ((-1)/2);
    else if(userAnswer.compare("1/2"))
        userAnwserDoub = (1/2);
    else if(userAnswer.compare("0"))
        userAnwserDoub = (0);
    else if(userAnswer.compare("-1"))
        userAnwserDoub = (-1);
    else if(userAnswer.compare("1"))
        userAnwserDoub = (1);
    else if(userAnswer.compare("s(3)"))
        userAnwserDoub = (sqrt(3));
    else if(userAnswer.compare("-s(3)"))
        userAnwserDoub = (-(sqrt(3)));
    else if(userAnswer.compare("-s(3)/3"))
        userAnwserDoub = (-((sqrt(3))/3));
    else if(userAnswer.compare("s(3)/3"))
        userAnwserDoub = ( (sqrt(3))/3 );    
    else
    {
        cout << "INVALID NUMBER. EXITING OUT OF PROGRAM " << endl;
        exit(1);
    }
}


void Dictonary::checkVAL(string &val, double &AIANWSERDOUB)
{
    /*
    string arrayPossibleRandians[17] = { "0","pi/6", "pi/4" "pi/3", "pi/2", "2pi/3", "3pi/4", "5pi/6"
        ,"pi", "7pi/6", "5pi/4", "4pi/3", "3pi/2", "5pi/3", "7pi/4"
        ,"11pi/6", "2pi" };
    */
    if(val.compare("0") == 0)
        AIANWSERDOUB = 0;
    else if(val.compare("pi/6") == 0)
        AIANWSERDOUB = (PI/6);
    else if(val.compare("pi/4") == 0)
        AIANWSERDOUB = (PI/4);
    else if(val.compare("pi/3") == 0)
        AIANWSERDOUB = (PI/3);
    else if(val.compare("pi/2") == 0)
        AIANWSERDOUB = (PI/2);
    else if(val.compare("2pi/3") == 0)
        AIANWSERDOUB = ( (2*PI) / 3);
    else if(val.compare("3pi/4") == 0)
        AIANWSERDOUB = ( (3*PI) / 4);
    else if(val.compare("5pi/6") == 0)
        AIANWSERDOUB = ( (5*PI) /6 );
    else if(val.compare("pi") == 0)
        AIANWSERDOUB = PI;
    else if(val.compare("7pi/6") == 0)
        AIANWSERDOUB = ( (7*PI)/6 );
    else if(val.compare("5pi/4") == 0)
        AIANWSERDOUB = ( (5*PI) /4);
    else if(val.compare("4pi/3") == 0)
        AIANWSERDOUB = ( (4*PI) /3);
    else if(val.compare("3pi/2") == 0)
        AIANWSERDOUB = ( (3*PI)/2 );
    else if(val.compare("5pi/3") == 0)
        AIANWSERDOUB = ( (5*PI) /3 );
    else if(val.compare("7pi/4") == 0)
        AIANWSERDOUB = ( (7*PI) /4 );
    else if(val.compare("11pi/6") == 0)
        AIANWSERDOUB = ( (11*PI) /6 );
    else if(val.compare("2pi") == 0)
        AIANWSERDOUB = (2*PI);


}
//degreeToRadians
double Dictonary::d2r(double d)
{
    return(d/180) * ((double) PI);
}

Dictonary::~Dictonary()
{
}

Solution To My Problem. Make a custom Tan Function:

//AI
double Dictonary::customTan(double convertToTan)
{
    double returned;

    if(convertToTan == 0)
        returned = 0;
    else if(convertToTan == (PI/6))
        returned = (sqrt(3)/3);
    else if(convertToTan == (PI/4))
        returned = 1;
    else if(convertToTan == (PI/3))
        returned = sqrt(3);
    else if(convertToTan == (PI/2))
    {
        cout << "GAME EXITING. UNDEFINED NUMBER " << endl;
        exit(1);
    }

    else if(convertToTan == ((2*PI) / 3))
        returned = -(sqrt(3));
    else if(convertToTan == ((3*PI) / 4))
        returned = -1;
    else if(convertToTan == ((5*PI) /6))    
        returned = (-((sqrt(3))/3));
    else if(convertToTan == PI)
        returned = 0;
    else if(convertToTan == (7*PI)/6)
        returned = ( (sqrt(3))/3 );
    else if( convertToTan == (5*PI) /4 )    
        returned = 1;
    else if((4*PI) /3)
        returned = sqrt(3);
    else if( convertToTan == (3*PI)/2 )
    {
        cout << "GAME EXITING. UNDEFINED NUMBER " << endl;
        exit(1);
    }
    else if(convertToTan == (5*PI) /3 )
        returned = -sqrt(3);
    else if(convertToTan == ( (7*PI) /4))
        returned = -1;
    else if(convertToTan == ((11*PI) /6))
        returned = (-((sqrt(3))/3));
    else if(convertToTan == (2*PI))
        returned = 0;
    else
    {
        cout << "INVALID NUMBER. EXITING OUT OF PROGRAM " << endl;
        exit(1);
    }
    return returned;    
}
  • the anwsers on there @tobi303 are pure conceptual.. i want a reason why tan dosent work on my code.. – user6437039 Jun 07 '16 at 20:45
  • 3
    You had a math problem and used floating point numbers to solve it. Now you have 2.00000000003 problems. – nwp Jun 07 '16 at 20:46
  • 2
    @user6437039 because floating point numbers can't be exactly represented in computers and you get rounding errors/approximations in the calculation steps. – AliciaBytes Jun 07 '16 at 20:49
  • It seems like you could really shrink your sample code to provide just an example of the issue you're having. – Retired Ninja Jun 07 '16 at 20:49
  • Im Super Confused @nwp ... If i do #define PI 2.14159265358979323846f Then it gives 8.74228e-08 which is not the anwser... the anwser is 0 – user6437039 Jun 07 '16 at 20:49
  • So How do i solve that problem @RaphaelMiedl ... or is it unsolvable ??!??! – user6437039 Jun 07 '16 at 20:50
  • @user6437039 Computer works in binary, not decimal. That's why `tan` "doesn't work", and the link concerning floating point math discusses this. – PaulMcKenzie Jun 07 '16 at 20:51
  • @PaulMcKenzie So I CANT DO TAN???????? then i cant complete project :( ?? – user6437039 Jun 07 '16 at 20:51
  • http://stackoverflow.com/questions/35373952/why-does-cosm-pi-2-float0-evaluate-to-false-c is another related question. – Mark B Jun 07 '16 at 20:52
  • 1
    @user6437039 you did not ask for `tan` of PI, you asked for `tan` of `3.14159265358979323846 ` which is not equal to PI. – Revolver_Ocelot Jun 07 '16 at 20:52
  • 1
    @user6437039 in general never compare floating point numbers for equality, compare against a delta. For example `if (abs(a - b) < 0.0001)` – AliciaBytes Jun 07 '16 at 20:52
  • 1
    @user6437039 You solve the problem by not comparing floating point using `==` since it is an approximation. Welcome to the world of binary floating point calculations. – PaulMcKenzie Jun 07 '16 at 20:52
  • @user6437039 you CAN, but with specified accuracy – AnatolyS Jun 07 '16 at 20:52
  • The answer cannot be calculated precisely when you round the numbers. `tan(π)` is `0`, `tan(3.14159265358979323846)` is not `0`. – nwp Jun 07 '16 at 20:53
  • Ok @nwp then how do i solve this?? Is this solvable??? Ahhhh – user6437039 Jun 07 '16 at 20:54
  • Same thing @Revolver_Ocelot how do i solve this problem then?? – user6437039 Jun 07 '16 at 20:54
  • @RaphaelMiedl yea, i previously did double – user6437039 Jun 07 '16 at 20:54
  • @PaulMcKenzie .... then how do i solve this without == ??? – user6437039 Jun 07 '16 at 20:54
  • @user6437039 What do you mean "is this solvable"? The solution is to compare "close enough" to 0, not exactly 0. Again, welcome to the world of binary computing machines. – PaulMcKenzie Jun 07 '16 at 20:55
  • @PaulMcKenzie ...... -1.22465e-16 does not "compare close enough" to 0 – user6437039 Jun 07 '16 at 20:57
  • @user6437039 Just compare if the values are **approximately** the same. `if (std::abs(value - expectedValue) < errorEpsilon)`. For epsilon use an appropriate value like `0.00001` or whatever is appropriate in your case. – AliciaBytes Jun 07 '16 at 20:57
  • @user6437039 Have a look at your definition of Pi: `#define PI 3.14159265358979323846`. If you think, this is *precise*, then have a look at [here](http://www.piday.org/million/)... Actually, you did exactly the same yourself as any floating point unit is forced to do due to limited number of bits to represent numbers: you *rounded*. And rounding will lead to such seemingly odd results. This is the same reason why you should not compare two double values for equality, but for being the difference (more precise: absolute value of) smaller than some appropriately small threshold. – Aconcagua Jun 07 '16 at 20:58
  • @user6437039 `-1.22465e-16` is equal to `-0.000000000000000122465` which in my opinion is pretty damn close to 0, and probably close enough for you as well. Note that this is scientific notation, the `-1.22465e-16` means the same as `-1.22465 * 10^-16` – AliciaBytes Jun 07 '16 at 20:59
  • @user6437039 `-0.000000000000000122465` You're joking, right? – PaulMcKenzie Jun 07 '16 at 21:00
  • @user6437039 [See this](https://isocpp.org/wiki/faq/newbie#floating-pt-errs) -- Now if even rinky-dink decimal numbers have a problem with this, what makes you think that `tan(pi)` will be any different. – PaulMcKenzie Jun 07 '16 at 21:02
  • http://cpp.sh/6mkn7 tan takes radians, guys, and why he needs floats, idk – strangeqargo Jun 07 '16 at 21:03
  • @strangeqargo: Yeah, we know. What's your point? – Benjamin Lindley Jun 07 '16 at 21:05
  • i mean, example from reference gives -0.0 not some scientific notation which scares our author – strangeqargo Jun 07 '16 at 21:06
  • @PaulMcKenzie the only way i can do this is if i make a custom tan function that relates to my problem.. – user6437039 Jun 07 '16 at 21:07
  • @strangeqargo: That's a result of `printf` rounding. The actual result is not 0. – Benjamin Lindley Jun 07 '16 at 21:07
  • 1
    @strangeqargo have a look at http://cpp.sh/8grh6 I only replaced your printf with a `cout` and you can see that it uses scientific notation. Your `printf` just did some rounding, that doesn't mean the number was actually 0, or would compare equal with `==` – AliciaBytes Jun 07 '16 at 21:10
  • @user6437039 what's wrong with `answer < 0.000000001` to compare if it's close enough? – AliciaBytes Jun 07 '16 at 21:11
  • @user6437039 -- Forget binary numbers for a moment -- this issue exists for decimal numbers. What if the question is "what is the `tan(0.3)`? What is the answer? – PaulMcKenzie Jun 07 '16 at 21:12
  • 2
    @user6437039: Sounds like you want a symbolic computation library, if you need results to be so exact. – Benjamin Lindley Jun 07 '16 at 21:14
  • @RaphaelMiedl thanks, i see now – strangeqargo Jun 07 '16 at 21:16
  • @RaphaelMiedl i cant see that link you gave me... DNS not found. – user6437039 Jun 07 '16 at 21:17
  • @RaphaelMiedl nvm i see it but, its not 0. – user6437039 Jun 07 '16 at 21:18
  • I Posted Above @PaulMcKenzie a solution. Im not sure yet, since i will hae to test it but thats my custom tan functin – user6437039 Jun 07 '16 at 21:29
  • Nvm it still dosent work @PaulMcKenzie ... Can someone help me [here](https://ide.c9.io/amanuel2/mathgame) please? – user6437039 Jun 07 '16 at 21:32
  • @user6437039 - *i see it but, its not 0* -- With the basic types, that's the best you will get. If you want exact math, then get a multiprecision library like GNU MP, or a symbolic library as mentioned before, or similar library that does exact math. BTW, this issue isn't only with C++, but any language that represents floating point in this fashion, including Java, C#, etc. – PaulMcKenzie Jun 07 '16 at 21:35
  • @PaulMcKenzie can you help me in c9? So i cant do it without use of libraraies... – user6437039 Jun 07 '16 at 21:37
  • @user6437039 *So i cant do it without use of libraraies* -- Sure you can do it without using libraries -- do you have the time to put together code that duplicates what the library creators (who are the experts) have done? If so, go ahead. – PaulMcKenzie Jun 07 '16 at 21:39
  • @PaulMcKenzie i mean i dont know how to use libraries in c9.. sure in visual studio its easy – user6437039 Jun 07 '16 at 21:43
  • What is `c9`? And whatever that is, that's another question concerning how to use libraries. It isn't really related to the `tan` function and floating point accuracy, so that requires another SO question, not tacked to this one. – PaulMcKenzie Jun 07 '16 at 21:47
  • @PaulMcKenzie so i cant do it without the use of Libraries? The only thing i can think of is custom sin+cos+tan functions... – user6437039 Jun 07 '16 at 21:51

0 Answers0