0

This post is related to my previous post:

Weird data corruption in C++ code for unsigned long long

The issue raised in that post is resolved, but now I am facing a different issue related to truncation of unsigned long long data type. This happens in the function iPow() for raising a base to the power of an exponent. The source code for iPow() was shared in my previous post, but is reproduced below for the sake of convenience:

 unsigned long long userinput::iPow(){

        while(this->revValue)
        {
                if (this->revValue & 1ULL)
                {
                        this->result *= this->value;
                }
                this->revValue >>= 1;
                this->value *= this->value;
        }
        return this->result;
}

In the above function, value, revValue, and result are all unsigned long long. The source code for the class declaration was shared in the previous post, but is reproduced below for convenience:

class userinput{

        public:
                userinput(unsigned long long);
                ~userinput();
                unsigned long long reverse ();
                unsigned long long raise_to_reverse ();

        private:
                userinput();
                userinput(const userinput&);
                void operator=(const userinput&);

        private:
                unsigned long long value;
                unsigned int numDigits;
                unsigned long long revValue;
                unsigned long long result;

        private:
                void calc_numDigits();
                unsigned long long iPow ();


};

I am reproducing below the gdb output for the values of this->value, this->revValue, and this->result for each iteration of the loop in iPow():

Enter a number between 0 and 99999 (exlusive):
1234

Breakpoint 1, userinput::iPow (this=0x7fffffffde10) at program.cpp:49
49      while(this->revValue)
Missing separate debuginfos, use: debuginfo-install glibc-2.15-56.fc17.x86_64 libgcc-4.7.0-5.fc17.x86_64 libstdc++-4.7.0-5.fc17.x86_64
(gdb) p this->revValue
$1 = 4321
(gdb) n
51          if (this->revValue & 1ULL)
(gdb) p this->revValue & 1ULL
$2 = 1
(gdb) n
53              this->result *= this->value;
(gdb) n
55          this->revValue >>= 1;
(gdb) p this->result
$3 = 1234
(gdb) n
56          this->value *= this->value;
(gdb) p this->revValue
$4 = 2160
(gdb) n
49      while(this->revValue)
(gdb) p this->value
$5 = 1522756
(gdb) n
51          if (this->revValue & 1ULL)
(gdb) p this->revValue & 1ULL
$6 = 0
(gdb) n
55          this->revValue >>= 1;
(gdb) n
56          this->value *= this->value;
(gdb) p this->revValue
$7 = 1080
(gdb) n
49      while(this->revValue)
(gdb) p this->value
$8 = 2318785835536
(gdb) n
51          if (this->revValue & 1ULL)
(gdb) p this->revValue & 1ULL
$9 = 0
(gdb) n
55          this->revValue >>= 1;
(gdb) n
56          this->value *= this->value;
(gdb) p this->revValue
$10 = 540
(gdb) n
49      while(this->revValue)
(gdb) p this->value
$11 = 3022197894083133696
(gdb) n
51          if (this->revValue & 1ULL)
(gdb) p this->revValue & 1ULL
$12 = 0
(gdb) n
55          this->revValue >>= 1;
(gdb) n
56          this->value *= this->value;
(gdb) p this->revValue
$13 = 270
(gdb) n
49      while(this->revValue)
(gdb) p this->value
$14 = 16658586050838462464
(gdb) n
51          if (this->revValue & 1ULL)
(gdb) p this->revValue & 1ULL
$15 = 0
(gdb) n
55          this->revValue >>= 1;
(gdb) n
56          this->value *= this->value;
(gdb) p this->revValue
$16 = 135
(gdb) n
49      while(this->revValue)
(gdb) p this->value
$17 = 8477297326610710528
(gdb) n
51          if (this->revValue & 1ULL)
(gdb) p this->revValue & 1ULL
$18 = 1
(gdb) n
53              this->result *= this->value;
(gdb) n
55          this->revValue >>= 1;
(gdb) p this->result
$19 = 1681011244301025280
(gdb) n
56          this->value *= this->value;
(gdb) p this->revValue
$20 = 67
(gdb) n
49      while(this->revValue)
(gdb) p this->value
$21 = 0
(gdb) n
51          if (this->revValue & 1ULL)
(gdb) p this->revValue & 1ULL
$22 = 1
(gdb) n
53              this->result *= this->value;
(gdb) n
55          this->revValue >>= 1;
(gdb) p this->result
$23 = 0
(gdb) n
56          this->value *= this->value;
(gdb) p this->revValue
$24 = 33
(gdb) n
49      while(this->revValue)
(gdb) p this->value
$25 = 0
(gdb)

As seen in the gdb output, the maximum value attained by this->value is $17 = 8477297326610710528 after which the value truncates to zero in the next iteration. Consequently, the value of this->result also truncates to zero due to the loop logic.

Is there a data type that I can use to print all the digits of the result of iPow(), considering the range 0-99999 (exclusive)? Or if there is no feasible data type, what alternative can I use to to print all the digits of the result of iPow() to stdout?

Kindly share your thoughts.

TIA Vinod

Community
  • 1
  • 1
  • I think you should use `std::string` – CinCout Aug 31 '15 at 09:47
  • @Garg Ankit How can I use std::string for the processing inside iPow()? I mean you need two integers for base and exponent? –  Aug 31 '15 at 09:52
  • Since your result is not in the range of the largest datatype possible in `C++`, you need to each time store the result in a string. Similar to `BigInteger` in `Java` – CinCout Aug 31 '15 at 09:53

1 Answers1

2

There is overflow in your calculations. unsigned long long has 64 bits in your case. The C++ specification mentions that multiplication of unsigned numbers uses modular arithmetic. That is, the result of the multiplication is correct up to a multiple of 264.

In your case:

1681011244301025280 is 0x175426D200000000 (I convert to hexadecimal for convenience)

When multiplied by itself:

0x175426D200000000 * 0x175426D200000000 =
(0x175426D2 * 2^32) * (0x175426D2 * 2^32) =
(0x175426D2 * 0x175426D2) * (2^32 * 2^32) =
(whatever) * 2^64) ≡ 0 (modulo 2^64)

So it's perfectly understandable why your big number multiplied by itself gives 0 when 64 bits are not enough to hold the result.

To eliminate the possibility of an overflow, use a bigint type (bigint is a keyword for an Internet search).

A recommendation question for a bigint library is e.g. here.

Community
  • 1
  • 1
anatolyg
  • 26,506
  • 9
  • 60
  • 134
  • thanks for your suggestion, but I cannot use any third party libraries for my code. Besides, I am coding on Linux. –  Aug 31 '15 at 15:42