0

In a c program I have a variable of type long long int and it stores a value 0x7fffffffffffffff. When I divide this value with 1024 * 4 it gives me 2251799813685247 i.e. 0x7ffffffffffff.

Now when I multiply back (1024 * 4) it results in 0x7ffffffffffff000.

Even if I make the variable of type long long unsigned int there is no change in result. The code is running on 64 bit machine.

Why does not it results in 0x7fffffffffffffff?

3
  • 2
    Could you add your code in the question? Commented Nov 14, 2013 at 8:23
  • 5
    Why does (10/3)*3 not equal 10? Hmmm.... Commented Nov 14, 2013 at 8:25
  • @WhozCraig ... yeah completely logical Commented Nov 14, 2013 at 8:25

4 Answers 4

7

If you divide it by 4096, that is merely a shift right by 12 bits. That means that the last 12 bits are lost:

0x7fffffffffffffff becomes
0x7ffffffffffff

If you multiply back, you shift left by 12, so the missing bits are filled with 0.

Sign up to request clarification or add additional context in comments.

7 Comments

While the bit shift paints a nice picture, the root cause for this is integer division. The missing "chunk" is 4095 i.e 0xFFF, dropped by division operation never to be seen again on the multiplication back (+1 for the picture btw, nice answer).
@WhozCraig From the POV of the standard, you may be right, but division is often implemented as a shift.
Sure, but nothing in the standard mandates it is implemented as a shift, so the POV of the standard is all I got. I certainly would were i emitting the opcodes and handed a 2^N denominator, to be sure. And the same problem is pervasive with a non-power-of-two (dividing and multiplying by 4095 for example, will yield 7ffffffffffffff8)
thanks gl and craig for the clarifications. craig if integer division is the problem then it must not come if I use long division. I tried using ldiv for long division but it does not solve the issue. printf("===> %6lx\n", 0x7fffffffffffffff); printf("===> %6lx\n", (0x7fffffffffffffff/(1024*4))); printf("===> %6lx\n", ldiv(0x7fffffffffffffff,(1024*4))); results in ===> 7fffffffffffffff ===> 7ffffffffffff ===> 7ffffffffffff
@RupeshKumar The problem is the modulo is lost. If you want it back, retain it first. I.e. tmp = 0x7FFFFFFFFFFFFFFF % (1024*4); The result will be the cut-off modulo lost during the division. adding it back is one way to retain it.
|
1
echo "((15/4)*4)" | bc

the result is not 15

Comments

1

Both integer division and integer multiplication work exactly only as long as the result fits within the confines of the type. If it doesn't you get all sorts of truncation etc.

Let's get a simpler version, a char variable [0-255]

  unsigned char a = 12;
  unsigned char b = a/4;

Since 12/4 = 3 exactly, and 3 is an integer in range between 0 and 255, b is 3. Multiply that by 4, and you get your 12 back.

  unsigned char a = 11;
  unsigned char b = a/2;

11/2 is 5.5 but integers can't store the fractional part. In this case b is 5 and the 0.5 part is irrecoverably lost. Multiply the b by 2 and you get 10, not 11.

Note, it's truncation, not rounding.

  unsigned char a = 100;
  unsigned char b = a/15;

100/15 is 6.66(6) - which rounded to nearest integer would be closer to 7. Thing is, we're truncating, not rounding, so (int) 6.6666666666 is 6. The fractional part is forever lost. Now multiply b*15 and you get 90. It's rather far off - it's the cost of using integers instead of floats.

Even worse things happen in overflow.

  unsigned char a = 150;
  unsigned char b = a*2;  //300 with top bit truncated becomes 44
  unsigned char c = b/2;  // 44/2 = 22

but that's a subject for a different question.

Comments

0

Its simple maths...

1024 * 4 * 0x7ffffffffffff = 0x7ffffffffffff000

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.