find greatest number, x for given y and n such that x ^ y <= n - algorithm

I need to find a greatest number, x for given y and n such that x ^ y <= n
Here n can be very large number - 1 <= n <= 10^10
and 1 <= y <= 10^5
for example :
for y = 5 and n = 1024
x ^ 5, then x = 4 (4 ^ 5 = 1024)
for y = 5 and n = 480
x ^ 5 , then x = 3 (3 ^ 5 = 243, 4 ^ 5 = 1024) - selecting lowest one, so x = 3
i have written a small program, But i want more efficient technique because n and y can be very large.
def get(y, n):
x = 1
while x ** y <= n:
x += 1
return x - 1

Using a multiple-precision arithmetic library, such as gmpy2's iroot.
>>> import gmpy2
>>> root, exact = gmpy2.iroot(n, y)
This is simply an integer n-th root algorithm. It should be fast and correct even for huge numbers (something that floats cannot guarantee in the general case).
The second value returned is a boolean which indicates if the root is exact or not.
>>> print(*gmpy2.iroot(1024, 5))
4 True
>>> print(*gmpy2.iroot(480, 5))
3 False

you can use binary search on integer to move from your O(x) to O(log(x)) if you apply floating math then:
x^y = n // ^(1/y)
x = n^1/y
x = floor(pow(n,1/y))
your example n=400 and y=5 is like this:
x = floor(pow(400,1/5))
x = floor(pow(400,0.2))
x = floor(3.3144540173399868004685801443126)
x = 3
of coarse for big n will this not work with basic floating types. In such case either use bin search on big integers or implement your own bigint pow if you do not have it already at your disposal. Anyway both approaches are described here:
Power by squaring for negative exponents do not get fouled by the title it is all integer math ...
[edit1]
after absorbing your comments:
n = < 1 , 10^10 >
y = < 1 , 10^5 >
no FPU just integer math
I would use binary search. You need to use at least ceil(log2(10^10))=34 bit variables for this so unsigned 64 bit QWORD it is. if you do not have such variables you need to implement it from lower bit width variables first.
The binary search mask will be:
m = 2^33 = 1<<33 = 0x0000000200000000
so you first need to implement pow and then root adapting code from linked answer here is C++ result:
#define T_bits 34
#define T_MSB 0x0000000200000000
#define T QWORD
T pow(T x,T y) // power by squaring returns z=x^y where x>=0, y>=0
{
T i,z=1;
for (i=0;i<T_bits;i++) // test all bits from MSB to LSB
{
z*=z;
if (T(y&T_MSB)) z*=x;
y<<=1;
}
return z;
}
T bits(T x) // count how many bits is in x
{
T m=T_MSB,z=T_bits;
for (;m;m>>=1,z--)
if (x>=m) break;
return z;
}
T root(T x,T y) // bin search y-th root returns z=x^(1/y)
{
T m,z;
m=((bits(x)+y-1)/y); // ceil(bits(x)/y)
if (m) m=1<<m; else m=1; // MSB of the result for bin search 2^(ceil(bits(x)/y))
for (z=0;m;m>>=1) // test all bits of x from MSB to LSB
{
z|=m; // set actual bit
if (pow(z,y)>x) z^=m; // clear if result exceedes x
}
return z;
}
for those of you that have just 32 bit arithmetics and have lover limit n<2^32 change the defines to:
#define T_bits 32
#define T_MSB 0x80000000
#define T DWORD
or use any other variable type you got at your disposal. The T is your data-type T_MSB is MSB bit set and T_bits is used bit count.
If you use:
root(400,5);
it will return 3. You can use your ** instead of pow I can not as my compiler does not recognize ** operator. Now to explanation of binary search
let assume your example. You start with x=1 then test x=2 then x=3 and so on until you cross x^y>=n so in reality you had checked pow(n,1/y) values. if we use n=10000, y=2 that will lead to 100 tests.
The binary search does not increment but set individual bits instead. 10000 has 14 bits so ceil(14/y)=7 so the process will be:
x with set bit| x^y | action
-------------------------------
0100 0000 bin | 4096 | none
0110 0000 bin | 9216 | none
0111 0000 bin | 12544 | clear
0110 1000 bin | 10816 | clear
0110 0100 bin | 10000 | none
0110 0010 bin | 10404 | clear
0110 0001 bin | 10201 | clear
-------------------------------
0110 0000 bin | 10000 | result
leading to only 7 tests instead of your naive 100.

