views:

584

answers:

5
long long int A = 3289168178315264;
long long int B = 1470960727228416;
double D = sqrt(5);

long long int out = A + B*D;

printf("%lld",out);

This gives result : -2147483648

I am not able to figure out why (it should be a positive result). Can somebody help?

+3  A: 

maybe you have to specify those constants as "long long" literals? e.g. 3289168178315264LL

newacct
Indeed, without LL suffix GCC even complains that "integer constant is too large for ‘long’ type".
qrdl
I have correct values in A and B (have tried printing them)... Still output is incorrect.
Rohit
@Rohit On GCC adding LL does the trick. What is your compiler?
qrdl
A: 

The parameter to sqrt should be double.

#include <math.h>
double sqrt( double num );

And also we should explict cast the result from B * D to long long.

    long long int A = 3289168178315264;
    long long int B = 1470960727228416;
    double D = sqrt(5.0);
    printf("%f\n",D);
    long long int out = A + (long long) (B * D);
    printf("%lld",out);
pierr
C should implicitly cast to a double. int --> double is implicit, but double --> is not.
carl
A: 

My guess is that the compiler needs to round the result from "A+B*D" to an integer first, because you're storing the result inside an int field. So basically, you're having a datatype conflict.

Both A and B are still valid numbers for a long long int, which is 8 bytes long. You could even multiply them by 1.000 and still have valid long long int values. In some other languages it's also known as the int64.

A double, however, is also 64-bits but part of those are used as exponent. When you multiply a double with an int64, the result would be another double. Adding another int64 to it still keeps it a double. Then you're assigning the result to an int64 again without using a specific rounding method. It would not surprise me if the compiler would use a 4-bit rounding function for this. Am even amazed that the compiler doesn't puke and break on that statement!

Anyways, when using large numbers like these, you have to be extra careful when mixing different types.

Workshop Alex
Thanks... It works with " long long int out = A + (long long int)(B*D); "
Rohit
This doesn't make a lot of sense as an explanation. Given that the code is using 'long long', it should be using a C99 compiler. When the compiler processes the expression `B * D`, it must promote B to a `double` and compute the result as a `double`. When it looks at 'A + <exp>', it sees that it must add a `double` and a `long long`, again promoting A to double and producing a `double`. Then it assigns a `double` to a `long long` with the implicit conversion. There should be no call to use plain `int` or even `long` at all.
Jonathan Leffler
True, that it suddenly works makes no sense. It's not always easy to explain or even logical! To know why, you'd might have to check the disassembly of the code to see what kind of code it actually created. It's just that sometimes, compilers act in an illogical way.
Workshop Alex
A: 

Your answer (have to verify) calcuates successfully, however, it causes an overflow into the sign bit, which makes the answer negative. Solution : make all your variables unsigned.

Why:

Numbers are stored as series of bits in you computer's memory. The first bit in such a series, when set means that you number is negative. So the calculation works, but overflows into the sign bit.

Recommendation:

If you're working with numbers this big, I recommend you to get a multiprecision arithmetic library. 'T will save you a lot of time and trouble.

Aviral Dasgupta
Can you justify the overflow assertion? Explain how you conclude that overflow occurs.
Jonathan Leffler
+1  A: 

What compiler/operating system are you using? I ran your code using Visual C++ 2008 Express Edition on Windows XP and IT WORKS - answer: 6578336356630528 (this is a 53-bit number, so it just fits inside a double).

I also tried two variations to see if the order of operations mattered:

long long int out = A; out+=B*D;

long long int out = B*D; out+=A;

These both work as well!

Curious.

Rick Regan
On MacOS X (10.5.11) with GCC 4.0.1, the original code produces the same answer as Rick says MSVC++ does - and compiles with no warning when I include `<stdio.h>` and `<math.h>` and use the compiler flags `-Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -std=c99` (which is very fussy). The C99 compilation mode matters; with C89 mode, the integer constants are too big.
Jonathan Leffler
(Addendum: add the `LL` suffix to the constants and GCC works without complaint in C89 mode. Note that adding `-pedantic` would cause trouble in C89 mode.)
Jonathan Leffler