Working out 2powX

  • (3 Pages)
  • +
  • 1
  • 2
  • 3

34 Replies - 2439 Views - Last Post: 07 March 2012 - 04:38 AM Rate Topic: -----

#16 Karel-Lodewijk  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 445
  • View blog
  • Posts: 849
  • Joined: 17-March 11

Re: Working out 2powX

Posted 02 March 2012 - 02:21 PM

CTphpnwb's suggestion is excellent if you want a binary number because 2^10000 is a nice round number in binary. But if you want a decimal result it might not be so easy. In decimal 2^10000 is not so round, in fact it is:

Spoiler


If you want an exact solution, I would use a bignum library.

If you want an approximation and the result no longer fits in a double/log double. Then you could do something like:

we want 2^10000

If the base number was 10, a power could be calculated by just shifting the number, so we rewrite the exponent in a part that'll make the base 10 (log2(10)) and the rest.

So, we rewrite

2^10000
= 10 ^ (10000/log2(10))
= 10 ^ 3010.3
= 10 ^ 0.3 * 10 ^ 3010

So we have reduced our huge exponential to a reasonable small one (10^0.3) and a shift operation.

= 1.99526231... * 10^3010

This result is not exact because 10^0.3 can't be calculated exactly (with a double)

This post has been edited by Karel-Lodewijk: 02 March 2012 - 02:22 PM

Was This Post Helpful? 0
  • +
  • -

#17 Karel-Lodewijk  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 445
  • View blog
  • Posts: 849
  • Joined: 17-March 11

Re: Working out 2powX

Posted 02 March 2012 - 02:43 PM

View PostCTphpnwb, on 02 March 2012 - 09:07 PM, said:

Base10 = Binary
2^0 = 1
2^1 = 10
2^2 = 100
2^3 = 1000

See a pattern?
2^n = 1 in the n binary position, where in this case 0 <= n <= 10000
Now you need to store it. That's where the array comes in. Next, you need to calculate the base10 equivalent and display it.


The point is that it doesn't solve anything. Now you have a really big binary number and now you got to convert it to a decimal numer. So how do we do that.

10....00 to base 10
= 0 * 2^0 + 0 * 2^1 + ... + 0*2^9999 + 1*2^10000
= 2 ^ 10000 :)

That didn't sove much did it. The base conversion requires you to be able to calculate a really big exponential.

This post has been edited by Karel-Lodewijk: 02 March 2012 - 02:52 PM

Was This Post Helpful? 0
  • +
  • -

#18 Itchigon  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 31
  • Joined: 17-February 12

Re: Working out 2powX

Posted 02 March 2012 - 02:48 PM

View PostCTphpnwb, on 02 March 2012 - 02:07 PM, said:

Base10 = Binary
2^0 = 1
2^1 = 10
2^2 = 100
2^3 = 1000

See a pattern?
2^n = 1 in the n binary position, where in this case 0 <= n <= 10000
Now you need to store it. That's where the array comes in. Next, you need to calculate the base10 equivalent and display it.


Thanks for your help so far, I feel bad having to ask for more help in explaining this.

I'm having issues with storing the number in an array. I understand the pattern, so for example 2^10000 = 1 followed by 10,000 zero's. But I don't get how to do this in code form? Is there some form of psuedocode you could give me just for populating the array and then I could work out how to convert into Base10?

Karel, what I want is basically:

1. User enters a number x (between 1-10000)
2. Program calculates 2 pow x
3. Program adds all digits of 2 pow x together. E.g. 2 pow 4 = 16, 1+6 = 7.
4. Print this result to the user

In regards to your explanation, do I need to keep precision to work out part 3. or could I work this out by using your method?
Was This Post Helpful? 0
  • +
  • -

#19 Karel-Lodewijk  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 445
  • View blog
  • Posts: 849
  • Joined: 17-March 11

Re: Working out 2powX

Posted 02 March 2012 - 03:01 PM

View PostItchigon, on 02 March 2012 - 09:48 PM, said:

Karel, what I want is basically:

1. User enters a number x (between 1-10000)
2. Program calculates 2 pow x
3. Program adds all digits of 2 pow x together. E.g. 2 pow 4 = 16, 1+6 = 7.
4. Print this result to the user

In regards to your explanation, do I need to keep precision to work out part 3. or could I work this out by using your method?


Nope you pretty much need full precision. Like I said, use a bignum library. You could do it by hand but it would require a bit of work.
Was This Post Helpful? 0
  • +
  • -

#20 Itchigon  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 31
  • Joined: 17-February 12

Re: Working out 2powX

Posted 02 March 2012 - 03:02 PM

View PostKarel-Lodewijk, on 02 March 2012 - 03:01 PM, said:

View PostItchigon, on 02 March 2012 - 09:48 PM, said:

Karel, what I want is basically:

1. User enters a number x (between 1-10000)
2. Program calculates 2 pow x
3. Program adds all digits of 2 pow x together. E.g. 2 pow 4 = 16, 1+6 = 7.
4. Print this result to the user

