Why tanh function from math.h library give wrong result? - c

#include<stdio.h>
#include<math.h>
#define PI 2*acos(0.0)
int main(void)
{
double theta;
theta=tanh(1/(sqrt(3.0)));
printf("With tanh function = %lf\n",theta);
printf("Actual value = %lf\n",PI/6.0);
return 0;
}
Output:
With tanh function = 0.520737
Actual value = 0.523599
Why are these two values different? It should me same as my understanding.

You've got that identity completely wrong.
The actual identity is
tanh-1(i ⁄ √3) = πi ⁄ 6 (where i is the imaginary unit, √-1)
C11 can easily validate that:
#define _XOPEN_SOURCE 700
#include<stdio.h>
#include<math.h>
#include<complex.h>
int main(void)
{
complex double theta=catanh(I/sqrt(3.0));
printf("With atanh function = %lf\n",cimag(theta));
printf("Actual value = %lf\n",M_PI/6);
return 0;
}
(Live on coliru: http://coliru.stacked-crooked.com/a/f3df5358a2be67cd):
With atanh function = 0.523599
Actual value = 0.523599
M_PI will be in math.h in any Posix compliant system. Apparently, on Windows you use
#define _USE_MATH_DEFINES
but I have no idea whether Visual Studio supports complex.h.

Your program has a couple of minor flaws, but none that cause it to misbehave.
Your PI macro should be parenthesized:
#define PI (2*acos(0.0))
but you happen to get away without the parentheses because of the way you use it.
The correct format for printing a double value is actually %f, but %lf is accepted as well. (%Lf is for long double. %f also works for float, because float arguments to variadic functions are promoted to double). This also doesn't affect your program's behavior.
In fact, your program is working correctly. I've confirmed using an HP 42S emulator that tanh(1/(sqrt(3.0))) is approximately 0.520737 (I get 0.520736883716).
The problem is your assumption that the result should be π/6.0. It isn't.

Related

Float inputs for which sinf and sin return different results?

I'm trying to understand something about sin and sinf from math.h.
I understand that their types differ: the former takes and returns doubles, and the latter takes and returns floats.
However, GCC still compiles my code if I call sin with float arguments:
#include <stdio.h>
#include <math.h>
#define PI 3.14159265
int main ()
{
float x, result;
x = 135 / 180 * PI;
result = sin (x);
printf ("The sin of (x=%f) is %f\n", x, result);
return 0;
}
By default, all compiles just fine (even with -Wall, -std=c99 and -Wpedantic; I need to work with C99). GCC won't complain about me passing floats to sin. If I enable -Wconversion then GCC tells me:
warning: conversion to ‘float’ from ‘double’ may alter its value [-Wfloat-conversion]
result = sin (x);
^~~
So my question is: is there a float input for which using sin, like above, and (implicitly) casting the result back to float, will result in a value that is different from that obtained using sinf?
This program finds three examples on my machine:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i;
float f, f1, f2;
for(i = 0; i < 10000; i++) {
f = (float)rand() / RAND_MAX;
float f1 = sinf(f);
float f2 = sin(f);
if(f1 != f2) printf("jackpot: %.8f %.8f %.8f\n", f, f1, f2);
}
}
I got:
jackpot: 0.98704159 0.83439910 0.83439904
jackpot: 0.78605396 0.70757037 0.70757031
jackpot: 0.78636044 0.70778692 0.70778686
This will find all the float input values in the range 0.0 to 2 * M_PI where (float)sin(input) != sinf(input):
#include <stdio.h>
#include <math.h>
#include <float.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
int main(void)
{
for (float in = 0.0; in < 2 * M_PI; in = nextafterf(in, FLT_MAX)) {
float sin_result = (float)sin(in);
float sinf_result = sinf(in);
if (sin_result != sinf_result) {
printf("sin(%.*g) = %.*g, sinf(%.*g) = %.*g\n",
FLT_DECIMAL_DIG, in, FLT_DECIMAL_DIG, sin_result,
FLT_DECIMAL_DIG, in, FLT_DECIMAL_DIG, sinf_result);
}
}
return 0;
}
There are 1020963 such inputs on my amd64 Linux system with glibc 2.32.
float precision is approximately 6 significant figures decimal, while double is good for about 15. (It is approximate because they are binary floating point values not decimal floating point).
As such for example: a double value 1.23456789 will become 1.23456xxx as a float where xxx are unlikely to be 789 in this case.
Clearly not all (in fact very few) double values are exactly representable by float, so will change value when down-converted.
So for:
double a = 1.23456789 ;
float b = a ;
printf( "double: %.10f\n", a ) ;
printf( "float: %.10f\n", b ) ;
The result in my test was:
double: 1.2345678900
float: 1.2345678806
As you can see the float in fact retained 9 significant figures in this case, but it is by no means guaranteed for all possible values.
In your test you have limited the number of instances of mismatch because of the limited and finite range of rand() and also because f itself is float. Consider:
int main()
{
unsigned mismatch_count = 0 ;
unsigned iterations = 0 ;
for( double f = 0; f < 6.28318530718; f += 0.000001)
{
float f1 = sinf(f);
float f2 = sin(f);
iterations++ ;
if(f1 != f2)
{
mismatch_count++ ;
}
}
printf("%f%%\n", (double)mismatch_count/iterations* 100.0);}
In my test about 55% of comparisons mismatched. Changing f to float, the mismatches reduced to 1.3%.
So in your test, you see few mismatches because of the constraints of your method of generating f and its type. In the general case the issue is much more obvious.
In some cases you might see no mismatches - an implementation may simply implement sinf() using sin() with explicit casts. The compiler warning is for the general case of implicitly casting a double to a float without reference to any operations performed prior to the conversion.
However, GCC still compiles my code if I call sin with float arguments:
Yes, this is because they are implicitly converted to double (because sin() requires a float), and back to float (because sin() returns a double) on entering and exiting from the sinf() function. See below why it is better to use sinf() in this case, instead of having only one function.
You have included math.h which has prototypes for both function calls:
double sin(double);
float sinf(float);
And so, the compiler knows that to use sin() it is necessary a conversion from float to double so it compiles a conversion before calling, and also compiles a conversion from double to float in the result from sin().
In case you have not #include <math.h> and you ignored the compiler warning telling you are calling a function sin() with no prototype, the compiler should have also converted first the float to double (because on nonspecified argument types this is how it mus proceed) and pass the double data to the function (which is assumed to return an int in this case, that will provoke a serious Undefined Behaviour)
In case you have used the sinf() function (with the proper prototype), and passed a float, then no conversion should be compiled, the float is passed as such with no type conversion, and the returned value is assigned to a float variable, also with no conversion. So everything goes fine with no conversion, this makes the fastest code.
In case you have used the sinf() function (with no prototype), and passed a float, this float would be converted to a double and passed as such to sinf(), resulting in undefined behaviour. In case somehow sinf() returned properly, an int result (that could have something to do with the calculation or not, as per UB) would be converted into float type (should this be possible) and assigned to the result value.
In the case mentioned above, in case you are operating on floats, it is better to use sinf() as it takes less to execute (it has less iterations to do, as less precision is required in them) and the two conversions (from float to double and back from double to float) have not to be compiled in, in the binary code output by the compiler.
There are some systems where computations on float are an order of magnitude faster than computations on double. The primary purpose of sinf is to allow trigonometric calculations to be performed efficiently on such systems in cases where the lower precision of float would be adequate to satisfy application needs. Converting a value to float, calling sin, and converting the result to float would always yield a value that either matched that of sinf or was more accurate(*), and on some implementations that would in fact be the most efficient way of implementing sinf. On some other systems, however, such an approach would be more than an order of magnitude slower than using a purpose-designed function to evaluate the sine of a float.
(*) Note that for arguments outside the range +/- π/2, the most mathematically accurate way of computing sin(x) for an exact specified value of x might not be the most accurate way of computing what the calling code wants to know. If an application computes sinf(angle * (2.0f * 3.14159265f)), when angle is 0.5, having the function (double)3.1415926535897932385-(float)3.14159265f may be more "mathematically accurate" than having it return sin(angle-(2.0f*3.14159265f)), but the latter would more accurately represent the sine of the angle the code was actually interested in.

