finding power of a number - fpga

I have a very big number which is a product of several small primes. I know the number and also I know the prime factors but I don't know their powers. for example:
(2^a)x(3^b)x(5^c)x(7^d)x(11^e)x .. = 2310
Now I want to recover the exponents in a very fast and efficient manner. I want to implement it in an FPGA.
Regards,

The issue is that you are doing a linear search for the right power when you should be doing a binary search. Below is an example showing how to the case where the power of p is 10 (p^10). This method finds the power in O(log N) divisions rather than O(N).
First find the upper limit by increasing the power quickly until it's too high, which happens at step 5. Then it uses a binary search to find the actual power.
Check divisibility by p. Works.
Check divisibility by p^2. Works.
Check divisibility by p^4. Works.
Check divisibility by p^8. Works.
Check divisibility by p^16. Doesn't work. Undo/ignore this one.
Check divisibility by p^((8+16)/2)=p^12. Doesn't work. Undo/ignore this one.
Check divisibility by p^((8+12)/2)=p^10. Works, but might be too low.
Check divisibility by p^((10+12)/2)=p^11. Doesn't work. Undo/ignore this one.
Since ((10+11)/2)=10.5 is not an integer, the power most be the low end, which is 10.
Note, there is a method where you actually divide by p, and at step 4, you've actually divided the number by p^(1+2+4+8)=p^15, but it's a bit more difficult to explain the binary search part. However, the size of the number being divided gets smaller, so division operations are faster.

Related

Algorithm complexity

Suppose an oracle knows a natural number nthat you wish to know.
The oracle answers only Yes/No, to the following three types of queries:
Is the number greater than x ?
Is the number lesser than x ?
Is the number equal to x ?
(where x can be an arbitrary natural number, that can changed across queries).
Describe a method for posing queries to the oracle, which is asymptotically efficient in the number of queries posed.
Perform the analysis and write a proof of correctness. Note that the number of queries posed will be a function of n
This question is not very fair as it requires asymptotic efficiency, without giving any hint on the goal. We can use an informal information theoretic bound and say that the answer conveys i bits of information, which is Omega(i)=Omega(Lg n).
The algorithm
Phase 1: find the number of significant bits.
Ask x<1b, x<10b, x<100b, x<1000b, x<10000b, x<100000b... (all powers of 2)
until you get a yes.
Phase 2: find all bits.
Take the value of the last bound where phase 1 stopped and divide it by 2.
Then, going from the second most significant to the least significant bit,
set the next bit and ask if <x. Keep the bit set if you get a no.
Example
Let us assume x=10110b, your questions will go as follows:
x<1b ? no
x<10b ? no
x<100b ? no
x<1000b ? no
x<10000b ? no
x<100000b ? yes
Q=10000b
x<11000b ? yes
Q=10000b
x<10100b ? no
Q=10100b
x<10110b ? no
Q=10110b
x<10111b ? yes
Q=10110b
For 5 bits, 10 questions.
Correctness
In phase 1, the search intervals form a partition of the integers and the search will stop sooner or later. When it stops, P<=x<2P holds, where P is a power of 2,or 2^k<=x<2^(k+1).
In phase 2, we keep the invariant condition Q<=x<Q+2^(k+1) by iterative halving (initially Q=0): given Q<=x<Q+2^(k+1), we ask for x<Q+2^k and conclude either Q<=x<Q+2^k or Q+2^k<=x<Q+2^(k+1), which we turn to Q'<=x<Q'+2^k by setting Q'=Q+2^k. In the end, Q<=x<Q+1.
Efficiency
Phase 1 takes as many queries as there are significant bits.
Phase 2 takes as many queries as there are significant bits.
Check out the Wikipedia post on binary search algorithm. That can be a starting point for you.
Binary Search Algorithm

Power of two to get an integer

I need a (fairly) fast way to get the following for my code.
Background: I have to work with powers of numbers and their product, so I decided to use logs.
Now I need a way to convert the log back to an integer.
I can't just take 2^log_val (I'm working with log base 2) because the answer will be too large. In fact i need to give the answer mod M for given M.
I tried doing this. I wrote log_val as p+q, where q is a float, q < 1 and p is an integer.
Now i can calculate 2^p very fast using log n exponentiation along with the modulo, but i can't do anything with the 2^q. What I thought of doing is finding the first integral power of 2, say x, such that 2^(x+q) is very close to an integer, and then calculate 2^p-x.
This is too long for me because in the worst case I'll take O(p) steps.
Is there a better way?
While working with large numbers as logs is usually a good approach, it won't work here. The issue is that working in log space throws away the least significant digits, thus you have lost information, and won't be able to go back. Working in mod space will also throw away information (otherwise your number gets to big, as you say), but it throws away the most significant ones instead.
For your particular problem POWERMUL, what I would do is to calculate the prime factorizations of the numbers from 1 to N. You have to be careful how you do it, since your N is fairly large.
Now, if your number is k with the prime factorization {2: 3, 5: 2} you get the factorization of k^m by {2: m*3, 5:m*2}. Division similarly turns into subtraction.
Once you have the prime factorization representation of f(N)/(f(r)*f(N-r)) you can recreate the integer with a combination of modular multiplication and exponentiation. The later is a cool technique to look up. (In fact languages like python has it built in with pow(3, 16, 7)=4.
Have fun :)
If you need an answer mod N, you can often do each step of your whole calculation mod N. That way, you never exceed your system's integer size restrictions.