In regards to your explanation, do I need to keep precision to work out part 3. or could I work this out by using your method?


Nope you pretty much need full precision. Like I said, use a bignum library. You could do it by hand but it would require a bit of work.


I'm not allowed to use a bignum library as the assignment says so.
Was This Post Helpful? 0
  • +
  • -

#21 CTphpnwb  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2503
  • View blog
  • Posts: 8,564
  • Joined: 08-August 08

Re: Working out 2powX

Posted 02 March 2012 - 03:20 PM

Storing the number is the easy part. Outputting the decimal equivalent is harder.
using namespace std;
#include <iostream>

void store2n(unsigned long b[], int n) {
	int byte_num = n/64;
	int position = n % 64;
	int temp = 1;
	temp = temp<<position;
	b[byte_num] = temp;
}

int main (int argc, char * const argv[]) {
	unsigned long big[157] = {0};
	store2n(big, 70);
	for (int i = 156; i >= 0; i--) {
		cout << big[i] << "_";
	}
	cout << endl <<"Note that this number is 64 * 2^64 since we're seeing the decimal value store in each array element, not the actual decimal number." << endl;
	
	cout << 10000.0/(sizeof(unsigned long)*8) << endl;
	
	return 0;
}


Was This Post Helpful? 0
  • +
  • -

#22 Karel-Lodewijk  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 445
  • View blog
  • Posts: 849
  • Joined: 17-March 11

Re: Working out 2powX

Posted 02 March 2012 - 03:21 PM

I think the simplest would be using a vector of unsigned char and do a x2 each time, pushing new digits as they are needed. i.e.:

{2} * 2
{4} * 2
{8} * 2 //push a 1
{6,1} * 2
{2,3}
...


This post has been edited by Karel-Lodewijk: 02 March 2012 - 03:21 PM

Was This Post Helpful? 0
  • +
  • -

#23 jimblumberg  Icon User is offline

  • member icon

Reputation: 3110
  • View blog
  • Posts: 9,482
  • Joined: 25-December 09

Re: Working out 2powX

Posted 02 March 2012 - 03:25 PM

Since your base will always be 2 wouldn't this be easier using shifting? After all pow(2,16) is the same as 1<<16. And as long as you only shift ((numeric_limits<unsigned type>::digits) - 1) maximum you will stay in within the size of your unsigned type value. To do a higher number of shifts start using an array of your maximum shifted values. For example for 100 (1.26765e+30) (using 32 bit unsigned value) shift 1<<31 1<<31 1<<31 1<<7 ( 2147483648 * 2147483648 * 2147483648 * 128 = 1.26765e+30) Also remember with "Big" floating point numbers you will also start seeing errors because of the number of significant digits of your floating point number.


Jim
Was This Post Helpful? 0
  • +
  • -

#24 Itchigon  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 31
  • Joined: 17-February 12

Re: Working out 2powX

Posted 02 March 2012 - 03:42 PM

Karel that could be done using arrays too right? I'm only using C.
Was This Post Helpful? 0
  • +
  • -

#25 CTphpnwb  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2503
  • View blog
  • Posts: 8,564
  • Joined: 08-August 08

Re: Working out 2powX

Posted 02 March 2012 - 03:46 PM

View Postjimblumberg, on 02 March 2012 - 06:25 PM, said:

Since your base will always be 2 wouldn't this be easier using shifting?

That's what I did. After determining which element to use and how many bits are left over to shift:
    temp = temp<<position;


Was This Post Helpful? 0
  • +
  • -

#26 jimblumberg  Icon User is offline

  • member icon

Reputation: 3110
  • View blog
  • Posts: 9,482
  • Joined: 25-December 09

Re: Working out 2powX

Posted 02 March 2012 - 04:27 PM

Could you explain your magic numbers? Why are you passing 70 to your program? Why the 64 in your function, and why (sizeof(unsigned long)*8) in main? What output does your program produce?

It produces this on my machine:

Quote

0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_
0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0
_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_
0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_64_0_

Note that this number is 64 * 2^64 since we're seeing the decimal value store in each array element, not the actual decimal number.
312.5


Is that correct?

Jim

This post has been edited by jimblumberg: 02 March 2012 - 04:29 PM

Was This Post Helpful? 0
  • +
  • -

#27 Itchigon  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 31
  • Joined: 17-February 12

Re: Working out 2powX

Posted 02 March 2012 - 04:51 PM

Yea i'm not sure what those numbers actually mean, I also get the same output Jim.
Was This Post Helpful? 0
  • +
  • -

#28 CTphpnwb  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2503
  • View blog
  • Posts: 8,564
  • Joined: 08-August 08

Re: Working out 2powX

Posted 02 March 2012 - 05:53 PM

It's just an example: 2^70 = (2^8) * (2^64) = 64 * 2^64
The first element of the array holds 0 through 2^64 -1
The second holds (0 through 2^64 - 1) * 2^64
and so on...

