Thread: Type casting

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Registered User
    Join Date
    May 2005
    Posts
    207

    Type casting

    I have a prime number calculator program that uses type casting. The type casting occurs in my "prime_calculator" function, under "Discard remaining composite numbers".

    If I run it without type casting it, I get an error msg "conversion from double to unsigned long; possible loss of data".

    I was just wondering where/what is the "double"?

    mw

    Code:
    #include<stdio.h>
    #include<stdlib.h>
    #include<math.h>
    #include<malloc.h>
    
    /*
    
    This program calculates prime numbers using the Eratosthenes Sieve algorithm.  It will find the prime numbers between 2 & "max".  It overwrites the prime numbers to the file "prime_numbers.txt"
    in the same folder.
    
    Definitions:
    
    1) Prime Number: a number with only 2 divisibles (itself & 1); the number "1" is not considered a prime number in this program
    2) Composite Number: a number with more than 2 divisibles
    
    Variable key:
    
    discard = this is used to calculate composite numbers
    count = a variable I use to count with
    prime[max] = a pointer array that stores all of the numbers in the "max" range
    max = the maximum range of prime numbers to calculate
    highest = input from the user that is passed to "max"
    
    An in-depth explanation of the Eratosthenes Sieve can be found on the internet.
    
    */
    
    //prototypes
    void start (void);
    void prime_calculator (unsigned long max);
    
    int main (void)
    {
    	start ();
    
    	return 0;
    }
    
    void start (void)
    {
    	unsigned long highest;
    
    	do
    	{
    		//input from user
    		printf ("\nType '0' to quit.");
    		printf ("\n\nPlease specify a max range to calculate prime numbers (up to 9000011).\n");
    		scanf ("%d", &highest);
    
    		//check input from user
    		if (highest < 0 || highest == 1 || highest > 9000011)
    		{
    			printf ("\n(Setting max range to 100)\n\n");
    			highest = 100;
    		}
    		
    		//if user doesn't enter zero, call prime_calculator
    		if (highest != 0)
    		{
    			prime_calculator (highest);
    		}
    
    	} while (highest != 0);
    }	
    
    void prime_calculator (unsigned long max)
    {
    	
    	unsigned long discard;
    	unsigned long count;
    
    	//Open & overwrite file for output
    	FILE *fp = fopen ("prime_numbers.txt", "w");
    
    	//Initialize the array
    	int *prime = malloc ((max+1)*sizeof(*prime));
    
    	if (!prime)
    	{
    		puts ("\n\nERROR! Not enough Memory!\n\n");
    		exit (1);
    	}
    
    	//initialize prime[max]
    	for (count = 0; count <= max; count++)
    	{
    		prime[count] = 1;
    	}
    
    	count = 0;
    	printf ("\nFinished initializing array.");
    
    	//Discard even composite numbers
    	for (discard = 4; discard <= max; discard = discard + 2)
    	{
    		prime[discard] = 0;
    	}
    	discard = 0;
    	printf ("\n\nFinished even discards.");
    
    	//Discard remaining composite numbers
    	count = 3;
    
    	do
    	{
    		for (discard = (int) pow(count,2); discard <= max; discard = discard + count * 2)
    		{
    			if (prime[discard] > 0)
    			{
    				prime[discard] = 0;
    			}
    		}
    		count++;
    	} while (pow(count,2) <= max);
    	count = 0;
    	discard = 0;
    	printf ("\n\nFinished all other discards.");
    
    	//Output
    	printf ("\n\nPrime Numbers between 2 and %d...\n", max);
    	for (count = 2; count <= max; count++)
    	{
    		if (prime[count] == 1)
    		{
    			printf ("%d ", count);
    			fprintf (fp,"\t%d", count);
    		}
    	}
    	count = 0;
    	fclose (fp);
    	free (prime);
    	printf ("\n\n");
    }

  2. #2
    Supermassive black hole cboard_member's Avatar
    Join Date
    Jul 2005
    Posts
    1,709
    I'm ........ at math, but I'll give it my best shot - someone please correct me

    discard is long, and you're casting the return value of pow to and int (the same effect as abs()?). This would cause the loss of everything after the decimal place?

    Sorry if it didn't help you, I'd like to know myself.
    Always willing to learn

    I think the double occurs when you pow count?
    Good class architecture is not like a Swiss Army Knife; it should be more like a well balanced throwing knife.

    - Mike McShaffry

  3. #3
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Just pay attention to the return values of the functions you use. pow's man page


    Quzah.
    Hope is the first step on the road to disappointment.

  4. #4
    Registered User
    Join Date
    May 2005
    Posts
    207
    I hope I'm not using decimals in prime number calculations... :-)

    Ok, I changed the type casting to (unsigned long) and still don't get any errors. I guess what I'm really wondering is why do I have to type cast at all?

    'count' is already declared as an unsigned long so it seems redundant to have to type cast it as the same data type when I take it to a power...

    mw

  5. #5
    Registered User
    Join Date
    May 2005
    Posts
    207
    Oh, I get it! The 'pow' function assumes a double data type. I would need to use 'powl' to get a long double data type (which I guess is as close as I'll get).

    My program will calculate prime numbers up to 9000011 (which is near the limit of my computer). Why was I able to type cast the 'pow' function as an 'int' and still get accurate calculations? I didn't verify all 900011 of the prime numbers, but I randomly verified the high-level numbers and they seemed to be correct.

    C is quite a bit too fast and loose for me... :-(

    mw

  6. #6
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Casting a floating point number to an integeral type will truncate anything past the decimal place, assuming the rest of the number is in range to fit in the integeral type.


    Quzah.
    Hope is the first step on the road to disappointment.

  7. #7
    Registered User
    Join Date
    May 2005
    Posts
    207
    Ok, I understand the concept of truncation, but I thought 'unsigned long' has a range of 0 to 4,294,967,295. I chose this data type because I wanted integer numbers that were greater than zero (ie: no decimals and no negative numbers).

    What am I missing? And why does using an 'int' data type give me correct calculations when it SHOULD be truncating? I just noticed that my pointer array is an 'int'?! An 'int' pointer array that has over 9 million elements should have some kind of truncation, right?

    mw

    PS: Why are you guys mentioning "everything past the decimal"? I'm not using decimals at all... ('powf' is a floating point, but that's not in my program)
    Last edited by Lionmane; 08-18-2005 at 01:55 PM.

  8. #8
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by Lionmane
    PS: Why are you guys mentioning "everything past the decimal"? I'm not using decimals at all... ('powf' is a floating point, but that's not in my program)
    No one said anything about powf. We've already told you more than once, and even provided a link. You still aren't paying attention:

    pow returns a double And you most definately are using that in your program:
    Code:
    do
    	{
    		for (discard = (int) pow(count,2); discard <= max; discard = discard + count * 2)
    		{
    			if (prime[discard] > 0)
    			{
    				prime[discard] = 0;
    			}
    		}
    		count++;
    	} while (pow(count,2) <= max);

    Quzah.
    Hope is the first step on the road to disappointment.

  9. #9
    Registered User
    Join Date
    May 2005
    Posts
    207
    Ok, I can understand that.

    That still doesn't answer why I can declare '*prime' as an int and have over 9 million elements without any problems. Or why I can typecast 'pow' as an int (using calculations in the millions) without any data loss.

    The problem I'm having is not that I'm getting errors; it's that I'm NOT getting errors when I think I should be.

    mw

  10. #10
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by Lionmane
    That still doesn't answer why I can declare '*prime' as an int and have over 9 million elements without any problems.
    Presumably because your machine has enough memory to ensure the malloc() call succeeds. If the malloc() call failed -- and it can fail if there isn't enough free memory -- you will have all sorts of problems. That's one reason why most people terminate if malloc() returns NULL.

    The other related factor is that the range of integers supported on your machine (represented by macros like INT_MAX) is presumably large enough to be able to represent values within the range you're working in.

    Quote Originally Posted by Lionmane
    Or why I can typecast 'pow' as an int (using calculations in the millions) without any data loss.
    That is the result of what values can be represented in an int, and what can be represented in a double. An int is typically 4 bytes, and a double is typically 8. Depending on how the two types are implemented (by your compiler, which may do it based on how your operating system does it, which [in turn] may do it based on how your hardware does it), it is not impossible that every possible value that can be represented in an int can be represented precisely in a double ON YOUR MACHINE. As the range of values that can be represented in an int and a double are implementation dependent, it is also quite possible the conversion from double to int will lose information on another machine. It is also possible (in fact, likely in practice) that it will lose information for large values but not for small ones. That is what your compiler is warning you about.

    Quote Originally Posted by Lionmane
    The problem I'm having is not that I'm getting errors; it's that I'm NOT getting errors when I think I should be.
    A warning is just that: a warning about something which MIGHT happen if the circumstances are right. The typecast does not make the possible loss of precision go way - it just stops the compiler compiler warning about it (as a typecast is essentially an instruction to the compiler of "I know what I'm doing; don't complain about this".

    Incidentally, rather than using "pow(count, 2)", why not use "count*count" or (if the resultant value may be larger than can be stored in an int), use "(long)count*count"?

  11. #11
    Registered User
    Join Date
    May 2005
    Posts
    207
    Ok, so here's the final question:

    Why is using powers in C such an unnecessary hassle? In QBasic, you would simply say:

    for count = (count ^ 2) to max step (count * 2)

    And be done with it. Why does C assume a particular data type for powers anyway? What idiot came up with that idea? Why can't the data type be defined by the user?

    mw

  12. #12
    aoeuhtns
    Join Date
    Jul 2005
    Posts
    581
    Quote Originally Posted by Lionmane
    Ok, so here's the final question:

    Why is using powers in C such an unnecessary hassle? In QBasic, you would simply say:

    for count = (count ^ 2) to max step (count * 2)

    And be done with it. Why does C assume a particular data type for powers anyway? What idiot came up with that idea? Why can't the data type be defined by the user?

    mw
    C operators generally map to processor instructions. Processors can add, multiply, bit-shifting, xor, etc, if you instruct them to do so. Most do not have an "exponent" instruction.

    Also, there are different types of exponentiation algorithms that can be used -- for floating point numbers, you would use logarithms, while exact exponents with integers might be implemented via a recursive function. An exponent operator would not fit in with the rest of the operators, since it would map to a function call, not a processor instruction. And since there are multiple ways of doing exponentiation, the function it maps to might not be the type of algorithm that users want.

    After all, if the language supports taking floating point powers, then it implicitly supports taking logarithms, as well. What kind of sick low-level programming language would have logarithms hidden behind one of its operators? And if it supports logarithms, then why isn't a log function also part of the programming language?

    In short, when it comes to C, exponentiation is something best left for the standard library. Adding an operator for it would be a mistake.
    Last edited by Rashakil Fol; 08-18-2005 at 06:39 PM.

  13. #13
    Registered User
    Join Date
    May 2005
    Posts
    207
    Ok, here's my new program. I've removed a couple of libraries (math.h & stdlib.h), toned down my data types and simplified my math for this retarded child.

    I can calculate approx 150% more prime numbers now without having to wait too long (ie: more than about 5 mins). The algorithm I'm using is extremely efficient, but creating a pointer with millions of elements is taxing.

    Any ideas? I was thinking of using a random access file as storage instead of a pointer. I can probably reach the limits of 'int' that way! :-)

    mw
    Code:
    #include<stdio.h>
    #include<malloc.h>
    
    /*
    
    This program calculates prime numbers using the Eratosthenes Sieve algorithm.  It will find the
    prime numbers between 2 & "max".  It overwrites the prime numbers to the file "prime_numbers.txt"
    in the same folder.
    
    Definitions:
    
    1) Prime Number: a positive integer with only 2 divisibles (itself & 1); the number "1" is not
    	considered a prime number in this program
    2) Composite Number: a number with more than 2 divisibles
    
    Variable key:
    
    highest = input from the user that is passed to "max"
    max = the maximum range of prime numbers to calculate
    prime[max] = a pointer array that stores all of the numbers in the "max" range
    discard = this is used to calculate composite numbers
    count = a variable I use to count with
    
    An in-depth explanation of the Eratosthenes Sieve can be found on the internet.
    
    */
    
    //prototypes
    void start_prime (void);
    int prime_calculator (int max);
    
    int main (void)
    {
    	start_prime ();
    
    	return 0;
    }
    
    void start_prime (void)
    {
    	int highest;
    
    	do
    	{
    		//Input from user
    		printf ("\n\n*WARNING*  Enter '0' to quit if you don't want to overwrite your output file!!");
    		printf ("\n\nPlease specify a max range to calculate prime numbers (up to 21,000,000).\n");
    		scanf ("%d", &highest);
    
    		//Weed killer
    		if (highest < 0 || highest == 1 || highest > 21000000)
    		{
    			printf ("\n(Setting max range to 100)\n");
    			highest = 100;
    		}
    		
    		//Call prime_calculator function
    		if (highest != 0)
    		{
    			prime_calculator (highest);
    		}
    
    	} while (highest != 0);
    	printf ("\n");
    }	
    
    int prime_calculator (int max)
    {
    	int discard;
    	int count;
    
    	//Open and overwrite file for output
    	FILE *fp = fopen ("prime_numbers.txt", "w");
    
    	//Declare pointer array
    	int *prime = malloc ((max+1)*sizeof(*prime));
    
    	if (!prime)
    	{
    		puts ("\n\nERROR! Not enough Memory!\n\n");
    		return (0);
    	}
    	printf ("\nFinished declaring pointer array (step 1 of 4)...");
    
    	//Initialize pointer array
    	prime[0] = 0;
    	prime[1] = 0;
    	for (count = 2; count <= max; count++)
    	{
    		prime[count] = 1;
    	}
    	count = 0;
    	printf ("\n\nFinished initializing pointer array (step 2 of 4)...");
    
    	//Discard even numbers
    	for (discard = 4; discard <= max; discard = discard + 2)
    	{
    		prime[discard] = 0;
    	}
    	discard = 0;
    	printf ("\n\nFinished even discards (step 3 of 4)...");
    
    	//Discard remaining composite numbers using the Eratosthenes Sieve
    	count = 3;
    	do
    	{
    		for (discard = count * count; discard <= max; discard = discard + count * 2)
    		{
    			if (prime[discard] > 0)
    			{
    				prime[discard] = 0;
    			}
    		}
    		count++;
    	} while (count * count <= max);
    	count = 0;
    	discard = 0;
    	printf ("\n\nFinished the Eratosthenes Sieve (step 4 of 4)...");
    
    	//Output and closing for this function call
    	printf ("\n\nPrime Numbers between 2 and %d:\n", max);
    	if (max > 5500)
    	{
    		printf ("** Too many to print on screen! **");
    	}
    	for (count = 2; count <= max; count++)
    	{
    		if (prime[count] == 1)
    		{
    			if (max <= 5500)
    			{
    				printf ("%d ", count);
    			}
    			fprintf (fp,"\t%d", count);
    		}
    	}
    	count = 0;
    	max = 0;
    	free (prime);
    	fclose (fp);
    
    	printf ("\n\n");
    	return (0);
    }
    Last edited by Lionmane; 08-19-2005 at 12:23 PM.

  14. #14
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,005
    I twiddled with some micro-optimizing such as using calloc instead of malloc and the initialization loop (then you need to change your 0/1 logic too). This made it run about twice as fast for my little attempt.

    But as the wisdom goes, it's probably better to improve the algorithm. The Sieve of Atkin is supposed to be an optimized version of the Sieve of Eratosthenes. I found an implementation here, but didn't do much with it.
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

  15. #15
    Registered User
    Join Date
    May 2005
    Posts
    207
    Hey, thanks Dave! That gave me an idea!

    I combined the initialization and the even-number discard loops!

    mw

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. What dose this type casting mean??
    By zhoufanking in forum C Programming
    Replies: 4
    Last Post: 06-11-2008, 06:09 AM
  2. Replies: 0
    Last Post: 03-20-2008, 07:59 AM
  3. pointer to array of objects of struct
    By undisputed007 in forum C++ Programming
    Replies: 12
    Last Post: 03-02-2004, 04:49 AM
  4. Erros in Utility Header File
    By silk.odyssey in forum C++ Programming
    Replies: 4
    Last Post: 12-22-2003, 06:17 AM
  5. help with simple type casting problem
    By Jeremy_S in forum C Programming
    Replies: 2
    Last Post: 02-27-2002, 12:38 PM