int divided by unsigned int causing rollover - c

I try to divide int by unsigned int and I get unexpected result:
int b;
unsigned int c;
int res;
float res_f;
b = -25;
c = 5;
res = b / c; // res = 858993454
res_f = b / c; // res_f = -5.000000
The same works just fine for '+', '-' and '*', but fails for '/'. What is it that I miss here?
P.S.
It was tested on different compilers and the result was the same.

Assuming this is C or similar (e.g. Objective C), change:
res = b / c;
to:
res = b / (int)c;
Explanation: b is being converted from int to unsigned int, according to C's type conversion rules for mixed expressions. In the process it overflows from -25 to 0xFFFFFFE7 == 4294967271. Then you get an unsigned int result of 4294967271 / 5U = 858993454U, which is then being implicitly converted back to an int (no overflow in this step, as the result is in the range of both signed and unsigned 32-bit ints).
By the way, the float result should be the same, within the precision limits of a float (I get 858993472.0). I'm surprised that you get -5.0 in this case.

Related

Finding modulus with very large exponentiation and divisor in C

I need a function in C that calculates a^n mod q, where the divisor q is determined to be very big (15,383,399,235,709,406,497) and the exponent n may also be as large as that.
Based on the property of modulo multiplication, that (a * b) mod n = ((a mod n) * (b mod n)) mod n, my attempt is as follows:
#include <stdio.h>
unsigned long long int modExp(unsigned long long int base, unsigned long long int expo, unsigned long long int mod)
{
unsigned long long int out = 1;
unsigned long long int cnt;
for (cnt=expo; cnt>0; cnt--)
{
out = (out * base) % mod;
}
return out;
}
int main()
{
printf("%llu", modExp(3, (189 + 50 * 223), 15383399235709406497));
return 0;
}
As seen in the main function above, I tested my function modExp with base 3, exponent (189 + 50 * 223), and divisor 15383399235709406497. It gave the output 3915400295876975163 with some warnings that
In function ‘findxA’:
findxA.c:17:32: warning: integer constant is so large that it is unsigned [enabled by default]
unsigned long long int h = 12036625823877237123;
^
findxA.c:17:5: warning: this decimal constant is unsigned only in ISO C90 [enabled by default]
unsigned long long int h = 12036625823877237123;
^
findxA.c:18:32: warning: integer constant is so large that it is unsigned [enabled by default]
unsigned long long int q = 15383399235709406497;
^
findxA.c:18:5: warning: this decimal constant is unsigned only in ISO C90 [enabled by default]
unsigned long long int q = 15383399235709406497;
^
findxA.c: In function ‘main’:
findxA.c:34:48: warning: integer constant is so large that it is unsigned [enabled by default]
printf("%llu", modExp(3, (189 + 50 * 223), 15383399235709406497));
^
findxA.c:34:5: warning: this decimal constant is unsigned only in ISO C90 [enabled by default]
printf("%llu", modExp(3, (189 + 50 * 223), 15383399235709406497));
^
To verify this answer, I compared the result (given by the C function) with the output given by evaluating the expression 3^(189 + 50 * 223) `mod` 15383399235709406497, written in Haskell. This Haskell expression evaluated to a different decimal, 12349118475990906085. I think it is my C function that is wrong, since I believe Haskell does a better job at handling such large decimals.
How can I improve my C function, modExp?
Edit: I have tried the option of the first answer of this question. However, as I am trying to deal with the decimal of unsigned long long int, I have switched every input and return types from int to unsigned long long int. This resulted in a Segmentation fault.
Edit2: I have used the function described on the above link in a wrong way. It does not give Segmentation fault; but it still does not output the correct decimal.
To reduce the chance of overflow, you can rely on (x*y)%z == ((x%z) * (y%z)) % z.
For example (untested):
unsigned long long int modExp(unsigned long long int base, unsigned long long int expo, unsigned long long int mod)
{
unsigned long long int baseMod = base%mod;
unsigned long long int out = 1;
unsigned long long int cnt;
for (cnt=expo; cnt>0; cnt--)
{
out = ( (out%mod) * baseMod) % mod;
}
return out;
}
Also note that exponentiation can be done more efficiently as "product of squares". For example, x ** 5 == 1*(x**4) * 0*(x**2) * 1*(x**1) because 5 == 1*4 + 0*2 + 1*1 (or 5 == 101b).
For example (untested):
unsigned long long int modExp(unsigned long long int base, unsigned long long int expo, unsigned long long int mod)
{
unsigned long long int out = 1;
unsigned long long int temp = base%mod;
while(exp0 > 0) {
if( (exp0 & 1) != 0) {
out = (out * temp) % mod;
}
temp = (temp*temp) % mod;
exp0 >>= 1;
}
return out;
}
For large exponents this should make a huge difference in performance (e.g. if the exponent is 123456 then the loop would have 17 iterations instead of 123456 iterations).
Also; if this is for some kind of cryptography (not unlikely); then you should state that clearly because you will probably want "constant time" (to reduce the chance of timing side-channels - e.g. inferring information about the exponent from how much time modExp() takes to execute).
Finally; even with the changes, numbers up to 15,383,399,235,709,406,497 are probably too large for unsigned long long (you'd need to ensure mod * mod <= ULLONG_MAX); which means that you'll probably need to use/implement "big integer" operations (e.g. maybe a typedef struct { uint32_t digit[4]; } MY_NUMBER_TYPE thing to handle 128-bit integers, with functions for multiplication and modulo).
This will never work this way!
This result of the multiplication here alone
out = (out * base) % mod;
needs potentially more than the 64 bit of the underlying data type. And if an integer overflow occurs (ie, the most significant bits get cut off), the mod operation turns out wrong!
Use larger data types, or use a different approach :-)
If you like, btw, please use this test code to see that there is actually an integer overflow occuring TWICE with your inputs:
#include <stdio.h>
unsigned long long int modExp(unsigned long long int base, unsigned long long int expo, unsigned long long int mod)
{
unsigned long long int out = 1;
while(expo>0)
{
if(expo % 2 == 1)
out = (out * base) % mod;
expo = expo >> 1;
if (base * base < base) printf("WARNING! INTEGER OVERFLOW!!!!\n");
base = (base * base) % mod;
}
return out;
}
int main()
{
printf("%llu", modExp(3, (189 + 50 * 223), 15383399235709406497));
return 0;
}