The last line shows how many elements you need in the array to represent 2^10000 on your system. Mine shows: 156.25 because there are 8 bytes in a long int on my system.
10000.0/(8*8) = 156.25
(8 bytes * 8 bits per byte)

Jim's system is using 4 bytes in a long int so he'd need 313 elements in the array:
10000.0/(4*8) = 312.5

If you use part of a byte you have to use the whole thing, so my code uses 157 for the size of big[]:
	unsigned long big[157] = {0};


Jim's would need to be 313 and each element would hold 2^32 possible values instead of 2^64 so the math would be a little different.

This post has been edited by CTphpnwb: 02 March 2012 - 06:11 PM

Was This Post Helpful? 0
  • +
  • -

#29 jimblumberg  Icon User is offline

  • member icon

Reputation: 3110
  • View blog
  • Posts: 9,482
  • Joined: 25-December 09

Re: Working out 2powX

Posted 03 March 2012 - 12:00 PM

I still don't really understand your code. I don't see why you need such a large array, You should be able to hold 2^10000 with an array size of 14 (actually with this size you can hold a number of 2^16383). This is also the largest value that a long double will hold on my machine when using pow(2.0,16283) which is 5.9487e4931 in decimal.

Using your program as a base, this is what I came up with.
#include <iostream>
#include <vector>
#include <cmath>

using namespace std;

void store2n(std::vector<int>& b, int n)
{
   // Determine the size of the vector needed to hold this power.
   int k = 0;
   while((1<<k++) < n);
   // Need one less bit space.
   b.resize(k-1);

   for(int i = b.size()-1; i >= 0; --i)
   {  // Fill in the proper bit positions.
      if(n - (1<<i) >= 0)
      {
         b[i] = 1;
         n = n - (1<<i);
      }
   }
}

int getTotal(const std::vector<int>& big)
{
   int total = 0;
   for (int i = big.size()-1; i >= 0; --i)
      if(big[i])
         total += (1<<i);
   return(total);
}

std::vector<int> add2n(std::vector<int>& a, std::vector<int>& B)/>
{
   std::vector<int> temp((a.size() + b.size()),0);
   store2n(temp,getTotal(a) + getTotal(B)/>);

   return(temp);
}

int main ()
{
   int howBig;

   std::vector<int> big;
   std::vector<int> small;
   std::vector<int> medium;

   int smallP = 30;
   int mediumP = 40;

   store2n(small,smallP);
   store2n(medium,mediumP);
   big = add2n(small,medium);

   // 2^16383 is the largest number that can be held in a large double on my machine.


   howBig = smallP+mediumP;

   cout << "2 to the " << howBig << " power. \n\n";

   cout << "In Decimal is " << pow(2.0,(long double)(howBig)) << "\n\n";

   cout << "Which is ";
   for (int i = big.size()-1; i >= 0; i--) {
      cout << big[i] << " ";
   }
   cout << " in binary \n\n";
   int total = 0;
   cout << "Which is ";

   for (int i = big.size()-1; i >= 0; --i) {
      if(big[i])
      {
         total += (1<<i);
         big[i] = (1<<i);
         cout << big[i];
         cout << " + ";
      }
      else
      {
         cout << 0;
         if( i > 0) cout << " + ";
      }
   }
   cout << " = " << total << endl << endl;
   cout << "In Decimal is " << pow(2.0,(long double)(total)) << "\n\n";

   return 0;
}




And this is the output that this program produces:

Quote

2 to the 70 power.

In Decimal is 1.18059e+21

Which is 1 0 0 0 1 1 0 in binary

Which is 64 + 0 + 0 + 0 + 4 + 2 + 0 + = 70

In Decimal is 1.18059e+21

And if I change the program to produce 2^10,000 I get this output:

Quote

2 to the 10000 power.

In Decimal is 1.99506e+3010

Which is 1 0 0 1 1 1 0 0 0 1 0 0 0 0 in binary

Which is 8192 + 0 + 0 + 1024 + 512 + 256 + 0 + 0 + 0 + 16 + 0 + 0 + 0 + 0 + = 10000

In Decimal is 1.99506e+3010


Jim
Was This Post Helpful? 0
  • +
  • -

#30 CTphpnwb  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2503
  • View blog
  • Posts: 8,564
  • Joined: 08-August 08

Re: Working out 2powX

Posted 03 March 2012 - 12:29 PM

Well, I'm not sure why you're using doubles at all. Sure, you can represent the number with them, but not accurately. Try adding 2^10000 and 2^1. Your result will be the same as 2^10000. If you want to store the number down to the least significant digit you have to use an array of integers. That leaves you with:

2^0 requires 1 bit => 1
2^1 requires 2 bits => 10
2^2 requires 3 bits => 100
...
2^10 requires 11 bits => 10000000000

So, 2^N requires N+1 bits and 2^10000 requires 10001 bits.
10001/64(bits per long int) = 156.265625 long integer values, meaning we'd need to use an array with 157 integers to store this value, assuming we didn't use a sign bit.
Was This Post Helpful? 0
  • +
  • -

  • (3 Pages)
  • +
  • 1
  • 2
  • 3