Question

i have troubles implementing a simple training program in C. The program should calculate a random cosinus or sinus of an angle, print the question "calculate cosinus/sinus of the angle x" to the user, who should type in the right answer in form "factor sqrt(value)". i.e. for cos(0) the user should type 1, for sin(45) the user should type 0.5sqrt(2). Most of the code is given in this task. The program doesn't work properly - for cos(270) the right answer is meant to be -0.000. Why is this happening? Why doesn't this code screams "division by 0"? Furthermore according to the task description the variable right should be of type double and rueckgabe of type int. But when i use double instead of float, i just get very high values (like 21234 or -435343). If i would use int as a return value of get_user_input(), the program won't work, right?

Here's the code:

#include <stdio.h>
#include <math.h>
#include <time.h> 
#include <stdlib.h>

#define PI          (acos(-1)) 
#define ACCURACY    1e-4    

float get_user_input(is_cos, angle){ 
    if (is_cos == 1) {
        printf("Berechnen Sie den Cosinus zu %i\n", angle);
    }
    else {
        printf("Berechnen Sie den Sinus zu %i\n", angle);   
    }
    float faktor, wurzel=1.;
    float rueckgabe;
    scanf("%fsqrt(%f)", &faktor, &wurzel);

    rueckgabe = faktor * sqrt(wurzel);

    return rueckgabe;

}

int main (){
    float right;
    int correct;
    int angles[] = { 0, 30, 45, 60, 90, 180, 270, 360 }; 
    srand ( time(NULL) );
    int is_cos = rand()%2; 
    int angle = angles[ rand()%(sizeof(angles)/sizeof(int)) ];

    if( is_cos == 1) {
        right = cos(angle/180.*PI); 
    }
    else {
        right = sin(angle/180.*PI); 
    }


    correct = fabs(get_user_input(is_cos, angle)/right - 1.) <= ACCURACY;

    printf("Ihre Antwort war %s!\n", correct ? "richtig" : "falsch");
    return 0;
}
Was it helpful?

Solution

Since the sine and cosine return values in the range [-1, 1], I'd suggest that you use the absolute, rather than the relative, error. By replacing

correct = fabs(get_user_input(is_cos, angle)/right - 1.) <= ACCURACY;

with

correct = fabs(get_user_input(is_cos, angle) - right) <= ACCURACY;

everything should work as expected.

Generally I tend to use relative errors for large values and absolute errors for small values. You can combine both with

fabs(a-b)/(1.0+min(fabs(a), fabs(b)))

which (assuming you have a reasonable definition of min) tends to the relative error for large values and to the absolute error for small ones.

OTHER TIPS

In your program, both divisor and dividend can be close to / exactly 0 at the same time.

Your program does not give you a "division by zero"-error, because by default most floating point implementations silently give you infinity/NaN/0/-0, depending on the exact values you divide.

The cosine to 270° is not exactly zero in floating-point arithmetic, because 270° cannot be expressed exactly in radians.

The following table shows the cosine of 270° (in the middle row) and in the first and last rows the cosines of the adjacent 32-bit floating-point numbers:

                         phi                        cos(phi)
                   4.7123885                -0.0000004649123
                    4.712389               0.000000011924881
                   4.7123895                0.00000048876205

And the same for 64-bit double-precision floating-point numbers:

                         phi                        cos(phi)
           4.712388980384689         -1.0718754395722282e-15
            4.71238898038469         -1.8369701987210297e-16
           4.712388980384691           7.044813998280222e-16

With the current floating-point precision, there's no way that cos(phi) with phi in the vicinity of 1.5*pi can be exactly zero.

You could fix that by writing a cosdeg that takes an argument in degrees and returns exact values for the angles where the cosines and sines are -1, 0 or 1 and values calulated with radians otherwise. (Which then will happily generate the desired division by zero.)

The arguments to sin() and cos() are expressed in radians, not degrees.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top