Error on casting unsigned int to float

For the following program.
#include <stdio.h>
int main()
{
unsigned int a = 10;
unsigned int b = 20;
unsigned int c = 30;
float d = -((a*b)*(c/3));
printf("d = %f\n", d);
return 0;
}
It is very strange that output is
d = 4294965248.000000
When I change the magic number 3 in the expression to calculate d to 3.0, I got correct result:
d = 2000.000000
If I change the type of a, b, c to int, I also got correct result.
I guess this error occurred by the conversion from unsigned int to float, but I do not know details about how the strange result was created.
I think you realize that you casting minus to unsigned int before assignment to float. If you run the below code, you will get highly likely 4294965296
#include <stdio.h>
int main()
{
unsigned int a = 10;
unsigned int b = 20;
unsigned int c = 30;
printf("%u", -((a*b)*(c/3)));
return 0;
}
The -2000 to the right of your equals sign is set up as a signed
integer (probably 32 bits in size) and will have the hexadecimal value
0xFFFFF830. The compiler generates code to move this signed integer
into your unsigned integer x which is also a 32 bit entity. The
compiler assumes you only have a positive value to the right of the
equals sign so it simply moves all 32 bits into x. x now has the
value 0xFFFFF830 which is 4294965296 if interpreted as a positive
number. But the printf format of %d says the 32 bits are to be
interpreted as a signed integer so you get -2000. If you had used
%u it would have printed as 4294965296.
#include <stdio.h>
#include <limits.h>
int main()
{
float d = 4294965296;
printf("d = %f\n\n", d);
return 0;
}
When you convert 4294965296 to float, the number you are using is long to fit into the fraction part. Now that some precision was lost. Because of the loss, you got 4294965248.000000 as I got.
The IEEE-754 floating-point standard is a standard for representing
and manipulating floating-point quantities that is followed by all
modern computer systems.
bit 31 30 23 22 0
S EEEEEEEE MMMMMMMMMMMMMMMMMMMMMMM
The bit numbers are counting from the least-significant bit. The first
bit is the sign (0 for positive, 1 for negative). The following
8 bits are the exponent in excess-127 binary notation; this
means that the binary pattern 01111111 = 127 represents an exponent
of 0, 1000000 = 128, represents 1, 01111110 = 126 represents
-1, and so forth. The mantissa fits in the remaining 24 bits, with
its leading 1 stripped off as described above. Source
As you can see, when doing conversion 4294965296 to float, precision which is 00011000 loss occurs.
11111111111111111111100 00011000 0 <-- 4294965296
11111111111111111111100 00000000 0 <-- 4294965248
This is because you use - on an unsigned int. The - inverts the bits of the number. Lets print some unsigned integers:
printf("Positive: %u\n", 2000);
printf("Negative: %u\n", -2000);
// Output:
// Positive: 2000
// Negative: 4294965296
Lets print the hex values:
printf("Positive: %x\n", 2000);
printf("Negative: %x\n", -2000);
// Output
// Positive: 7d0
// Negative: fffff830
As you can see, the bits are inverted. So the problem comes from using - on unsigned int, not from casting unsigned intto float.
As others have said, the issue is that you are trying to negate an unsigned number. Most of the solutions already given have you do some form of casting to float such that the arithmetic is done on floating point types. An alternate solution would be to cast the results of your arithmetic to int and then negate, that way the arithmetic operations will be done on integral types, which may or may not be preferable, depending on your actual use-case:
#include <stdio.h>
int main(void)
{
unsigned int a = 10;
unsigned int b = 20;
unsigned int c = 30;
float d = -(int)((a*b)*(c/3));
printf("d = %f\n", d);
return 0;
}
Your whole calculation will be done unsigned so it is the same as
float d = -(2000u);
-2000 in unsigned int (assuming 32bits int) is 4294965295
this gets written in your float d. But as float can not save this exact number it gets saved as 4294965248.
As a rule of thumb you can say that float has a precision of 7 significant base 10 digits.
What is calculated is 2^32 - 2000 and then floating point precision does the rest.
If you instead use 3.0 this changes the types in your calculation as follows
float d = -((a*b)*(c/3.0));
float d = -((unsigned*unsigned)*(unsigned/double));
float d = -((unsigned)*(double));
float d = -(double);
leaving you with the correct negative value.
you need to cast the ints to floats
float d = -((a*b)*(c/3));
to
float d = -(((float)a*(float)b)*((float)c/3.0));
-((a*b)*(c/3)); is all performed in unsigned integer arithmetic, including the unary negation. Unary negation is well-defined for an unsigned type: mathematically the result is modulo 2N where N is the number of bits in unsigned int. When you assign that large number to the float, you encounter some loss of precision; the result, due to its binary magnitude, is the nearest number to the unsigned int that divides 2048.
If you change 3 to 3.0, then c / 3.0 is a double type, and the result of a * b is therefore converted to a double before being multiplied. This double is then assigned to a float, with the precision loss already observed.