Related

Decimal to Binary based on the logic B[i]*(2)^i Where i=[0,2,3...N-1]

I have a function that takes a binary array and returns a decimal based on the below logic:
1 | -2 | 4 | -8 | 16 | -32 ...
1 | 0 | 0 | 1 | 1 | 1 = 1 + 0 + 0 + (-8) + 16 + (-32) = -23
def bin_to_dec(bin_array):
dec = 0
for i in range(0, len(bin_array)):
if i%2 == 0:
dec += bin_array[i] * 2**i
else:
dec += bin_array[i] * -2**i
print(dec)
return dec
I am struggling with writing the decimal to binary piece of the above logic. As in a function that takes for example -23 as input, and returns [1,0,0,1,1,1]. Any help would be highly appreciated.
You can use a few observations to solve this:
Consider a 5-bit number with the coefficient of 16 as 1. What could be the maximum value of the number? 21 = 1 + 4 + 16. Similarly, minimum value would be 6 = 16 - 2 - 8. So, for any number between [6,21], the coefficient of 16 is guaranteed to be 1.
Similarly, for a 6 bit number, if -32's bit is 1, the range of numbers will be between [-42, 11] -32 - 2 - 8 = -42 and -32 + 16 + 4 + 1 = 11
Now, each number x can be expressed in two ways for our problem:
a. (some binary number <= x) + (some positive value) (for example, 20 = 16+4)
b. (some binary number >= x) + (some negative value) (for example, 7 = 16+(-9))
Combining point #3 and #4, you can determine the most significant bit of the number. Calculate the range for the biggest binary number <= x (by binary number, I mean exponent of 2). If x is outside the upper limit of the range, we'll use method 3b to express it as a sum, or else method 3a.
Example: for 20, biggest exponent = 16 which has range [6,21], so we'll use 3a. However, for 30, we'll have to use 3b and express it as 64 + (some negative value).
Similarly, for negative numbers, you can use the lower bound of range to see which will be the biggest negative exponent. Example: for -9, biggest exponent = -8, which has range [-10,-3]. Since lower bound of -10 < -9, we can express it as -8 + (some negative value). For -14, we'll have to express it as -32 + (some positive value)
Using all of this, you can come with an implementation (either recursive or iterative, your decision). The algorithm would broadly look like:
convert(i):
x = rightmost bit/exponent for i
diff = difference between x and i
return x + convert(diff)
Using -23 as example:
Biggest exponenent <= -23 = -8. Since it is outside -8's range, we make it -32 + (9). Recursively solve for 9.
Biggest exponenent <= 9 = 4. Since it is outside 4's range, we make it 16 + (-7). Recursively solve for 7.
Biggest exponenent <= -7 = -2. Since it is outside -2's range, we make it -8 + (1). Recursively solve for 1.
For 1, we get 1.
So we get (-32)+(16)+(-8)+(1), which was the original summation.

How does less than and greater than work on a logical level in binary?

