Reputation: 381
Please consider the following simple program. When I compile this with compile : gcc -o test test.c
I get lots of warning: integer overflow in expression [-Woverflow]
warnings. I don't understand why I get these warnings.
Note that the variable Q is 31 bits long. I have tried typecasting to uint64_t
but without any solution. Interestingly if I remove the #define Q ( (1<<k1) - (1<<k2) + 1 )
and write the numericalvalue of Q as uint64_t Q=2130706433;
Then most of the warnings messages are gone but still I get one warning message for m=( m& (k1_minus_one) ) + ( ((m>>k1)<<k2) - (m>>k1) );
. If I put the numerical value the code works as expected in spite of the warnings, however with the former #define
statement the code does not work. I am using gcc (Ubuntu 6.5.0-2ubuntu1~16.04) 6.5.0 20181026
Can you please tell me what could be the possible source of this problem and possible solutions?
#include<stdio.h>
#include<stdint.h>
#include<stdlib.h>
//compile : gcc -o test test.c
#define N 1024
#define k1 31
#define k2 24
void mul_mod_large(uint64_t *a, uint64_t *b, uint64_t *c);
void get_arr(uint64_t *a, uint64_t q, uint64_t n);
#define k1_minus_one ( (1<<k1)-1 )
#define Q ( (1<<k1) - (1<<k2) + 1 )
//uint64_t Q=2130706433;
void main(){
}
void mul_mod_large(uint64_t *a, uint64_t *b, uint64_t *c){
uint64_t i, m;
for(i=0;i<N;i++){
m=a[i]*b[i];
while(m>(2*Q)){
m=( m& (k1_minus_one) ) + ( ((m>>k1)<<k2) - (m>>k1) );
}
c[i]=m;
if(m>=Q){
c[i]=m-Q;
}
}
}
Upvotes: 0
Views: 113
Reputation: 381
As many suggested the problem arose due to the default limit of C for #define constants which is int32. So If I put U
after the 1
's the problem is solved.
#define k1_minus_one ( (1U<<k1)-1 )
#define Q ( (1U<<k1) - (1U<<k2) + 1 )
The above code gives no warnings and runs without errors.
As mentioned in the comments by @Ian Abbott, instead of putting U after 1s writing UINT32_C(1) gives a better and more generic soultion.
Upvotes: 0
Reputation: 12708
The numbers in a signed
32 bit numer in two's complement varie from -2^31
to 2^31 - 1
.
You are using the subexpression (1 << 31)
which is effectively equivalent to 2^31
, which is one plus than the maximum int
you can store in your computer. Even if you later subtract one, the partial result (1 << 31)
is out of range. Unluckily, signed numbers overflow is Undefined Behaviour in C, so you can get the desired result, or you can receive a completely different behaviour (like crashing or aborting your program). That is the reason for the warning you get. You can get the maximum number in other ways, but the most effective is to simply use 0x7fffffff
, or
#include <limits.h>
...
INT_MAX /* this is very safe :) */
or
(((1 << 30) - 1) << 1) + 1)
(this last example builds 2^31 - 1
by multiplying by 2 the number 2^30 - 1
and adding one to the result, and that's safe)
Upvotes: 1