Multiplication and Division unsigned integers

In my program , I have to perform arithmetic operations on unsigned integers.
The variable a has a range from 0 to 4294967295.
The variable b has a range from 0 to 32.
When I check the boundary condition by taking the maximun values for a and b,I am getting 0 as the answer since overflow occurs when I try to multiply a and MAX_NS.Ideally I should get 7 as the answer.How could I write the program such that overflow is taken care of and I get 7 as the answer and hopefully it works for other valid value range for a and b.Thanks.
#include "stdio.h"
#define MAX_NS 1000000000
int main()
{
unsigned int a = 4294967295;
unsigned int b = 32 ;
unsigned int c = ((b * MAX_NS)/a);
printf("%d",c);
}
**Edit:**Please note that I can't use unsigned long long.I can use only unsigned int for the variables.
Here is solution as Weather Vane suggested
#include "stdio.h"
#define MAX_NS 1000000000
int main()
{
unsigned long long a = 4294967295;
unsigned long long b = 32;
unsigned long long c = ((b * MAX_NS) / a);
printf("%llu", c);
}
The key is that the product b * MAX_NS must be computed using wide enough math.
Make certain at least one of the * operands is unsigned long long.
With large enough b and small enough a, the quotient will need a wider type to avoid overflow;
#include "stdio.h"
// #define MAX_NS 1000000000
#define MAX_NS 1000000000LLU
int main(void) {
unsigned int a = 4294967295; // type may remain unsigned
unsigned int b = 32 ; // type may remain unsigned
unsigned long long c = ((b * MAX_NS)/a);
printf("%llu",c);
}
Alternatively, coax the multiplication gently by multiplying by 1ull. In general avoid casting as in (unsigned long long) b * MAX_NS. Rampant practice of casting surprisingly sometimes narrows the math which could happen here at a later date with uintmax_t b.
#define MAX_NS 1000000000
int main(void) {
unsigned int a = 4294967295; // type may remain unsigned
unsigned int b = 32 ; // type may remain unsigned
unsigned long long c = ((1ull * b * MAX_NS)/a);
printf("%llu",c);
}