I see how equality could work by just comparing bit patterns, but how would one write one's own less than and greater than operators? What is the actual process to mechanically compare values to each other?
I assume you want to just know how logic does it? And mimic that? Well here goes:
First off you have to talk about unsigned greater than or less than vs signed greater than vs less than because they matter. Just do three bit numbers to make life easier, it all scales up to N bits wide.
As processor documentation usually states a compare instruction will do a subtraction of the two operands in order to generate flags, so it is a subtract that doesnt save the answer just modifies the flags. That then later jump or branch on some flag pattern can be used. Some processors dont use flags but have a similar solution, they still use the equivalent of flags but just dont save them anywhere. compare and branch if greater than kind of an instruction instead of separate compare and branch if greater than instructions.
What is a subtract in logic? Well in grade school we learned that
a - b = a + (-b).
We also know from intro programming classes that a negative in twos complement means invert and add one so
a - b = a + (~b) + 1.
Note ones complement means to invert ~b in C means invert all the bits it is also known as taking the ones complement.
so 7 - 5 is
1
111
+010
=====
Pretty cool we can use the carry in as the "plus one".
1111
111
+010
=====
010
So the answer is 2 with the carry out set. Carry out set is a good thing means we didnt borrow. Not all processors do the same but so far with a subtract we use an adder but invert the second operand and invert the carry in. If we invert the carry out we can call it a borrow, 7 - 5 doesnt borrow. Again some processor architectures dont invert and call it a borrow they just call it carry out. It still goes into the carry flag if they have flags.
Why does any of this matter? Just hang on.
Lets look at 6-5 5-5 and 4-5 and see what the flags tell us.
1101
110
+010
=====
001
1111
101
+010
=====
000
0001
100
+010
=====
111
So what this means is the carry out tells us (unsigned) less than if 0. If if 1 then greater than or equal. That was using a - b where b is what we were comparing against. So if we then do b - a that would imply that we can get (unsigned) greater than with the carry bit. 5 - 4, 5 - 5, 5 - 6. We already know what 5 - 5 looks like zero with the carry out set
1111
101
011
====
001
0011
101
001
====
111
Yep we can determine (unsigned) greater than or equal or (unsigned) less than or equal using the carry flag. Not less than is the same as greater than or equal and vice versa. You just need to get the operand you want to compare against in the right place. I probably did this backward from every compare instruction as I think they subtract a - b where a is what is being compared against.
Now that you have seen this you can easily scratch out the above math on a piece of paper in a few seconds to know which order you need things and what flags to use. Or do a simple experiment like this with a processor you are using and look at the flags to figure out which is subtracted from which and/or whether or not they invert the carry out and call it a borrow.
We can see from doing it with paper and pencil as in grade school that addition boils down to one column at a time, you have a carry in plus two operands, and you get a result and a carry out. You can cascade the carry out to the carry in of the next column and repeat this for any number of bits you can afford to store.
Some/many instruction sets use flags (carry, zero, signed overflow, and negative are the set you need to do most comparisons). You can see I hope that you dont need assembly language nor an instruction set with flags, you can do this yourself with a programming language that has the basic boolean and math operations.
Untested code I just banged out in this edit window.
unsigned char a;
unsigned char b;
unsigned char aa;
unsigned char bb;
unsigned char c;
aa = a&0xF;
bb = (~b)&0xF;
c = aa + bb + 1;
c >>=4;
a >>=4;
b >>=4;
aa = a&0xF;
bb = (~b)&0xF;
c = c + aa + bb;
c >>=4;
And there you go, using an equals comparison, compare c with zero. And depending on your operand order it tells you (unsigned) less than or greater than. If you want to do more than 8 bits then keep on cascading that add with carry indefinitely.
Signed numbers...
ADDITION (and subtraction) LOGIC DOES NOT KNOW THE DIFFERENCE BETWEEN SIGNED AND UNSIGNED OPERANDS. Important to know. This is the beauty of twos complement. Try it yourself write a program that adds bit patterns together and prints out the bit patterns. Interpret those bit patterns input and output as all unsigned or all signed and you see this works (note some combinations overflow and the result is clipped).
Now saying that the flags do vary for subtraction comparisons. We know from grade school math where we carry the one or whatever over as we see in binary as well. The carry out is an unsigned overflow for unsigned. If set you overflowed we have a 1 we cant fit into our register so the result is too big we fail. Signed overflow though is the V bit which tells us if the carry IN and carry OUT of the msbit were the same or not.
Now lets use four bits, cause I want to. We can do the 5 - 4, 5 - 5, and 5 - 6. These are positive numbers so we have seen this but we didnt look at the V flag nor N flag (nor z flag). The N flag is the msbit of the result which indicates negative using twos complement notation, not to be confused with a sign bit although it is as a side effect, it is just not a separate sign bit that you remove from the number.
11111
0101
1011
=====
0001
c = 1, v = 0, n = 0
11111
0101
1010
=====
0000
c = 1, v = 0, n = 0
00011
0101
1001
=====
1111
c = 0, v = 0, n = 1
Now negative numbers -5 - -6, -5 - -5, -5 - -4
10111
1011
1010
=====
0110
c = 0, v = 1, n = 1
You know what, there is an easier way.
#include <stdio.h>
int main ( void )
{
unsigned int ra;
unsigned int rb;
unsigned int rc;
unsigned int rd;
unsigned int re;
int a;
int b;
for(a=-5;a<=5;a++)
{
for(b=-5;b<=5;b++)
{
ra = a&0xF;
rb = (-b)&0xF;
rc = ra+rb;
re = rc&8;
re >>=3;
rc >>=4;
ra = a&0x7;
rb = (-b)&0x7;
rd = ra+rb;
rd >>=3;
rd += rc;
rd &=1;
printf("%+d vs %+d: c = %u, n = %u, v = %u\n",a,b,rc,re,rd);
}
}
return(0);
}
and a subset of the results
-5 vs -5: c = 1, n = 0, v = 0
-5 vs -4: c = 0, n = 1, v = 0
-4 vs -5: c = 1, n = 0, v = 0
-4 vs -4: c = 1, n = 0, v = 0
-4 vs -3: c = 0, n = 1, v = 0
-3 vs -4: c = 1, n = 0, v = 0
-3 vs -3: c = 1, n = 0, v = 0
-3 vs -2: c = 0, n = 1, v = 0
-2 vs -3: c = 1, n = 0, v = 0
-2 vs -2: c = 1, n = 0, v = 0
-2 vs -1: c = 0, n = 1, v = 0
-1 vs -2: c = 1, n = 0, v = 0
-1 vs -1: c = 1, n = 0, v = 0
-1 vs +0: c = 0, n = 1, v = 0
+0 vs -1: c = 0, n = 0, v = 0
+0 vs +0: c = 0, n = 0, v = 0
+0 vs +1: c = 0, n = 1, v = 0
+1 vs +0: c = 0, n = 0, v = 0
+1 vs +1: c = 1, n = 0, v = 0
+1 vs +2: c = 0, n = 1, v = 0
+3 vs +2: c = 1, n = 0, v = 0
+3 vs +3: c = 1, n = 0, v = 0
+3 vs +4: c = 0, n = 1, v = 0
And I will just tell you the answer...You are looking for n == v or not n == v. So if you compute n and v, then x = (n+v)&1. Then if that is a zero they were equal, if that is a 1 they were not. You can use an equals comparison. When they were not equal b was greater than a. Reverse your operands and you can check b less than a.
You can change the code above to only print out if n and v are equal. So if you are using a processor with only an equals comparison, you can still survive with real programming languages and comparisons.
Some processor manuals may chart this out for you. They may say n==v for one thing or not z and n!=v for the other (LT vs GT). But it could be simplified, from grade school the alligator eats the bigger one a > b when you flip it b < a. So feed the operators in one way and you get a > b, feed them the other way you get b < a.
Equals is just a straight bit comparison that goes through a separate logic path, not something that falls out of the addition. N is grabbed from the msbit of the result. C and V fall out of the addition.
One method that is O(1) over all numbers in the given domain (keeping the number of bits constant) would be to subtract the numbers and check the sign bit. I.e., suppose you have A and B, then
C = A - B
If C's sign bit is 1, then B > A. Otherwise, A >= B.