Why does compiler think I am using double, in "pow". 'double' to 'float' C4244

I am new to C programming. I keep getting this error, (in this case relating to code inside the cubic root function):
1>c:\users\r\documents\visual studio 2010\projects\lab5.c\lab5.c\lab5code.c(57): warning C4244: '=' : conversion from 'double' to 'float', possible loss of data
I have tried storing the cubic root calculation in a float, and then returning that to main, but still no luck. I have seen people compile my code with no problems.
I have so far tested the code on VS 2008, and 2010 express editions, same errors. I get this a lot, trying to figure out why.
//INCLUDE HEADER FILES
#include <stdio.h> //Defines printf, scanf & getch
#include <conio.h> //Defines get.ch
#include <stdlib.h> //Defines system("pause")
#include <math.h> //Defines math functions
// FUNCTION PROTOTYPES
void explain();
float get_value();
float cubic_root(float num);
void display(float x, float y);
int main(void)
{
float in,out;
//Variable Declarations
explain(); //Explain
in=get_value(); //Get Value from USER
out=cubic_root(in); //Calculations
display(in,out); //Output
}
//FUNCTION DEFINITIONS
void explain(void)
{
system("cls");
puts("This will take cubic root\nPress enter to continue...");
_getch();
}
float get_value(void)
{
float input;
fflush(stdin);
puts("Enter the number you want to cube root...\n");
scanf_s("%f",&input);
return(input);
}
float cubic_root(float num)
{
float div,total;
total=(pow(num,1.0/3.0));
return(total);
}
void display(float x, float y)
{
printf("%.1f, %.1f",x,y);
getch();
}
Because pow() returns a double, and you are assigning it to a float.
exp1=pow(num,0.33);
pow() returns a double and you're converting it to a float. That's why a warning is emitted and you should take notice of it.
The best thing to do is to refactor your code to use double precision variables. You will probably find that there is no performance hit in doing that as many low level floating point computations are at (or higher than) double precision anyway.
Note that pow(num, 0.33); is a grotesque approximation for a cube root. Use pow(num, 1.0 / 3); instead. You need to use 1.0 so the literal is evaluated (most likely at compile time) in floating point.
This:
exp1 = pow(num, 0.33);
assigns the return value of the pow() function, which has type double, to exp which has type float.
The fix is to use the powf() function instead:
float cubic_root(float num)
{
return powf(num, 1.f / 3.f);
}
You can of course just cast the result to float to tell the compiler you really mean this, but it seems extremely wasteful and pointless to do the exponentiation calculation using more precision than you really need, so don't do that.