Unsure why this cast works

i have the following code:
unsigned short a, b, c, d;
unsigned long result;
a = 30000;
b = 40000;
c = 50000;
d = 60000;
result = (unsigned long)(a + b + c + d) / 4;
printf("result is %i", result);
The result of this is (30000 + 40000 + 50000 + 60000) / 4 = 180000 / 4 = 45000 which is correct. But i wonder why. I would expect the addition of unsigned shorts to overflow because it is done in 16 bit and after the addition the overflowed result is converted to unsigned long and then divided by 4.
What am i missing here?
Your shorts were promoted to ints before addition.
http://en.cppreference.com/w/cpp/language/implicit_conversion (the link is about C++, but C rules are basically same)
Integral promotion
...arithmetic operators do not accept types smaller than int as arguments, and integral promotions are automatically applied...

In C89, how can I truncate and split a double precision floating point into two 32-bit words?

When targeting C99, I could truncate and split a double value into two 32-bit integers with the following code:
#include <stdint.h>
void split(double d, unsigned long *most_significant_word, unsigned long *least_significant_word)
{
uint64_t i = (uint64_t)d;
*most_significant_word = i >> 32;
*least_significant_word = i & 0xffffffff;
}
C89 however, does not seem to define a 64-bit integer type, so I can't use the compiler to perform the truncation. Even if the truncation was not necessary(the value already represented an integer) I also could not use bit operators like & or >> since these don't work on double values.
So, how can the above split() function be implemented in pure C89(and thus without relying on 64-bit integers), returning the 21/32 bit words that make up a 53-bit integer stored in a double value?
Ignoring the sign (as does the original code) it should be as simple as this:
void split(double d, unsigned long *most_significant_word, unsigned long *least_significant_word)
{
*most_significant_word = d/4294967296.; // d>>32 in double
*least_significant_word = fmod(d, 4294967296.);
}
To take negative numbers into consideration, operate on the absolute value then compute the two's complement:
void split(double d, unsigned long *most_significant_word, unsigned long *least_significant_word)
{
double dabs = d < 0 ? -d : d;
*most_significant_word = dabs/4294967296.;
*least_significant_word = fmod(dabs, 4294967296.);
if (d < 0) {
*most_significant_word = ~*most_significant_word;
*least_significant_word = ~*least_significant_word + 1;
if (!*least_significant_word) *most_significant_word += 1;
}
}

Resources