How to search the minimum n that 10^n ≡ 1 mod(9x) for given x

For given x, I need to calculate the minimum n that equates true for the formula 10^n ≡ 1 (mod 9x)
My algorithm is simple. For i = 1 to inf, I loop it until I get a result. There is always a result if gcd(10, x) = 1. Meanwhile if I don't get a result, I increase i by 1 .
This is really slow for big primes or numbers with a factorization of big values, so I ask if there is another way to calculate it faster. I have tried with threads, getting each thread the next 10^i to calculate. Performance is a bit better, but big primes still don't finish.
You can use Fermat's Little Theorem.
Assuming your x is relatively prime with 10, the following holds:
10 ^ φ(9x) ≡ 1 (mod 9x)
Here φ is Euler's totient function. So you can easily calculate at least one n (not necessarily the smallest) for which your equation holds. To find the smallest such n, just iterate through the list of n's divisors.
Example: x = 89 (a prime number just for simplicity).
9x = 801
φ(9x) = 6 * (89 - 1) = 528 (easy to calculate for a prime number)
The list of divisors of 528:
1
2
3
4
6
8
11
12
16
22
24
33
44
48
66
88
132
176
264
528
Trying each one, you can find that your equation holds for 44:
10 ^ 44 ≡ 1 (mod 801)
I just tried the example, it runs in less than one second:
public class Main {
public static void main(String[] args) {
int n = 1;
int x = 954661;
int v = 10;
while (v != 1) {
n++;
v = (v * 10) % (9*x);
}
System.out.println(n);
}
}
For larger values of x the variables should be of type long.
As you specified you are actually trying to get modulus with 1 that is 1mod(9x).
That will always give you 1.
And you don't have to calculate that part exactly which might reduce your calculation.
On the other hand for 10^n = 1, it will always be 0.
So can you exactly specify what you are trying to do

