Consider the following:
double fact(int n)
{
int i;
double res = 1;
for (i = 1; i <= n; i++)
res *= i;
return res;
}
double f = 1;
for (int i = 0; i < 16; i++)
{
printf("%lf \n", fact(2*i + 1));
f *= (f + 1)*(f + 2);
printf("%lf \n", f);
}
Why does fact(2*i+1) results a correct value while f results a weird value of 1.#INF00?
Because it overflows.
The value of f after 16 iterations is bigger than if your code looked like this and your initial f was 2:
f *= f*f;
Which is the same as
f = f*f*f
So you take a cube 16 times - this is HUGE!
2^3 = 8
8^3 = 512
512^3 = 134217728
...
On the topic of undefined behaviour, the l length modifier in %lf is only defined for conversion specifiers using integer types. If you meant to use %Lf, then your argument should be a long double. Perhaps you meant to use %f, which corresponds to a double argument (floats end up promoted to double when passing them to variadic functions such as printf).
As Peter Ivanov explained, your calculations cause an overflow, which IIRC is also undefined behaviour.
As you've probably guessed, you might find a solution to your problem by using the long double type (and the corresponding %Lf format specifier) throughout your code...
Related
I tried to solve a task on codewars and happened something strange, in one case casting worked as usual and in the second o got strange behavior. Here is the code:
#include <stdio.h>
#include <string.h>
#include <math.h>
int digital_root(int n) {
char tmp[30];
char *ptr;
while(n > 9){
sprintf(tmp, "%d", n);
int len = strlen(tmp);
float n_tmp = n / (pow(10, len));
n = 0;
for(int i = 1; i <=len; i++){
float t = n_tmp * (pow(10, i));
printf(" vars = [%f , %d] ", t, (int)t); //this line
n += (int) t;
n_tmp -= (int)t/pow(10,i);
}
}
return n;
}
int main()
{
digital_root(16);
return 0;
}
And the line printf(" vars = [%f , %d] ", t, (int)t); outputs: vars = [1.600000 , 1] vars = [6.000000 , 5], what is so strange. Can someone explain this behavior?
Every casting float to int is a rounding, so every time you do it, stop for a second and think: what kind of rounding do I need this time? Dropping the fractional part? floor()? ceil()? Or rounding positive float towards nearest int? If 5.999999999999 should be 6, use (int)(t+.5), not (int)t.
Or you can mimic the printf behavior and round only the smallest float fraction, which can vary (depending on the biggest value you use). (int)(t+.000001) will round both 1.9 to 1 (as it probably should), and 3.9999999999 to 4 (because it is 4 with some tiny number representation errors).
You should however know the size of a fraction which can be an actual, meaningful part of your data. Everything smaller than this fraction must be rounded. It can be either .00000001 or .5, that depends on your needs and the algorithm itself.
The function calculates the value of sinh(x) using the following
development in a Taylor series:
I want to calculate the value of sinh(3) = 10.01787, but the function outputs 9. I also get this warning:
1>main.c(24): warning C4244: 'function': conversion from 'double' to 'int', possible loss of data
This is my code:
int fattoriale(int n)
{
int risultato = 1;
if (n == 0)
{
return 1;
}
for (int i = 1; i < n + 1; i++)
{
risultato = risultato * i;
}
return risultato;
}
int esponenziale(int base, int esponente)
{
int risultato = 1;
for (int i = 0; i < esponente; i++)
{
risultato = risultato * base;
}
return risultato;
}
double seno_iperbolico(double x)
{
double risultato = 0, check = -1;
for (int n = 0; check != risultato; n++)
{
check = risultato;
risultato = risultato + (((esponenziale(x, ((2 * n) + 1))) / (fattoriale((2 * n) + 1))));
}
return risultato;
}
int main(void)
{
double numero = 1;
double risultato = seno_iperbolico(numero);
}
Please help me fix this program.
It is actually pretty great that the compiler is warning you about this kind of data loss.
You see, when you call this:
esponenziale(x, ((2 * n) + 1))
You essentially lose your accuracy since you are converting your double, which is x, to an int. This is since the signature of esponenziale is int esponenziale(int base, int esponente).
Change it to double esponenziale(double base, int esponente), risultato should be a double as well, since you are returning it from the function and performing mathematical operations with/on it.
Remember that dividing a double with an int gives you a double back.
Edit: According to ringø's comment, and seeing how it actually solved your issue, you should also set double fattoriale(int n) and inside that double risultato = 1;.
You are losing precision since many of the terms will be fractional quantities. Using an int will clobber the decimal portion. Replace your int types with double types as appropriate.
Your factorial function will overflow for surprisingly small values of n. For 16 bit int, the largest value of n is 7, for 32 bit it's 12 and for 64 bit it's 19. The behaviour on overflowing a signed integral type is undefined. You could use unsigned long long or a uint128_t if your compiler supports it. That will buy you a bit more time. But given you're converting to a double anyway, you may as well use a double from the get-go. Note that an IEEE764 floating point double will hit infinity at 171!
Be assured that the radius of convergence of the Maclaurin expansion of sinh is infinite for any value of x. So any value of x will work, although convergence might be slow. See http://math.cmu.edu/~bkell/21122-2011f/sinh-maclaurin.pdf.
I wrote this code in C:
double x1 = 7.52, x2 = 7, x3 = 8;
int m = 0;
double sum = x1 + x2*m + x3*m*m;
printf("%lf", m, sum);
but sum is always 0 no matter what the value of m that i changed..
why doesnt it make normal calculation ?
thanks
Because your are printing m which is int with the "%lf" specifier which is for double.
And you are also passing more arguments to printf() than format specifiers, which means that you are not enabling compiler warnings, you should, specially if you are a beginner.
Change this
printf("%lf", m, sum);
to
printf("m = %d\nsum = %f\n", m, sum);
and see what I mean.
Actually you are printing the value of m -
printf("%lf", m, sum);
You have to print -
printf("%lf",sum);
I am generating arrays which are dynamic size. The part of the code that I am showing is grabbing value of the array the way it does, and it works.
The problem is I have no idea how this work. I don't see why both cast and pre-cast have pointer in it?
How to code something similar correctly?
Example: *(double*)&j;
I also noticed that *(int*)&column_sum[i] + 1; won't add the 1 to the result. Also I have no idea why...
double val = 1000 * multiplier;
double *column_sum = malloc(val * sizeof *column_sum);
double *p = malloc(val * val * sizeof *p);
printf("Rows/Columns: %.0f", val);
for (i = 0; i < val; i++){
column_sum[i] = 0.0;
for (j = 0; j < val; j++){
int index = i * (int)val + j;
p[index] = *(double*)&j; // here
int offsetI = *(int*)&column_sum[i] + 1; // here
int offsetJ = *(int*)&p[index] + 1; // here
printf("%d->", offsetI);
printf("%d,", offsetJ);
}
printf("\n");
}
What does it do:
&var // get the pointer of the variable
(type*)&var // cast the pointer to an other pointer type
*(type*)&var // Dereferencing the casted pointer so "interpret" the variable as a "type"
What is important here, is that it is interpret and not cast.
We can see the difference in this example:
float a = 0.5;
int b = (int)a;
int c = *(int*)&a;
printf("%f %08x %08x\n", a, b, c);
// Output:
// 0.500000 00000000 3f000000
// 3f000000 is the way 0.5 is encoding following standard IEEE 754
It's usefull if you want to work on representation of floats for example:
float a = 1.5;
int b = *(int*)&a;
b &= 0xF;
a = *(float*)&b;
For example it's the reason of the use of this syntax here: https://en.wikipedia.org/wiki/Fast_inverse_square_root#Overview_of_the_code, for manipulating bit of representation of double.
I have this number in hexadecimal:
FFFFFFFFFFFF
and I need to save it, so I used double
double a=0xffffffffffff;
but I need to print it and I don't know how to. Each time I use %f, %d, %x, it doesn't print the value of it; I just need to print ffffffffffff. My code:
int main()
{
double a=0xffffffffffff;
printf("%x\n",a);
printf("%d\n",a);
printf("%X\n",a);
printf("%f\n",a);
return 0;
}
The only true value is %f; that returns the decimal value of the hexadecimal — it returns this:
ffffffe0
-32
FFFFFFE0
281474976710655.000000
with this I need to change from that hexadecimal to string, to compare it, because I have FFFFFFFFFFFF in string too and I need to compare both. If I can't printf it, neither will sprintf will work.
That's an integer, and a long one. Don't use double to store such a value, that's for floating-point.
Just use:
unsigned long long temp = 0xffffffffffffull;
You have 12 hexadecimal digits, so your number needs at least 12 * 4 = 48 bits. Most platforms should have an unsigned long long of 64 bits, which should be fine.
If your compiler is supported enough to support C99, you can do:
#include <stdint.h>
and then use the uint_least64_t type as suggested in a comment. In Linux I guess you're using GCC so you should be fine, you might need to specify that you intend your code to be compiled as C99 (with -std=c99).
To print it, use:
printf("temp=%llx\n", temp);
Also note that the value itself is not hexadecimal, but you can print it as hexadecimal. THe value is just a value, the base matters only when converting to/from text, i.e. an external representation of the number. Internally on a binary computer, the number is stored in binary.
While you store the value in a double, there's no sane way to get hexadecimal output.
Your code passes a double to printf() and repeatedly tries to format that as a plain int; that is not going to work well. If you used GCC with warnings enabled, you should have got warnings about mismatches between format string and value (and if you use GCC without warnings enabled, repent your evil/lazy ways and turn the compiler warnings on — use -Wall at least, and probably -Wextra too, and fix any resulting warnings).
The value is 12 F's, so it is a long long value (or unsigned long long); store it and treat it as such:
int main()
{
unsigned long long a = 0xFFFFFFFFFFFF;
printf("%llx\n", a);
printf("%lld\n", a);
printf("%llX\n", a);
printf("0x%llX\n", a);
return 0;
}
An old question, but I think the OP was trying to get to a hex string representation of a double and back again.
If so, here's some code to do that:
union {
double dbl;
uint8_t i8[sizeof(double) + 1];
} buf;
printf("sizeof(dbl) = %ld\n", sizeof(double));
memset(buf.i8, 0x00, sizeof(buf.i8));
buf.dbl = 3.14159265359;
printf("%f\n", buf.dbl);
for(int i = 0; i < (int) sizeof(buf.i8) - 1; ++i) {
printf("%02X", buf.i8[i]);
}
printf("\n");
The resulting output is:
sizeof(dbl) = 8
3.141593
EA2E4454FB210940
To read in the 16 character string and get the double back:
const char* str = "EA2E4454FB210940";
int j = 0;
for (int i = 0; i < (int) strlen(str); i += 2) {
uint8_t val = 0;
for (int k = 0; k < 2; ++k) {
char ch = str[i + k];
val *= 16;
if (ch >= '0' && ch <= '9') {
val += ch - '0';
} else if (ch >= 'A' && ch <= 'F') {
val += ch - 'A' + 10;
}
}
buf.i8[j++] = val;
}
for(int i = 0; i < (int) sizeof(buf.i8) - 1; ++i) {
printf("%02X", buf.i8[i]);
}
printf("\n");
printf("%f\n", buf.dbl);
The output is:
EA2E4454FB210940
3.141593
Note that this is on OSX, different platforms may not have the same binary representation for a double. Also, not sure what happens with NaN and other oddball values.
In another context, his question is valid. Say you want to print the output of the pow() function in hexadecimal - I just encountered one now.
printf( "pow(a, b) is : %f\n", pow(a, b) ); //Will give decimal value
printf( "pow(a, b) is : %X\n", pow(a, b) ); //Not allowed
So do
unsigned long long int temp;
temp = pow(a, b);
printf( "pow(a, b) is : %X\n", temp); //Will give hexadecimal value