Generate a random number using coin flips while guarenteeing termination

The usual method to generate a uniform random number 0..n using coin flips is to build a rng for the smallest power of two greater than n in the obvious way, then whenever this algorithm generates a number larger than n-1, throw that number away and try again.
Unfortunately this has worst case runtime of infinity.
Is there any way to solve this problem while guaranteeing termination?
Quote from this answer https://stackoverflow.com/a/137809/261217:
There is no (exactly correct) solution which will run in a constant
amount of time, since 1/7 is an infinite decimal in base 5.
Now ask Adam Rosenfield why it is true :)

Guessing a number knowing only if the number proposed is lower or higher?

I need to guess a number. I can only see if the number I'm proposing is lower or higher. Performance matters a whole lot, so I thought of the following algorithm:
Let's say the number I'm trying to guess is 600.
I start out with the number 1000 (or for even higher performance, the average result of previous numbers).
I then check if 1000 is higher or lower than 600. It is higher.
I then divide the number by 2 (so that it is now 500), and check if it is lower or higher than 600. It is lower.
I then find the difference and divide it by 2 in the following way to retrieve a new number: (1000 + 500) / 2. The result is 750. I then check that number.
And so on.
Is this the best approach or is there a smarter way of doing this? For my case, every guess takes approximately 500 milliseconds, and I need to guess quite a lot of numbers in as low time as possible.
I can roughly assume that the average result of previous guesses is close to the upcoming numbers too, so there's a pattern there which I can use for my own advantage.
yes binary search is the most effective way of doing this. Binary Search is what you described. For a number between 1 and N Binary Search runs in O(log(n)) time.
So here is the algorithm to find a number between 1-N
int a = 1, b = n, guess = average of previous answers;
while(guess is wrong) {
if(guess lower than answer) {a = guess;}
else if(guess higher than answer) {b = guess;}
guess = (a+b)/2;
} //Go back to while
Well, you're taking the best possible approach without the extra information - it's a binary search, basically.
Exactly how you use the "average result of previous guesses" is up to you; it would suggest biasing the results towards that average, but you'd need to perform analysis of just how indicative previous results are in order to work out the best approach. Don't just use the average: use the complete distribution.
For example, if all the results have been in the range 600-700 (even though the hypothetical range is up to 1000) with an average of 670, you might start with 670 but if it says "guess higher" then you would probably want to choose a value between 670 and 700 as your next guess, rather than 835 (which is very likely to be higher than the real result).
I suggest you log all the results from previous enquiries, so you can then use that as test data for alternative approaches.
In general, binary search starting at the middle point of the range is the optimal strategy. However, you have additional specific information which may make this a suboptimal strategy. This depends critically in what exactly "close to the average of the previous results" means.
If numbers are close to the previous average then dividing by 2 in the second step is not optimal.
Example: Previous numbers 630, 650, 620, 660. You start with 640.
Your number is actually closer. Imagine that it is 634.
The number is lower. If in the second step you divide by 2, you get 320, thus losing any advantage about the previous average numbers.
You should analyze the behaviour further. It may be optimal, in your specific case, to start at the mean of the N previous numbers and then add or substract some quantity related to the standard deviation of the previous numbers.
Yes, binary search (your algorithm) is correct here. However there is one thing missing in the standard binary search:
For binary search you normally need to know the maximum and minimum between which you are searching. In case you do not know this, you have to iteratively find the maximum in the beginning, like so:
Start with zero
if it is higher than the number searched, zero is your maximum and you have to find a minimum
if it is lower than the number searched, zero is your minimum and you have to find a maximum
You can search for your maximum/minimum by starting at 1 or -1 and always multiplying by two until you find a number which is greater/smaller
When you always multiply by two, you will be much faster than when you search linearly.
Do you know the range of possible values? If yes, always start in the middle and do exactly what you describe.
A standard binary search between 0 and N(N is the given number) will give you the answer in logN time.
int a = 1, b = n+1, guess = average of previous answers;
while(guess is wrong) {
if(guess lower than answer) {a = guess;}
else if(guess higher than answer) {b = guess;}
guess = (a+b)/2;
} //Go back to while
You got to add +1 to n else you can never get n since it's an int.
I gave an answer to a similar question "Optimal algorithm to guess any random integer without limits?"
Actually, provided there algorithm not just searches for the conceived number, but it estimates a median of the distribution of the number that you may re-conceive at each step! And also the number could be even from the real domain ;)