Generate number with equal probability

You are given a function let’s say bin() which will generate 0 or 1 with equal probability. Now you are given a range of contiguous integers say [a,b] (a and b inclusive).
Write a function say rand() using bin() to generate numbers within range [a,b] with equal probability
The insight you need is that your bin() function returns a single binary digit, or "bit". Invoking it once gives you 0 or 1. If you invoke it twice you get two bits b0 and b1 which can be combined as b1 * 2 + b0, giving you one of 0, 1, 2 or 3 with equal probability. If you invoke it thrice you get three bits b0, b1 and b2. Put them together and you get b2 * 2^2 + b1 * 2 + b0, giving you a member of {0, 1, 2, 3, 4, 5, 6, 7} with equal probability. And so on, as many as you want.
Your range [a, b] has m = b-a+1 values. You just need enough bits to generate a number between 0 and 2^n-1, where n is the smallest value that makes 2^n-1 greater than or equal to m. Then just scale that set to start at a and you're good.
So let's say you are given the range [20, 30]. There are 11 numbers there from 20 to 30 inclusive. 11 is greater than 8 (2^3), but less than 16 (2^4), so you'll need 4 bits. Use bin() to generate four bits b0, b1, b2, and b3. Put them together as x = b3 * 2^3 + b2 * 2^2 + b1 * 2 + b0. You'll get a result, x, between 0 and 15. If x > 11 then generate another four bits. When x <= 11, your answer is x + 20.
Help, but no code:
You can shift the range [0,2 ** n] easily to [a,a+2 ** n]
You can easily produce an equal probability from [0,2**n-1]
If you need a number that isn't a power of 2, just generate a number up to 2 ** n and re-roll if it exceeds the number you need
Subtract the numbers to work out your range:
Decimal: 20 - 10 = 10
Binary : 10100 - 01010 = 1010
Work out how many bits you need to represent this: 4.
For each of these, generate a random 1 or 0:
num_bits = 4
rand[num_bits]
for (x = 0; x < num_bits; ++x)
rand[x] = bin()
Let's say rand[] = [0,1,0,0] after this. Add this number back to the start of your range.
Binary: 1010 + 0100 = 1110
Decimal: 10 + 4 = 14
You can always change the range [a,b] to [0,b-a], denote X = b - a. Then you can define a function rand(X) as follows:
function int rand(X){
int i = 1;
// determine how many bits you need (see above answer for why)
while (X < 2^i) {
i++;
}
// generate the random numbers
Boolean cont = true;
int num = 0;
while (cont == true) {
for (j = 1 to i) {
// this generates num in range [0,2^i -1] with equal prob
// but we need to discard if num is larger than X
num = num + bin() * 2^j;
}
if (num <= X) { cont = false}
}
return num;
}

Fast modulo 3 or division algorithm?

