I'm trying to compute an estimation of pi using Monte Carlo methods.
The method that I used is that of the circumference inscribed into a square.
This is my simple code for the solution of the problem:
#define _XOPEN_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <mpi.h>
#define SEED time(NULL)
void pi_mpi_version(void) {
unsigned int seed;
long long int all_point;
double x, y, start, end;
int rank, size;
long long int i, points = 0, all_intern;
MPI_Init(NULL, NULL);
start = MPI_Wtime();
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
seed = SEED + rank;
for ( i = 0; i < 1000000000; i++ ) {
x = (double) rand_r(&seed) / RAND_MAX;
y = (double) rand_r(&seed) / RAND_MAX;
if ( x * x + y * y <= 1.0 ) points++;
}
MPI_Reduce(&points, &all_intern, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
all_point = 1000000000 * size;
MPI_Barrier(MPI_COMM_WORLD);
end = MPI_Wtime();
if ( rank == 0 ) {
printf("All intern: %lld\n", all_intern);
printf("All points: %lld\n", all_point);
printf("\u03C0 \u2248 %Lf\n", (long double) all_intern / all_point * 4.0);
printf("Time elapsed: %.4f\n", end - start);
}
MPI_Finalize();
}
I try to set all varible to long long int but with the input 1000000000 like in the code, that return a negative number. With input up to 100000000 it seems to work.
That's actually a much more interesting question than you might imagine. Your results are the combination of two issues: Overflow and a type confusion.
First the overflow part:
Numbers larger than 2147483647 can't be represented using signed 32 bit integers, which is the default size of an int in many C++ compilers as well as what MPI uses for the internal representation of an MPI_INT. So as soon as you have more than a 2-3 MPI ranks, the partial counts in the magnitude of 1000000000 * pi / 4 can still be represented as an int, but their sum can't - the result overflows and becomes a negative number. The same holds for the line
1000000000 * size
Without any suffix, both size and 1000000000 are of type int, so is their product. This computation will thus overflow, and only then will the result be stored in the larger long long int all_points variable.
Simple fix: Replace the computation by
1000000000LL * size
This forces the first integer to be of type long long int, so the whole computation won't overflow.
But your code has a second, more serious issue: Type confusion.
MPI_Reduce expects a void* value for both its send and receive buffer, which means that you can use any pointer as a parameter. The type confusion now is that MPI_Reduce expects you to pass a pointer to an int, because you passed MPI_INT as the type argument. But the pointer you passed points to a long long int. What you would need to use instead is MPI_LONG_LONG_INT, which corresponds to the long long int type.
If you want to know why your code still worked for smaller iteration counts, you can read up on the binary representation of integers, especially Little/Big Endian.
Related
Beginner in C language.
I suspect it may be due to overflow, but could not solve this simple exercise:
program to compute the sum of squares of all the natural numbers smaller than 10000
I initially tried:
#include <stdio.h>
int main() {
int a = 10000;
int square(int num) {
return num * num;
};
int total = 0;
while (a > 0) {
a--;
total += square(a);
//printf("a is %d and square is %d and total %d \n", a, square(a), total );
};
printf("total is %d ", total );
return total;
}
result: total is -1724114088
and here there's the strange thing:
...
a is 9936 and square is 98724096 and total 2063522144
a is 9935 and square is 98704225 and total -2132740927
...
So I tried to change total to long, tried to change declaring square function as long square(int num ), but nothing changed.
Could you explain why the sum turns negative ?
Is it due to overflow ? But why not resetting to 0 or positive, instead of going negative ?
how can I know how many bits for int are there in a computer that I don't know (e.g. cloud ?
E.g. I am coding here: [https://www.programiz.com/c-programming/online-compiler/]
Which is best practice to fix it ?
Do not define function in functions.
int main() {
int square() { // NO!
Functions belong at file scope:
int square() { //OK
}
int main() { //OK
}
The code compiles because compilers have extensions to the language. It's not part of the C programming language.
Could you explain why the sum turns negative ?
See ex. why the value of sum is coming out to be negative? and other questions. The sum "wraps around" on your platform.
Is it due to overflow ?
Yes.
But why not resetting to 0 or positive, instead of going negative ?
Because systems nowadays are twos-complement, it's simpler to implement a single hardware instruction for adding numbers then two separate instructions with special overflow semantics. Unsigned and signed twos-complement numbers behave the same when doing operations on them, so instead of doing special semantics on overflow, when adding signed numbers they are added the same as they would be unsigned (bits are just added) and the result is then interpreted as a signed number (in a C program), which because the most significant bit becomes set the number becomes negative.
Anyway, compiler just does not care, because signed overflow is undefined behavior compiler does not have to care. The compiler just generates a hardware instruction for signed addition, which behaves as explained above.
how can I know how many bits for int are there in a computer that I don't know
You can check your compiler documentation.
But usually it's simpler to just compile a simple C program where you use CHAR_BIT - the number of bits in a byte - and sizeof(int) - the number of bytes in an int - and inspect the output of that program. For example, a program such as:
#include <stdio.h>
#include <limits.h>
int main() {
printf("There are %d bits in int\n", (int)sizeof(int) * CHAR_BIT);
}
Note that number of bits in types does not only change with platform and operating systems, it can change with compiler, compiler versions and also compilation options.
Which is best practice to fix it ?
This depends on what behavior do you want.
To calculate bigger values use a bigger datatype - long or long long. When the language features are not enough, move your program to use some big number library.
If you want to terminate the program in case of problems - you can check for overflow and call abort() or similar if it happens.
Instead, you could have used a formula.
Sum of Squares of first N natural numbers = (N * (N + 1) * (2 * N + 1) / 6
For now, let N be 10000.
Ignoring the 6 in the formula, the sum of squares is as big as 10^12. It will not fit in an integer. You should use a data type that can accommodate bigger values, like long or long long int.
Here's the modified code.
#include <stdio.h>
int main() {
int a = 10000;
int square(int num) {
return num * num;
};
// Change int to long long int
long long int total = 0;
while (a > 0) {
a--;
total += square(a);
//printf("a is %d and square is %d and total %d \n", a, square(a), total );
};
// Change %d to %lld
printf("total is %lld ", total );
return total;
}
You'll need to change all uses of int to long:
#include <stdio.h>
int main() {
long a = 10000;
long square(long num) {
return num * num;
};
long total = 0;
while (a > 0) {
a--;
total += square(a);
//printf("a is %ld and square is %ld and total %ld \n", a, square(a), total );
};
printf("total is %ld ", total );
return 0;
}
which prints total is 333283335000
EDIT
Or you could just change the total, the return type of square, and perform the appropriate casts when computing the squared values:
#include <stdio.h>
int main() {
int a = 10000;
long square(int num) {
return (long)num * (long)num;
};
long total = 0;
while (a > 0) {
a--;
total += square(a);
//printf("a is %ld and square is %ld and total %ld \n", a, square(a), total );
};
printf("total is %ld ", total );
return 0;
}
Produces the same result shown above.
onlinegdb here
EDIT: After some discussion in the comments it came out that because of a luck of knowledge in how floating point numbers are implemented in C, I asked something different from what I meant to ask.
I wanted to use (do operations with) integers larger than those I can have with unsigned long long (that for me is 8 bytes), possibly without recurring to arrays or bigint libraries. Since my long double is 16 bytes, I thought it could've been possible by just switching type. It came out that even though it is possible to represent larger integers, you can't do operations -with these larger long double integers- without losing precision. So it's not possible to achieve what I wanted to do. Actually, as stated in the comments, it is not possible for me. But in general, wether it is possible or not depends on the floating point characteristics of your long double.
// end of EDIT
I am trying to understand what's the largest integer that I can store in a long double.
I know it depends on environment which the program is built in, but I don't know exactly how. I have a sizeof(long double) == 16 for what is worth.
Now in this answer they say that the the maximum value for a 64-bit double should be 2^53, which is around 9 x 10^15, and exactly 9007199254740992.
When I run the following program, it just works:
#include <stdio.h>
int main() {
long double d = 9007199254740992.0L, i;
printf("%Lf\n", d);
for(i = -3.0; i < 4.0; i++) {
printf("%.Lf) %.1Lf\n", i, d+i);
}
return 0;
}
It works even with 11119007199254740992.0L that is the same number with four 1s added at the start. But when I add one more 1, the first printf works as expected, while all the others show the same number of the first print.
So I tried to get the largest value of my long double with this program
#include <stdio.h>
#include <math.h>
int main() {
long double d = 11119007199254740992.0L, i;
for(i = 0.0L; d+i == d+i-1.0; i++) {
if( !fmodl(i, 10000.0L) ) printf("%Lf\n", i);
}
printf("%.Lf\n", i);
return 0;
}
But it prints 0.
(Edit: I just realized that I needed the condition != in the for)
Always in the same answer, they say that the largest possible value of a double is DBL_MAX or approximately 1.8 x 10^308.
I have no idea of what does it mean, but if I run
printf("%e\n", LDBL_MAX);
I get every time a different value that is always around 6.9 x 10^(-310).
(Edit: I should have used %Le, getting as output a value around 1.19 x 10^4932)
I took LDBL_MAX from here.
I also tried this one
printf("%d\n", LDBL_MAX_10_EXP);
That gives the value 4932 (which I also found in this C++ question).
Since we have 16 bytes for a long double, even if all of them were for the integer part of the type, we would be able to store numbers till 2^128, that is around 3.4 x 10^38. So I don't get what 308, -310 and 4932 are supposed to mean.
Is someone able to tell me how can I find out what's the largest integer that I can store as long double?
Inasmuch as you express in comments that you want to use long double as a substitute for long long to obtain increased range, I assume that you also require unit precision. Thus, you are asking for the largest number representable by the available number of mantissa digits (LDBL_MANT_DIG) in the radix of the floating-point representation (FLT_RADIX). In the very likely event that FLT_RADIX == 2, you can compute that value like so:
#include <float.h>
#include <math.h>
long double get_max_integer_equivalent() {
long double max_bit = ldexpl(1, LDBL_MANT_DIG - 1);
return max_bit + (max_bit - 1);
}
The ldexp family of functions scale floating-point values by powers of 2, analogous to what the bit-shift operators (<< and >>) do for integers, so the above is similar to
// not reliable for the purpose!
unsigned long long max_bit = 1ULL << (DBL_MANT_DIG - 1);
return max_bit + (max_bit - 1);
Inasmuch as you suppose that your long double provides more mantissa digits than your long long has value bits, however, you must assume that bit shifting would overflow.
There are, of course, much larger values that your long double can express, all of them integers. But they do not have unit precision, and thus the behavior of your long double will diverge from the expected behavior of integers when its values are larger. For example, if long double variable d contains a larger value then at least one of d + 1 == d and d - 1 == d will likely evaluate to true.
You can print the maximum value on your machine using limits.h, the value is ULLONG_MAX
In https://www.geeksforgeeks.org/climits-limits-h-cc/ is a C++ example.
The format specifier for printing unsigned long long with printf() is %llu for printing long double it is %Lf
printf("unsigned long long int: %llu ",(unsigned long long) ULLONG_MAX);
printf("long double: %Lf ",(long double) LDBL_MAX);
https://www.tutorialspoint.com/format-specifiers-in-c
Is also in Printing unsigned long long int Value Type Returns Strange Results
Assuming you mean "stored without loss of information", LDBL_MANT_DIG gives the number of bits used for the floating-point mantissa, so that's how many bits of an integer value that can be stored without loss of information.*
You'd need 128-bit integers to easily determine the maximum integer value that can be held in a 128-bit float, but this will at least emit the hex value (this assumes unsigned long long is 64 bits - you can use CHAR_BIT and sizeof( unsigned long long ) to get a portable answer):
#include <stdio.h>
#include <float.h>
#include <limits.h>
int main( int argc, char **argv )
{
int tooBig = 0;
unsigned long long shift = LDBL_MANT_DIG;
if ( shift >= 64 )
{
tooBig = 1;
shift -= 64;
}
unsigned long long max = ( 1ULL << shift ) - 1ULL;
printf( "Max integer value: 0x" );
// don't emit an extraneous zero if LDBL_MANT_DIG is
// exactly 64
if ( max )
{
printf( "%llx", max );
}
if ( tooBig )
{
printf( "%llx", ULLONG_MAX );
}
printf( "\n" );
return( 0 );
}
* - pedantically, it's the number of digits in FLT_RADIX base, but that base is almost certainly 2.
I am newbie, please bear if my question is silly.
int main()
{
int x=60674;
printf("%lf \n",(double)(x*x));
printf("%lld \n",(long long)(x*x));
return 0;
}
Why is this not working?
x * x overflows, so you should cast them into long longs before the multiplication:
printf("%lld \n",((long long)x * (long long)x));
Additionaly you may use standardised ints:
#include <inttypes.h>
#include <stdio.h>
int main() {
int x=60674;
printf("%" PRIu64 "\n",(uint64_t)x * x);
return 0;
}
Moreover you do not need to cast both variables .. the * will impose using the bigger type of the two multipliers.
Btw you could just use unsigned int .. the result would fit in UINT_MAX which is 4294967295 (from here )
x is a signed integer that can hold value only upto -2,147,483,847 to +2,147,483,847 and on performing the operation
x * x
==> 60674 * 60674 = 3,681,334,276
which generally overflows the integer range. Hence you might need some big data type to hold that calculation 60674 * 60674
You can try two things to do that.
Change the data type of x from int to long or for more range long long
long long x = 60674;
Type cast the calculation to long range data type.
printf("%lld \n",((long long)x* (long long)x));
After compiling this code:
#include <stdio.h>
int main()
{
long int a = 1000 * 1000 * 1000 * 1000 * 1000 * 1000;
printf("%i\n", a);
return 0;
}
I get -1486618624 as a result. How can I make this code work?
Thanks in advance for any answers!
The instances of 1000 you have specified are ints, therefore the multiplication takes place by multiplying ints and getting an int. This is overflowing before it gets assigned to a long int. Try:
long int a = 1000L * 1000L * 1000L * 1000L * 1000L * 1000L;
Also you need to then print the answer using a long int format, e.g.:
printf("%ld\n", a);
Note a long int may also be too small (if you are on some 32 bit platforms the maximum storable in a long int is 2^31 - 1, whereas on 64 bit platforms it's 2^63 - 1 which is sufficient), in which case try:
long long int a = 1000LL * 1000LL * 1000LL * 1000LL * 1000LL * 1000LL;
printf("%lld\n", a);
Even though you are assigning to a long int, each of your 1000s is an int, so the computer tries to calculate the result as an int. A number that exceeds the maximum int size overflows, causing it to "wrap around" and be seen as negative, because one bit of the memory used for an int is a negative flag.
You need to cast the 1000s, either with 1000L or (long int) 1000 for each. You also need %ld instead of %i in your printf.
Try using
long long var=1000LL*1000LL*1000LL; // append LL
printf("%lld",var);
Why do these programs produce different outputs?
Program 1:
#include <stdio.h>
#include <limits.h>
int main()
{
long long bigger = 0;
int smaller = INT_MAX;
bigger = smaller * 2;
printf("Smaller = %d\n", smaller);
printf("Bigger = smaller * 2 = %lld\n\n", bigger);
return 0;
}
Output:
Smaller = 2147483647
Bigger = smaller * 2 = -2
Program 2:
#include <stdio.h>
#include <limits.h>
int main()
{
long long bigger = 0;
int smaller = INT_MAX;
bigger = smaller;
bigger *= 2;
printf("Smaller = %d\n", smaller);
printf("Bigger = smaller * 2 = %lld\n\n", bigger);
return 0;
}
Output:
Smaller = 2147483647
Bigger = smaller * 2 = 4294967294
My guess is that program 1 attempts to store the multiplication result in a temporary storage which is of the same size as int. So it overflows. Whereas, program 2, stores the multiplication result in the larger storage.
Am I correct?
Additionally, if I have made any grievous mistake in either of the programs, please let me know (because according to me, those programs compile perfectly)!
smaller is an int, so is the literal 2. So their product is an int too. Since INT_MAX * 2 can't be represented by an int (by definition, pretty much), it overflows leading to undefined behavior.
If, however, you store the value in a long long, then, when performing the multiplication, default integer promotion (the "usual arithmetic conversion") happens. Now, if your long long can represent INT_MAX * 2, you will end up with something semantically equivalent with bigger = bigger * (long long)2, which works as expected.