Unexpected result from a division

I tried to implement the following calculation:
#include <stdio.h>
#include <math.h>
int main(){
float sum = 0;
int c = -4;
float x1 = 136.67;
float x2 = 2.38;
sum = c / (pow(abs(x1 - x2), 2));
printf("%f %f %f",sum,x1,x2);
return 0;
}
But the value of sum after the execution turns out to be -4. What is wrong?
abs is declared in <stdlib.h>. It takes an int argument and returns an int result.
The missing #include <stdlib.h> is likely to cause problems as well. You're calling abs with a floating-point argument; without a visible declaration, the compiler will probably assume that it takes a double argument, resulting in incorrect code. (That's under C90 rules; under C99 rules, the call is a constraint violation, requiring a compile-time diagnostic.)
You want the fabs function defined in <math.h>.
abs expects an integer, and you are providing a float. It should work if you apply an explicit type cast:
sum = c / (pow(abs((int)(x1 - x2)), 2));

C (C++, Objective-C) typecast from float to int results in decremented int

I've written an iPhone-App and encountered a problem concerning typecasting between float and int. I've rewritten the code in C and the results always were the same, no matter if having it compiled under OS X (Console and Xcode), Linux (Console) or Windows (Visual Studio):
// Calculation of a page index depending on the amount of pages, its x-offset on the view
// and the total width of the view
#include <stdio.h>
int main()
{
int result = 0;
int pagesCnt = 23;
float offsetX = 2142.0f;
float width = 7038.0f;
offsetX = offsetX / width;
offsetX = (float)pagesCnt * offsetX;
result = (int)offsetX;
printf("%f (%d)\n", offsetX, result);
// The console should show "7.000000 (7)" now
// But actually I read "7.000000 (6)"
return 0;
}
Of course, we have a loss of precision here. When doing the math with the calculator x results in 7.00000000000008 and not in just 7.000000.
Nevertheless, as much as I understand C, this shouldn't be a problem as C is meant to truncate the the after-point-positions of a floating point number when converting it to an integer. In this case this is what I want actually.
When using double instead of float, the result would be as expected, but I don't need double precision here and it shouldn't make any difference.
Am I getting something wrong here? Are there situations when I should avoid conversion to int by using (int)? Why is C decrementing result anyway? Am I supposed to always use double?
Thanks a lot!
Edit: I've misformulated something: Of course, it makes a difference when using double instead of float. I meant, that it shouldn't make a difference to (int) 7.000000f or 7.00000000000008.
Edit 2: Thanks to you I understand my mistake now. Using printf() without defining the floating point precision was wrong. (int)ing 6.99... to 6 is correct, of course. So, I'll use double in the future when encountering problems like this.
When I augment the precision for the output, the result that I receive from your program is 6.99999952316284179688 (6), so 6 seems to be correct.
If you change printf("%f (%d)\n", offsetX, result); to printf("%.8f (%d)\n", offsetX, result); you will see the problem. After making that change, the output is:
6.99999952 (6)
You can correct this by rounding instead of casting to int. That is, change result = (int)offsetX; to result = roundf(offsetX);. Don't forget to #include <math.h>. Now, the output is:
6.99999952 (7)
The compiler is not free to change the order of floating-point operations in many cases, since finite precision arithmetic is not, in general, associative. i.e.,
(23 * 2142) / 7038 = 7.00000000000000000000
(2142 / 7038) * 23 = 6.99999999999999999979
These aren't single precision results, but it shows that double precision will not address your problem either.

Function call with different datatypes

Isn't line 7 of this program "pay = prt(pay);" supposed to throw a compile or run-time error because it is passing in an int to a param that requires a double? I compiled it fine with dev-c++ and ran the program with both lines of output. Please explain, thank you.
#include <stdio.h>
int prt(double b);
main ()
{
int pay = 3;
double tax = 2.2;
pay = prt(pay);
prt(tax);
}
int prt(double b)
{
b *= 2;
printf("%.2lf\n", b);
}
C will automatically convert between different numeric types in this situation.
See Implicit type conversion in C-like languages.
You declared a function as int but never returned anything, and didn't give main a return type either. I'd say any compiler would be well within it's rights to reject your code.
data type having smaller or equal size can be converted to higher one.
in reverse case:
Float to int causes truncation, ie removal of the fractional part.
double to float causes rounding of digit
long int to int causes dropping of excess higher order bits.

Resources