is there a fast algorithm, similar to power of 2, which can be used with 3, i.e. n%3.
Perhaps something that uses the fact that if sum of digits is divisible by three, then the number is also divisible.
This leads to a next question. What is the fast way to add digits in a number? I.e. 37 -> 3 +7 -> 10
I am looking for something that does not have conditionals as those tend to inhibit vectorization
thanks
4 % 3 == 1, so (4^k * a + b) % 3 == (a + b) % 3. You can use this fact to evaluate x%3 for a 32-bit x:
x = (x >> 16) + (x & 0xffff);
x = (x >> 10) + (x & 0x3ff);
x = (x >> 6) + (x & 0x3f);
x = (x >> 4) + (x & 0xf);
x = (x >> 2) + (x & 0x3);
x = (x >> 2) + (x & 0x3);
x = (x >> 2) + (x & 0x3);
if (x == 3) x = 0;
(Untested - you might need a few more reductions.) Is this faster than your hardware can do x%3? If it is, it probably isn't by much.
This comp.compilers item has a specific recommendation for computing modulo 3.
An alternative, especially if the maximium size of the dividend is modest, is to multiply by the reciprocal of 3 as a fixed-point value, with enough bits of precision to handle the maximum size dividend to compute the quotient, and then subtract 3*quotient from the the dividend to get the remainder. All of these multiplies can be implemented with a fixed sequence of shifts-and-adds. The number of instructions will depend on the bit pattern of the reciprocal. This works pretty well when the dividend max is modest in size.
Regarding adding digits in the number... if you want to add the decimal digits, you're going to end up doing what amounts to a number-conversion-to-decimal, which involves divide by 10 somewhere. If you're willing to settle for adding up the digits in base2, you can do this with an easy shift-right and add loop. Various clever tricks can be used to do this in chunks of N bits to speed it up further.
Not sure for your first question, but for your second, you can take advantage of the % operator and integer division:
int num = 12345;
int sum = 0;
while (num) {
sum += num % 10;
num /= 10;
}
This works because 12345 % 10 = 5, 12345 / 10 = 1234 and keep going until num == 0
If you are happy with 1 byte integer division, here's a trick. You could extend it to 2 bytes, 4 bytes, etc.
Division is essentially multiplication by 0.3333. If you want to simulate floating point arithmetic then you need closest approximation for the 256 (decimal) boundary. This is 85, because 85 / 256 = 0.332. So if you multiply your value by 85, you should be getting a value close to the result in the high 8 bits.
Multiplying a value with 85 fast is easy. n * 85 = n * 64 + n * 16 + n * 4 + n. Now all these factors are powers of 2 so you can calculate n * 4 by shifting, then use this value to calculate n * 16, etc. So you have max 5 shifts and 4 additions.
As said, this'll give you approximation. To know how good it is you'll need to check the lower byte of the next value using this rule
n ... is the 16 bit number you want to divide
approx = HI(n*85)
if LO(n*85)>LO((n+1)*85)THEN approx++
And that should do the trick.
Example 1:
3 / 3 =?
3 * 85 = 00000000 11111111 (approx=0)
4 * 85 = 00000001 01010100 (LO(3*85)>LO(4*85)=>approx=1)
result approx=1
Example 2:
254 / 3
254 * 85 = 01010100 01010110 (approx=84)
255 * 85 = 01010100 10101011 (LO(254*85)<LO(255*85), don't increase)
result approx=84
If you're dealing with big-integers, one very fast method is realizing the fact for all
bases 10 +/- multiple-of-3
i.e.
4,7,10,13,16,19,22…. etc
All you have to do is count the digits, then % 3. something like :
** note : x ^ y is power, not bit-wise XOR,
x ** y being the python equivalent
function mod3(__,_) {
#
# can handle bases
# { 4, 7,10,13,16,19,
# 22,25,28,31,34 } w/o conversion
#
# assuming base digits :
#
# 0-9A-X for any base,
# or 0-9a-f for base-16
return \
(length(__)<=+((_+=++_+_)+_^_)\
&& (__~"^[0-9]+$") )\
? (substr(__,_~_,_+_*_+_)+\
substr(__,++_*_--))%+_\
:\
(substr("","",gsub(\
"[_\3-0369-=CFILORUXcf-~]+","",__))\
+ length(__) \
+ gsub("[258BbEeHKNQTW]","",__))%+_
}
This isn't the fastest method possible, but it's one of the more agile methods.

Resources