How to design an efficient algorithm for least upper bound search

Let's say you have some set of numbers with a known lower bound and unknown upper bound, i.e. 0, 1, 2, 3, ... 78 where 78 is the unknown. Assume for the moment there are no gaps in between numbers. There is a time-expensive function test() that tests if a number is in the set.
What is an efficient way (requiring a low amount of test() calls) to find the highest number in the set?
What if you have the added knowledge that the upper bound is 75 +/- 25?
What if there are random gaps between numbers in the set, i.e. 0, 1, 3, 4, 7, ... 78?
For the "no gaps case":
I assume that this is a fixed size of number, e.g. a 32 bit int
We wish to find x such that test(x) == true, test(x+1) == false, right?
You basically do a binary chop between the lowest known "not in set" (e.g. the biggest 32 bit int) and the highest known "in set" (starting with the known lower bound) by testing the middle value in the range each time and adjusting the boundaries accordingly. This would give an O(log N) solution (in terms of numbers of calls to test()) where X is the size of the potential set, not the actual set. This will be slower than just trying 1, 2, 3... for small sets, but much faster for large ones.
All of this falls down if there can be gaps, at which point I don't think there's any feasible solution beyond "start with the absolute highest possible number and work down until test(x) == true at which point that's the highest number". Any other strategy will fail or be more expensive as far as I can see.
Your best bet is to simply run through the set with O(n) complexity, which is not bad.
Take into consideration that the set is not sorted (it is a set, after all, and this is the given), each isInSet(n) operation takes O(n) as well, bringing you to O(n^2) for the entire operation, if you choose any algorithm for prodding the set at certain places...
A much better solution, if the set is in your control, would be to simply keep a max value of the set and update it on each insertion to the set. This will be O(1) for all cases.
Set Step to 1
set Upper to Lower + Step
if test(Upper) is true then set Lower to Upper, multiply Step by 2 and go to point 2
at this point you know that Lower is in your set while Upper is not. You can now do a binary search between Lower and Upper to find the limit.
This looks like O(log n * O(test)) complexity.
If you know that Upper is between 50 and 100, Do a binary search between these two values.
If you have random gaps and you know that the upper bound is 100 maximum I suspect you can not do better than starting from there and testing every number one by one until test() finds a value in your set.
If you have random gaps and you do not know an upper limit then you can never be sure you found the upper bound.
Maybe you should just traverse through it? It would be O(n) complex. I think there is no other way to do this.
Do you know the set size, before hand?
Actually, I guess you probably don't - otherwise the first problem would be trivial.
It would help if you had some idea how big the set was though.
Take a guess at the top value
Test - if in then increment value by some amount
If not in then decrease value by some amount
Once you have upper and lower bounds for largest value, binary search till you find it (to required precision).
For the gaps you've no such ability - you can't even tell when you've found the largest element. (Unless you known the maximum gap size)
If there are no gaps, then you are probably best off with a binary search.
If we use the second assumption, that the top is 75 +/- 25, then are Low end is 50 and high end is 100, and our first test case is 75. If it is present, then the low end is 75 and the high end is 100, and our test case is 87. That should yield results in O( ln N) (where here N would be 50).
If we can't assume a possible upper range, we just have to made educated guess at what it might be. If a value is not found, it becomes the high end. If it is found, it's the low end, and we double it to find the high end.
If there are gaps, the only way I can see of doing it is a linear search -- but even then you'll need a way of knowing when you reached the end, rather that just a big gap.
If your set happens to be the set of prime numbers, let me know when you find the biggest one. I'm sure we can work something out. ;)
But seriously, I'm guessing you know for a fact that the set does indeed have a largest value. Or, you're chopping it to a 32-bit integer.
A couple of suggestions:
1) Think of every case you can that would speed a result of test(x) == false. Then you can go on to the next one. If the time you spend going through all of the ejection cases is far less than going through the full test, then you'll come out ahead.
2) Can you gain any information from each test? For example, does test(x) == false imply that test(x+5679) == false as well?

Resources