My C-Program performs a "Turmrechnung"(A predefined number("init_num" gets multiplied with a predefined range of numbers(init_num*2*3*4*5*6*7*8*9 in my case, defined by the variable "h"), and after that it is divided by those same numbers and the result should be the initial value of "init_num". My task is to integrate a way to stop the calculation if the value of init_num becomes larger than INT_MAX(from limits.h).
But the If-Statement is always true, even if it is not, in case of a larger initial value of "init_num", which results in values bigger than INT_MAX along the way of the calculation.
It only works if i replace "INT_MAX" with a smaller number than INT_MAX like 200000000 in my If-Statement. Why?
#include <limits.h>
#include <stdio.h>
int main() {
int init_num = 1000000;
int h = 9;
for (int i = 2; i < h+1; ++i)
{
if (init_num * i < INT_MAX)
{
printf("%10i %s %i\n", init_num, "*", i);
init_num *= i;
}
else
{
printf("%s\n","An overflow has occurred!");
break;
}
}
for (int i = 2; i < h+1; ++i)
{
printf("%10i %s %i\n", init_num, ":", i);
init_num /= i;
}
printf("%10i\n", init_num);
}
if (init_num * i < INT_MAX)
INT_MAX is the maximum value of int , therefore , this condition will never be false or in other words 0 (except when it is equal to INT_MAX).
If you want you can write your condition like this -
if (init_num < INT_MAX/i)
init_num * i < INT_MAX will only be 0 if int_num * i is INT_MAX. This is not particularly likely. Note that signed integer overflow is undefined behaviour in C, so do be particularly careful here.
You can rewrite your statement to init_num < INT_MAX / i in your particular case. Do note that integer division truncates though.
The problem is signed integer overflow is undefined behaviour. Concentrate on the "undefined" part and think about it. Briefly: avoid under all circumstances.
To avoid this, you can either use a devinitively wider type which is gauranteed to hold the result of the multiplication and then test:
// ensure the type we use for cast is large enough
_Static_assert(LLONG_MAX > INT_MAX, "LLONG too small.");
if ( (long long)init_num * i < (long long)INT_MAX )
This apparently does not work is you are already at the limit (i.e. use the largest data type). So you have to check in advance:
if ( init_num < (INT_MAX / i) ) {
init_num *= i;
Although more time-consuming due to the extra division, this is in general the better approach, as it does not require a larger data type (where multiplication might be also more expensive).
init_num * int
results in an int and though cannot grow beyond a maximum possible int (INT_MAX) by defintion.
So provide "room" for calculations "larger" than an int by replacing
if (init_num * i < INT_MAX)
with
if ((long) init_num * i < (long) INT_MAX)
The casting to long leads to a long result.
(The above approach assumes long being wider then int.)
Related
Here is a code snippet:
unsigned int m,n,a;
long long int c,p=0,q=0;
scanf("%u%u%u",&m,&n,&a);
while(m>0){
m-=a;
p++;
}
while(n>0){
n-=a;
q++;
}
c=p*q;
printf("%lld",c);
The above code does not work for any input. That is, it seems like it has crashed,though I could not understand where I'm mistaken. I guess the part with %lld in the printf has problems. But Ido not know how to fix it. I'm using code blocks.
Some expected outputs for corresponding inputs are as follows:
Input: 6 6 4
Output: 4
Input: 1000000000 1000000000 1
Output: 1000000000000000000(10^18).
APPEND:
So, I'm giving the link of the main problem below. The logic of my code seemed correct to me.
https://codeforces.com/contest/1/problem/A
As it's been pointed out in comments/answers the problem is that m and n is unsigned so your loops can only stop if m and n are a multiple of a.
If you look at the input 6 6 4 (i.e. m=6 and a=4), you can see that m first will change like m = 6 - 4 which leads to m being 2. So in the next loop m will change like m = 2 - 4 which should be -2 but since m is unsigned it will wrap to a very high positive number (i.e. UINT_MAX-1) and the loop will continue. That's not what you want.
To fix it I'll suggest you drop the while loops and simply do:
unsigned int m,n,a;
long long unsigned int c,p=0,q=0;
scanf("%u%u%u",&m,&n,&a);
p = (m + a - 1)/a; // Replaces first while
q = (n + a - 1)/a; // Replaces second while
c=p*q;
printf("%lld",c);
One problem with this solution is that the sum (m + a - 1) may overflow (i.e. be greater than UINT_MAX) and therefore give wrong results. You can fix that by adding an overflow check before doing the sum.
Another way to protect against overflow could be:
p = 1; // Start with p=1 to handle m <= a
if (m > a)
{
m -= a; // Compensate for the p = 1 and at the same time
// ensure that overflow won't happen in the next line
p += (m + a - 1)/a;
}
This code can then be reduced to:
p = 1;
if (m > a)
{
p += (m - 1)/a;
}
while(m>0){
m-=a;
p++;
}
will run until m is equal to 0, since it cannot be negative because it is unsigned. So if m is 4 and a is 6, then m will underflow and get the maximum value that m can hold minus 2. You should change the input variables to signed.
4386427 shows how you can use math to remove the loops completely, but for the more general case, you can do like this:
while(m > a) {
m-=a;
p++;
}
// The above loop will run one iteration less
m-=a;
p++;
Of course, you need to do the same thing for the second loop.
Another thing, check return value of scanf:
if(scanf("%u%u%u",&m,&n,&a) != 3) {
/* Handle error */
}
Using an unsigned type isn't always the best choice to represent positive values, expecially when its modular behavior is not needed (and maybe forgotten, which leads to "unexpected" bugs). OP's use case requires an integral type capable of store a value of maximum 109, which is inside the range of a 32-bit signed integer (a long int to be sure).
As 4386427's answer shows, the while loops in OP's code may (and should) be avoided anyways, unless a "brute force" solution is somehow required (which is unlikely the case, given the origin of the question).
I'd use a function, though:
#include <stdio.h>
// Given 1 <= x, a <= 10^9
long long int min_n_of_tiles_to_pave_an_edge(long int x, long int a)
{
if ( x > a ) {
// Note that the calculation is performed with 'long' values and only after
// the result is casted to 'long long', when it is returned
return 1L + (x - 1L) / a;
}
else {
return 1LL;
}
}
int main(void)
{
// Given a maximum value of 10^9, a 32-bit int would be enough.
// A 'long int' (or 'long') is guaranteed to be capable of containing at
// least the [−2,147,483,647, +2,147,483,647] range.
long int m, n, a;
while ( scanf("%ld%ld%ld", &m, &n, &a) == 3 )
{
// The product of two long ints may be too big to fit inside a long.
// To be sure, performe the multiplication using a 'long long' type.
// Note that the factors are stored in the bigger type, not only the
// result.
long long int c = min_n_of_tiles_to_pave_an_edge(m, a)
* min_n_of_tiles_to_pave_an_edge(n, a);
printf("%lld\n",c);
}
}
I am trying to find the largest prime factor of a huge number in C ,for small numbers like 100 or even 10000 it works fine but fails (By fail i mean it keeps running and running for tens of minutes on my core2duo and i5) for very big target numbers (See code for the target number.)
Is my algorithm correct?
I am new to C and really struggling with big numbers. What i want is correction or guidance not a solution i can do this using python with bignum bindings and stuff (I have not tried yet but am pretty sure) but not in C. Or i might have done some tiny mistake that i am too tired to realize , anyways here is the code i wrote:
#include <stdio.h>
// To find largest prime factor of target
int is_prime(unsigned long long int num);
long int main(void) {
unsigned long long int target = 600851475143;
unsigned long long int current_factor = 1;
register unsigned long long int i = 2;
while (i < target) {
if ( (target % i) == 0 && is_prime(i) && (i > current_factor) ) { //verify i as a prime factor and greater than last factor
current_factor = i;
}
i++;
}
printf("The greates is: %llu \n",current_factor);
return(0);
}
int is_prime (unsigned long long int num) { //if num is prime 1 else 0
unsigned long long int z = 2;
while (num > z && z !=num) {
if ((num % z) == 0) {return 0;}
z++;
}
return 1;
}
600 billion iterations of anything will take some non-trivial amount of time. You need to substantially reduce this.
Here's a hint: Given an arbitrary integer value x, if we discover that y is a factor, then we've implicitly discovered that x / y is also a factor. In other words, factors always come in pairs. So there's a limit to how far we need to iterate before we're doing redundant work.
What is that limit? Well, what's the crossover point where y will be greater than x / y?
Once you've applied this optimisation to the outer loop, you'll find that your code's runtime will be limited by the is_prime function. But of course, you may apply a similar technique to that too.
By iterating until the square root of the number, we can get all of it's factors.( factor and N/factor and factor<=sqrt(N)). Under this small idea the solution exists. Any factor less than the sqrt(N) we check, will have corresponding factor larger than sqrt(N). So we only need to check up to the sqrt(N), and then we can get the remaining factors.
Here you don't need to use explicitly any prime finding algorithm. The factorization logic itself will deduce whether the target is prime or not. So all that is left is to check the pairwise factors.
unsigned long long ans ;
for(unsigned long long i = 2; i<=target/i; i++)
while(target % i == 0){
ans = i;
target/=i;
}
if( target > 1 ) ans = target; // that means target is a prime.
//print ans
Edit: A point to be added (chux)- i*i in the earlier code is may lead to overflow which can be avoided if we use i<=target/i.
Also another choice would be to have
unsigned long long sqaure_root = isqrt(target);
for(unsigned long long i = 2; i<=square_root; i++){
...
}
Here note than use of sqrt is not a wise choice since -
mixing of double math with an integer operation is prone to round-off errors.
For target given the answer will be 6857.
Code has 2 major problems
The while (i < target) loop is very inefficient. Upon finding a factor, target could be reduced to target = target / i;. Further, a factor i could occur multiple times. Fix not shown.
is_prime(n) is very inefficient. Its while (num > z && z !=num) could loop n time. Here too, use the quotient to limit the iterations to sqrt(n) times.
int is_prime (unsigned long long int num) {
unsigned long long int z = 2;
while (z <= num/z) {
if ((num % z) == 0) return 0;
z++;
}
return num > 1;
}
Nothing is wrong, it just needs optimization, for example:
int is_prime(unsigned long long int num) {
if (num == 2) {
return (1); /* Special case */
}
if (num % 2 == 0 || num <= 1) {
return (0);
}
unsigned long long int z = 3; /* We skipped the all even numbers */
while (z < num) { /* Do a single test instead of your redundant ones */
if ((num % z) == 0) {
return 0;
}
z += 2; /* Here we go twice as fast */
}
return 1;
}
Also the big other problem is while (z < num) but since you don't want the solution i let you find how to optimize that, similarly look out by yourself the first function.
EDIT: Someone else posted 50 seconds before me the array-list of primes solution which is the best but i chose to give an easy solution since you are just a beginner and manipulating arrays may not be easy at first (need to learn pointers and stuff).
is_prime has a chicken-and-egg problem in that you need to test num only against other primes. So you don't need to check against 9 because that is a multiple of 3.
is_prime could maintain an array of primes and each time a new num is tested that is a pime, it can be added to the array. num isr tested against each prime in the array and if it is not divisable by any of the primes in the array, it is itself a prime and is added to the array. The aray needs to be malloc'd and relloc'd unless there is a formue to calculate the number of primes up intil your target (I believe such formula does not exist).
EDIT: the number of primes to test for the target 600,851,475,143 will be approximately 7,500,000,000 and the table could run out of memory.
The approach can be adapted as follows:
to use unsiged int up until primes of UINT_max
to use unsigned long long int for primes above that
to use brute force above a certain memory consumption.
UINT_MAX is defined as 4,294,967,295 and would cover the primes up to around 100,000,000,000 and would cost 7.5*4= 30Gb
See also The Prime Pages.
I was working on Exercise 2-1 of K&R, the goal is to calculate the range of different variable types, bellow is my function to calculate the maximum value a short int can contain:
short int max_short(void) {
short int i = 1, j = 0, k = 0;
while (i > k) {
k = i;
if (((short int)2 * i) > (short int)0)
i *= 2;
else {
j = i;
while (i + j <= (short int)0)
j /= 2;
i += j;
}
}
return i;
}
My problem is that the returned value by this function is: -32768 which is obviously wrong since I'm expecting a positive value. I can't figure out where the problem is, I used the same function (with changes in the variables types) to calculate the maximum value an int can contain and it worked...
I though the problem could be caused by comparison inside the if and while statements, hence the typecasting but that didn't help...
Any ideas what is causing this ? Thanks in advance!
EDIT: Thanks to Antti Haapala for his explanations, the overflow to the sign bit results in undefined behavior NOT in negative values.
You can't use calculations like this to deduce the range of signed integers, because signed integer overflow has undefined behaviour, and narrowing conversion at best results in an implementation-defined value, or a signal being raised. The proper solution is to just use SHRT_MAX, INT_MAX ... of <limits.h>. Deducing the maximum value of signed integers via arithmetic is a trick question in standardized C language, and has been so ever since the first standard was published in 1989.
Note that the original edition of K&R predates the standardization of C by 11 years, and even the 2nd one - the "ANSI-C" version predates the finalized standard and differs from it somewhat - they were written for a language that wasn't almost, but not quite, entirely unlike the C language of this day.
You can do it easily for unsigned integers though:
unsigned int i = -1;
// i now holds the maximum value of `unsigned int`.
Per definition, you cannot calculate the maximum value of a type in C, by using variables of that very same type. It simply doesn't make any sense. The type will overflow when it goes "over the top". In case of signed integer overflow, the behavior is undefined, meaning you will get a major bug if you attempt it.
The correct way to do this is to simply check SHRT_MAX from limits.h.
An alternative, somewhat more questionable way would be to create the maximum of an unsigned short and then divide that by 2. We can create the maximum by taking the bitwise inversion of the value 0.
#include <stdio.h>
#include <limits.h>
int main()
{
printf("%hd\n", SHRT_MAX); // best way
unsigned short ushort_max = ~0u;
short short_max = ushort_max / 2;
printf("%hd\n", short_max);
return 0;
}
One note about your code:
Casts such as ((short int)2*i)>(short int)0 are completely superfluous. Most binary operators in C such as * and > implement something called "the usual arithmetic conversions", which is a way to implicitly convert and balance types of an expression. These implicit conversion rules will silently make both of the operands type int despite your casts.
You forgot to cast to short int during comparison
OK, here I assume that the computer would handle integer overflow behavior by changing into negative integers, as I believe that you have assumed in writing this program.
code that outputs 32767:
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
short int max_short(void)
{
short int i = 1, j = 0, k = 0;
while (i>k)
{
k = i;
if (((short int)(2 * i))>(short int)0)
i *= 2;
else
{
j = i;
while ((short int)(i + j) <= (short int)0)
j /= 2;
i += j;
}
}
return i;
}
int main() {
printf("%d", max_short());
while (1);
}
added 2 casts
I am reading Carnegie Mellon slides on computer systems for my quiz. In the slide page 49 :
Counting Down with Unsigned
Proper way to use unsigned as loop index
unsigned i;
for (i = cnt-2; i < cnt; i--)
a[i] += a[i+1];
Even better
size_t i;
for (i = cnt-2; i < cnt; i--)
a[i] += a[i+1];
I don't get why it's not going to be infinite loop. I am decrementing i and it is unsigned so it should be always less than cnt. Please explain.
The best option for down counting loops I have found so far is to use
for(unsigned i=N; i-->0; ) { }
This invokes the loop body with i=N-1 ... 0. This works the same way for both signed and unsigned data types and does not rely on any overflows.
This loop is simply relying on the fact that i will be decremented past 0, which makes it the max uint value. Which breaks the loop because now i < cnt == false.
Per Overflowing of Unsigned Int:
unsigned numbers can't overflow, but instead wrap around using the
properties of modulo.
Both the C and C++ standard guarantee this uint wrapping behavior, but it's undefined for signed integers.
The goal of the loops is to loop from cnt-2 down to 0. It achieves the effect of writing i >= 0.
The previous slide correctly talks about why a loop condition of i >= 0 doesn't work. Unsigned numbers are always greater than or equal to 0, so such a condition would be vacuously true. A loop condition of i < cnt ends up looping until i goes past 0 and wraps around. When you decrement an unsigned 0 it becomes UINT_MAX (232 - 1 for a 32-bit integer). When that happens, i < cnt is guaranteed to be false, and the loop terminates.
I would not write loops like this. It is technically correct but very poor style. Good code is not just correct, it is readable, so others can easily figure out what it's doing.
It's taking advantage of what happens when you decrement unsigned integer 0. Here's a simple example.
unsigned cnt = 2;
for (int i = 0; i < 5; i++) {
printf("%u\n", cnt);
cnt--;
}
That produces...
2
1
0
4294967295
4294967294
Unsigned integer 0 - 1 becomes UINT_MAX. So instead of looking for -1, you watch for when your counter becomes bigger than its initial state.
Simplifying the example a bit, here's how you can count down to 0 from 5 (exclusive).
unsigned i;
unsigned cnt = 5;
for (i = cnt-1; i < cnt; i--) {
printf("%d\n", i);
}
That prints:
4
3
2
1
0
On the final iteration i = UINT_MAX which is guaranteed to be larger than cnt so i < cnt is false.
size_t is "better" because it's unsigned and it's as big as the biggest thing in C, so you don't have to ensure that cnt is the same type as i.
This appears to be an alternative expression of the established idiom for implementing the same thing
for (unsigned i = N; i != -1; --i)
...;
They simply replaced the more readable condition of i != -1 with a slightly more cryptic i < cnt. When 0 is decremented in the unsigned domain it actually wraps around to the UINT_MAX value, which compares equal to -1 (in the unsigned domain) and which is greater than or equal to cnt. So, either i != -1 or i < cnt works as a condition for continuing iterations.
Why would they do it that way specifically? Apparently because they start from cnt - 2 and the value of cnt can be smaller than 2, in which case their condition does indeed work properly (and i != -1 doesn't). Aside from such situations there's no reason to involve cnt into the termination condition. One might say that an even better idea would be to pre-check the value of cnt and then use the i != -1 idiom
if (cnt >= 2)
for (unsigned i = cnt - 2; i != -1; --i)
...;
Note, BTW, that as long as the starting value of i is known to be non-negative, the implementation based on the i != -1 condition works regardless of whether i is signed or unsigned.
I think you are confused with int and unsigned int data types. These two are different. In the int datatype (2 byte storage size), you have its range from -32,768 to 32,767 whereas in the unsigned int datatype (2 byte storage size). you have the range from 0 to 65,535 .
In the above example mentioned, you are using the variable i of type unsigned int. It will decrements up to i=0 and then ends the for loop as per the semantics.
I have a problem that is, when I sum the values of an array (that are all positive, I verified by printing the values of the array), I end up with a negative value. My code for the sum is:
int summcp = 0;
for (k = 0; k < SIMUL; k++)
{
summcp += mcp[k];
}
printf("summcp: %d.\n", summcp);`
Any hint about this problem would be appreciated.
You are invoking undefined behaviour.
As integer variables can only hold a limited range of values, going beyond this range is undefined by the standard. Basically anything can happen. In your (and the most common) case, it simply wraps around its binary representation. As this is used for negative values, you will read this as such.
To circomvent this, use a type for summcp which can hold all possible values. An alternative would be to check if the next addition will overflow by:
if ( summcp >= INT_MAX - mcp[k] ) {
// handle positive overflow
}
Note that the above only works for mcp[k] >= 0 and positive overflow. The other 3 cases have to be handled differently. It is in general best, faster and much easier to use a large enough type for the sum and test lateron for overflow, if required.
Do not feel tempted to add and test the result!. As integer overflow is undefined behaviour, this will not work for all architectures.
This smells like an overflow issue; you might want to add a check against that like
for (k = 0; k < SIMUL && (INT_MAX - summcp > mcp[k]); k++ )
{
sumcp += mcp[k];
}
if (k < SIMUL)
{
// sum of all mcp values is larger than what an int can represent
}
else
{
// use summcp
}
If you are running into overflow issues, you might want to use a wider type for summcp like long or long long.
EDIT
The problem is that the behavior of signed integer overflow is not well-defined; you'll get a different result for INT_MAX + 1 based on whether your platform uses one's complement, two's complement, sign magnitude, or some other representation for signed integers.
Like I said in my comment below, if mcp can contain negative values, you should add a check for underflow as well.
Regardless of the type you use (int, long, long long), you should keep the over- and underflow checks.
If mcp only ever contains non-negative values, then consider using an unsigned type for your sum. The advantage of this is that the behavior of unsigned integer overflow is well-defined, and the result will be the sum of all elements of mcp modulo UINT_MAX (or ULONG_MAX, or ULLONG_MAX, etc.).
Declare variable summcp like
long long int summcp = 0;
I think your final output is going out of range. For this you will have to declare summcp as long long int
long long int summcp = 0;
for (k = 0; k < SIMUL; k++)
{
summcp += mcp[k];
}
printf("summcp: %lld.\n", summcp);
int variable throws garbage value if its range is exceeded.