Given a arbitrary integers p, g, and r and given y such that y = gx mod p where x is an unknown integer quantity, how would one solve for C where C = gr• (gx)-1 mod p?
My math is below, but when I input it in a verifier function, it says the answer is incorrect.
y•u = 1 mod p
y•u = 1 + mp
uy - mp = 1
where u is the inverse of y and m is the set of natural numbers (as inverse of mod requires this)
If I see it right you are looking for Inverse modpow. The math is like this:
ab = a^b % p
ab + c*p = a^b
log(ab+c*p)/log(a) = b
(ab+c*p)^(1/b) = a
where c is integer c={ 0,1,2,3,4... } converting between normal and modular arithmetics. So in your case you want to compute b. The problem is that log(ab+c*p)/log(a) grows very slow with increasing c if p is not much bigger than a. So in such case its faster to use all combinations of b instead until a fit is found something like this in C++:
//---------------------------------------------------------------------------
ALU32 alu;
DWORD modmul(DWORD a,DWORD b,DWORD p) // ans = a*b % p
{
DWORD ch,cl,c,d;
alu.mul(ch,cl,a,b);
alu.div(c,d,ch,cl,p);
return d;
}
//---------------------------------------------------------------------------
DWORD modinv(DWORD a,DWORD p) // a * ans % p = 1
{
DWORD b,c,db,dc,i=0;
db=p/a;
dc=db*a;
for (b=1,c=a;b<p;i++)
{
if (c==1) return b;
b+=db; c+=dc;
while (c<p){ b++; c+=a; }
c-=p;
}
return 0;
}
//---------------------------------------------------------------------------
DWORD modpow(DWORD a,DWORD b,DWORD p) // ans = a^b % p
{ // b is not mod(p) !
DWORD i,d=1;
for (a%=p,i=0;i<32;i++,b<<=1)
{
d=modmul(d,d,p);
if (DWORD(b&0x80000000)) d=modmul(d,a,p);
}
return d;
}
//---------------------------------------------------------------------------
DWORD imodpow(DWORD ab,DWORD a,DWORD p) // ab = a^ans % p
{ // ans is not mod(p) !
DWORD b,AB;
for (AB=1,b=0;;)
{
if (AB==ab) return b;
b++; if (!b) return 0;
AB=modmul(AB,a,p);
}
}
//---------------------------------------------------------------------------
of coarse this is SLOOOOW that is why is this used for cryptography...
Also beware there are multiple valid solutions and the first one found might not be the one you're seeking so you need to add additional conditions ...
The ALU32.h can be found in here Cant make value propagate through carry
And the modular arithmetics is based on this: Modular arithmetics and NTT (finite field DFT) optimizations
Here a sample for comparison (ignore VCL and tbeg/tend/tstr functions):
DWORD a=87654321,b=12345678,p=0xC0000001,ab,bb;
tbeg(); ab=modpow(a,b,p); tend(); mm_log->Lines->Add(AnsiString().sprintf("%8u^%8u mod %u = %u ",a,b ,p,ab)+tstr(1));
tbeg(); bb=imodpow(ab,a,p); tend(); mm_log->Lines->Add(AnsiString().sprintf("%8u^%8u mod %u = %u ",a,bb,p,ab)+tstr(1));
and output:
87654321^12345678 mod 3221225473 = 3038293251 [ 0.002 ms]
87654321^12345678 mod 3221225473 = 3038293251 [ 421.910 ms]
PS.
There might be some more advanced approaches from number theory if the p is special like prime, composite of two primes or even n-th root of unity ... but that is in galaxy far far away from mine reach of expertise.
[edit1]
from your newly posted question its finally more clear that you really just wanted modular inverse and has nothing to do with imodpow. So what you want is this:
a*b % p = 1
where b is unknown so simply try all b in increasing manner where a*b % p is just truncated by p towards zero and if the result is 1 you found your answer. I updated the code above with modinv function doing exactly that + some optimization. However I think there are even faster approaches for this using GCD or something.
Here another test sample:
DWORD a=87654321,b=12345678,p=0xC0000001,ab,bb;
ab=modmul(a,b,p);
tbeg(); bb=modinv(b,p); tend(); mm_log->Lines->Add(AnsiString().sprintf(" 1/%8u mod %u = %u ",b,p,bb)+tstr(1));
tbeg(); a =modmul(b,bb,p); tend(); mm_log->Lines->Add(AnsiString().sprintf("%8u*%8u mod %u = %u ",b,bb,p,a)+tstr(1));
tbeg(); a =modmul(ab,bb,p); tend(); mm_log->Lines->Add(AnsiString().sprintf("%8u*%8u mod %u = %u ",ab,bb,p,a)+tstr(1));
And output:
1/12345678 mod 3221225473 = 165081805 [ 4.999 ms]
12345678*165081805 mod 3221225473 = 1 [ 0.000 ms]
652073126*165081805 mod 3221225473 = 87654321 [ 0.000 ms]
Related
According to :help rand(),
rand([{expr}])
Return a pseudo-random Number generated with an xoshiro128**
algorithm using seed {expr}. The returned number is 32 bits,
also on 64 bits systems, for consistency.
{expr} can be initialized by srand() and will be updated by
rand(). If {expr} is omitted, an internal seed value is used
and updated.
Examples:
:echo rand()
:let seed = srand()
:echo rand(seed)
:echo rand(seed) % 16 " random number 0 - 15
It doesn't explain how a seed is changed every time rand() is called, but I expected it to be deterministically altered because
C++'s std::rand() does so,
and Wikipedia says
A pseudorandom number generator (PRNG), also known as a deterministic random bit generator (DRBG), is an algorithm...
However, in the code below, the value of a is deterministic but the values of b are not deterministic; they take different values when you restart the script.
let seed = srand(0)
let a = rand(seed) "deterministic
let b = rand() "not deterministic (why?)
echo [a, b]
let seed = [0, 1, 2, 3]
let a = rand(seed) "deterministic
let b = rand() "not deterministic (why?)
echo [a, b]
Is this an expected behavior? I think the behavior contradicts the documentation.
Environments:
~ $ vi --version
VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Apr 30 2020 13:32:36)
Included patches: 1-664
An algorithm used in Vim is fully deterministic. What creates a confusion is the fact that calling rand(seed) updates the seed "in place", but does not update any internal value(s). Therefore any subsequent rand() uses another (more or less random - quality depends on platform) internal seed value. So if you want to produce fully deterministic sequence, you must consequently invoke rand(seed) with the same variable.
This behaviour is easy to deduce from Vim's source code. Also :h rand() says that:
Return a pseudo-random Number generated with an xoshiro128**
algorithm using seed {expr}. The returned number is 32 bits,
also on 64 bits systems, for consistency.
{expr} can be initialized by srand() and will be updated by
rand(). If {expr} is omitted, an internal seed value is used
and updated.
If you find the wording misleading you can open an issue on github.
The documentation is badly written but the behavior is actually the expected one from the source code's perspective.
Analysis
rand() is defined as f_rand() in src/evalfunc.c. From the snippet at the end of this answer, we know some things:
f_rand() has only two sets of static variables: gx, ..., gw and initialized.
gx, ..., gw are the internal seeds. Their values are touched and referenced only when f_rand() is called with no argument (i.e. when argvars[0].v_type == VAR_UNKNOWN).
initialized remembers if f_rand() has ever been called with no argument and it is also touched and referenced only when f_rand() is called with no argument.
When f_rand() is called with a seed,
The value of the seed is used once and that is not saved as a static variable. In other words, the sentence "{expr} can be initialized by srand() and will be updated by rand()" in the documentation is nothing but a "lie"; {expr} is not remembered and thus not updated by the subsequent f_rand().
The value of the seed is updated in place via the pointers lx, ..., lw.
Conclusion
The sentence
{expr} can be initialized by srand() and will be updated by rand()
shall be modified to
{expr} can be initialized by srand() and will be updated by rand({expr}). You may want to store a seed into a variable and pass it to rand() since {expr} is not remembered in the function.
If you need the deterministic rand(), do this:
let seed = srand(0)
let a = rand(seed) "The value of `seed` is changed in place.
let b = rand(seed) "ditto
echo [a, b]
The Source Code of rand()
#define ROTL(x, k) ((x << k) | (x >> (32 - k)))
#define SPLITMIX32(x, z) ( \
z = (x += 0x9e3779b9), \
z = (z ^ (z >> 16)) * 0x85ebca6b, \
z = (z ^ (z >> 13)) * 0xc2b2ae35, \
z ^ (z >> 16) \
)
#define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \
result = ROTL(y * 5, 7) * 9; \
t = y << 9; \
z ^= x; \
w ^= y; \
y ^= z, x ^= w; \
z ^= t; \
w = ROTL(w, 11);
/*
* "rand()" function
*/
static void
f_rand(typval_T *argvars, typval_T *rettv)
{
list_T *l = NULL;
static UINT32_T gx, gy, gz, gw;
static int initialized = FALSE;
listitem_T *lx, *ly, *lz, *lw;
UINT32_T x, y, z, w, t, result;
if (argvars[0].v_type == VAR_UNKNOWN)
{
// When no argument is given use the global seed list.
if (initialized == FALSE)
{
// Initialize the global seed list.
init_srand(&x);
gx = SPLITMIX32(x, z);
gy = SPLITMIX32(x, z);
gz = SPLITMIX32(x, z);
gw = SPLITMIX32(x, z);
initialized = TRUE;
}
SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw);
}
else if (argvars[0].v_type == VAR_LIST)
{
l = argvars[0].vval.v_list;
if (l == NULL || list_len(l) != 4)
goto theend;
lx = list_find(l, 0L);
ly = list_find(l, 1L);
lz = list_find(l, 2L);
lw = list_find(l, 3L);
if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
x = (UINT32_T)lx->li_tv.vval.v_number;
y = (UINT32_T)ly->li_tv.vval.v_number;
z = (UINT32_T)lz->li_tv.vval.v_number;
w = (UINT32_T)lw->li_tv.vval.v_number;
SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w);
lx->li_tv.vval.v_number = (varnumber_T)x;
ly->li_tv.vval.v_number = (varnumber_T)y;
lz->li_tv.vval.v_number = (varnumber_T)z;
lw->li_tv.vval.v_number = (varnumber_T)w;
}
else
goto theend;
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = (varnumber_T)result;
return;
theend:
semsg(_(e_invarg2), tv_get_string(&argvars[0]));
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = -1;
}
I'm struggling with this problem I've found in a competitive programming book, but without a solution how to do it. For given two integers A and B (can fit in 64-bit integer type), where A is odd, find a pair of numbers X and Y such that A = X*Y and B = X xor Y.
My approach was to list all divisors of A and try pairing numbers under sqrt(A) with numbers over sqrt(A) that multiply up to A and see if their xor is equal to B. But I don't know if that's efficient enough.
What would be a good solution/algorithm to this problem?
You know that at least one factor is <= sqrt(A). Let's make that one X.
The length of X in bits will be about half the length of A.
The upper bits of X, therefore -- the ones higher in value than sqrt(A) -- are all 0, and the corresponding bits in B must have the same value as the corresponding bits in Y.
Knowing the upper bits of Y gives you a pretty small range for the corresponding factor X = A/Y. Calculate Xmin and Xmax corresponding to the largest and smallest possible values for Y, respectively. Remember that Xmax must also be <= sqrt(A).
Then just try all the possible Xs between Xmin and Xmax. There won't be too many, so it won't take very long.
The other straightforward way to solve this problem relies on the fact that the lower n bits of XY and X xor Y depend only on the lower n bits of X and Y. Therefore, you can use the possible answers for the lower n bits to restrict the possible answers for the lower n+1 bits, until you're done.
I've worked out that, unfortunately, there can be more than one possibility for a single n. I don't know how often there will be a lot of possibilities, but it's probably not too often if at all, so this may be fine in a competitive context. Probabilistically, there will only be a few possibilities, since a solution for n bits will provide either 0 or two solutions for n+1 bits, with equal probability.
It seems to work out pretty well for random input. Here's the code I used to test it:
public static void solve(long A, long B)
{
List<Long> sols = new ArrayList<>();
List<Long> prevSols = new ArrayList<>();
sols.add(0L);
long tests=0;
System.out.print("Solving "+A+","+B+"... ");
for (long bit=1; (A/bit)>=bit; bit<<=1)
{
tests += sols.size();
{
List<Long> t = prevSols;
prevSols = sols;
sols = t;
}
final long mask = bit|(bit-1);
sols.clear();
for (long prevx : prevSols)
{
long prevy = (prevx^B) & mask;
if ((((prevx*prevy)^A)&mask) == 0)
{
sols.add(prevx);
}
long x = prevx | bit;
long y = (x^B)&mask;
if ((((x*y)^A)&mask) == 0)
{
sols.add(x);
}
}
}
tests += sols.size();
{
List<Long> t = prevSols;
prevSols = sols;
sols = t;
}
sols.clear();
for (long testx: prevSols)
{
if (A/testx >= testx)
{
long testy = B^testx;
if (testx * testy == A)
{
sols.add(testx);
}
}
}
System.out.println("" + tests + " checks -> X=" + sols);
}
public static void main(String[] args)
{
Random rand = new Random();
for (int range=Integer.MAX_VALUE; range > 32; range -= (range>>5))
{
long A = rand.nextLong() & Long.MAX_VALUE;
long X = (rand.nextInt(range)) + 2L;
X|=1;
long Y = A/X;
if (Y==0)
{
Y = rand.nextInt(65536);
}
Y|=1;
solve(X*Y, X^Y);
}
}
You can see the results here: https://ideone.com/cEuHkQ
Looks like it usually only takes a couple thousand checks.
Here's a simple recursion that observes the rules we know: (1) the least significant bits of both X and Y are set since only odd multiplicands yield an odd multiple; (2) if we set X to have the highest set bit of B, Y cannot be greater than sqrt(A); and (3) set bits in X or Y according to the current bit in B.
The following Python code resulted in under 300 iterations for all but one of the random pairs I picked from Matt Timmermans' example code. But the first one took 231,199 iterations :)
from math import sqrt
def f(A, B):
i = 64
while not ((1<<i) & B):
i = i - 1
X = 1 | (1 << i)
sqrtA = int(sqrt(A))
j = 64
while not ((1<<j) & sqrtA):
j = j - 1
if (j > i):
i = j + 1
memo = {"it": 0, "stop": False, "solution": []}
def g(b, x, y):
memo["it"] = memo["it"] + 1
if memo["stop"]:
return []
if y > sqrtA or y * x > A:
return []
if b == 0:
if x * y == A:
memo["solution"].append((x, y))
memo["stop"] = True
return [(x, y)]
else:
return []
bit = 1 << b
if B & bit:
return g(b - 1, x, y | bit) + g(b - 1, x | bit, y)
else:
return g(b - 1, x | bit, y | bit) + g(b - 1, x, y)
g(i - 1, X, 1)
return memo
vals = [
(6872997084689100999, 2637233646), # 1048 checks with Matt's code
(3461781732514363153, 262193934464), # 8756 checks with Matt's code
(931590259044275343, 5343859294), # 4628 checks with Matt's code
(2390503072583010999, 22219728382), # 5188 checks with Matt's code
(412975927819062465, 9399702487040), # 8324 checks with Matt's code
(9105477787064988985, 211755297373604352), # 3204 checks with Matt's code
(4978113409908739575,67966612030), # 5232 checks with Matt's code
(6175356111962773143,1264664368613886), # 3756 checks with Matt's code
(648518352783802375, 6) # B smaller than sqrt(A)
]
for A, B in vals:
memo = f(A, B)
[(x, y)] = memo["solution"]
print "x, y: %s, %s" % (x, y)
print "A: %s" % A
print "x*y: %s" % (x * y)
print "B: %s" % B
print "x^y: %s" % (x ^ y)
print "%s iterations" % memo["it"]
print ""
Output:
x, y: 4251585939, 1616572541
A: 6872997084689100999
x*y: 6872997084689100999
B: 2637233646
x^y: 2637233646
231199 iterations
x, y: 262180735447, 13203799
A: 3461781732514363153
x*y: 3461781732514363153
B: 262193934464
x^y: 262193934464
73 iterations
x, y: 5171068311, 180154313
A: 931590259044275343
x*y: 931590259044275343
B: 5343859294
x^y: 5343859294
257 iterations
x, y: 22180179939, 107776541
A: 2390503072583010999
x*y: 2390503072583010999
B: 22219728382
x^y: 22219728382
67 iterations
x, y: 9399702465439, 43935
A: 412975927819062465
x*y: 412975927819062465
B: 9399702487040
x^y: 9399702487040
85 iterations
x, y: 211755297373604395, 43
A: 9105477787064988985
x*y: 9105477787064988985
B: 211755297373604352
x^y: 211755297373604352
113 iterations
x, y: 68039759325, 73164771
A: 4978113409908739575
x*y: 4978113409908739575
B: 67966612030
x^y: 67966612030
69 iterations
x, y: 1264664368618221, 4883
A: 6175356111962773143
x*y: 6175356111962773143
B: 1264664368613886
x^y: 1264664368613886
99 iterations
x, y: 805306375, 805306369
A: 648518352783802375
x*y: 648518352783802375
B: 6
x^y: 6
59 iterations
I have to find out the integral solution of a equation ax+by=c such that x>=0 and y>=0 and value of (x+y) is minimum.
I know if c%gcd(a,b)}==0 then it's always possible. How to find the values of x and y?
My approach
for(i 0 to 2*c):
x=i
y= (c-a*i)/b
if(y is integer)
ans = min(ans,x+y)
Is there any better way to do this ? Having better time complexity.
Using the Extended Euclidean Algorithm and the theory of linear Diophantine equations there is no need to search. Here is a Python 3 implementation:
def egcd(a,b):
s,t = 1,0 #coefficients to express current a in terms of original a,b
x,y = 0,1 #coefficients to express current b in terms of original a,b
q,r = divmod(a,b)
while(r > 0):
a,b = b,r
old_x, old_y = x,y
x,y = s - q*x, t - q*y
s,t = old_x, old_y
q,r = divmod(a,b)
return b, x ,y
def smallestSolution(a,b,c):
d,x,y = egcd(a,b)
if c%d != 0:
return "No integer solutions"
else:
u = a//d #integer division
v = b//d
w = c//d
x = w*x
y = w*y
k1 = -x//v if -x % v == 0 else 1 + -x//v #k1 = ceiling(-x/v)
x1 = x + k1*v # x + k1*v is solution with smallest x >= 0
y1 = y - k1*u
if y1 < 0:
return "No nonnegative integer solutions"
else:
k2 = y//u #floor division
x2 = x + k2*v #y-k2*u is solution with smallest y >= 0
y2 = y - k2*u
if x2 < 0 or x1+y1 < x2+y2:
return (x1,y1)
else:
return (x2,y2)
Typical run:
>>> smallestSolution(1001,2743,160485)
(111, 18)
The way it works: first use the extended Euclidean algorithm to find d = gcd(a,b) and one solution, (x,y). All other solutions are of the form (x+k*v,y-k*u) where u = a/d and v = b/d. Since x+y is linear, it has no critical points, hence is minimized in the first quadrant when either x is as small as possible or y is as small as possible. The k above is an arbitrary integer parameter. By appropriate use of floor and ceiling you can locate the integer points with either x as small as possible or y is as small as possible. Just take the one with the smallest sum.
On Edit: My original code used the Python function math.ceiling applied to -x/v. This is problematic for very large integers. I tweaked it so that the ceiling is computed with just int operations. It can now handle arbitrarily large numbers:
>>> a = 236317407839490590865554550063
>>> b = 127372335361192567404918884983
>>> c = 475864993503739844164597027155993229496457605245403456517677648564321
>>> smallestSolution(a,b,c)
(2013668810262278187384582192404963131387, 120334243940259443613787580180)
>>> x,y = _
>>> a*x+b*y
475864993503739844164597027155993229496457605245403456517677648564321
Most of the computation takes place in the running the extended Euclidean algorithm, which is known to be O(min(a,b)).
First let assume a,b,c>0 so:
a.x+b.y = c
x+y = min(xi+yi)
x,y >= 0
a,b,c > 0
------------------------
x = ( c - b.y )/a
y = ( c - a.x )/b
c - a.x >= 0
c - b.y >= 0
c >= b.y
c >= a.x
x <= c/x
y <= c/b
So naive O(n) solution is in C++ like this:
void compute0(int &x,int &y,int a,int b,int c) // naive
{
int xx,yy;
xx=-1; yy=-1;
for (y=0;;y++)
{
x = c - b*y;
if (x<0) break; // y out of range stop
if (x%a) continue; // non integer solution
x/=a; // remember minimal solution
if ((xx<0)||(x+y<=xx+yy)) { xx=x; yy=y; }
}
x=xx; y=yy;
}
if no solution found it returns -1,-1 If you think about the equation a bit then you should realize that min solution will be when x or y is minimal (which one depends on a<b condition) so adding such heuristics we can increase only the minimal coordinate until first solution found. This will speed up considerably the whole thing:
void compute1(int &x,int &y,int a,int b,int c)
{
if (a<=b){ for (x=0,y=c;y>=0;x++,y-=a) if (y%b==0) { y/=b; return; } }
else { for (y=0,x=c;x>=0;y++,x-=b) if (x%a==0) { x/=a; return; } }
x=-1; y=-1;
}
I measured this on my setup:
x y ax+by x+y a=50 b=105 c=500000000
[ 55.910 ms] 10 4761900 500000000 4761910 naive
[ 0.000 ms] 10 4761900 500000000 4761910 opt
x y ax+by x+y a=105 b=50 c=500000000
[ 99.214 ms] 4761900 10 500000000 4761910 naive
[ 0.000 ms] 4761900 10 500000000 4761910 opt
The ~2.0x difference for naive method times is due to a/b=~2.0and selecting worse coordinate to iterate in the second run.
Now just handle special cases when a,b,c are zero (to avoid division by zero)...
I'm quite new to Haskell, and to learn it better I started solving problems here and there and I ended up with this (project Euler 34).
145 is a curious number, as 1! + 4! + 5! = 1 + 24 + 120 = 145.
Find the sum of all numbers which are equal to the sum of the factorial >of their digits.
Note: as 1! = 1 and 2! = 2 are not sums they are not included.
I wrote a C and an Haskell brute force solution.
Could someone explain me the Haskell version is ~15x (~0.450 s vs ~6.5s )slower than the C implementation and how to possibly tune and speedup the Haskell solution?
unsigned int solve(){
unsigned int result = 0;
unsigned int i=10;
while(i<2540161){
unsigned int sumOfFacts = 0;
unsigned int number = i;
while (number > 0) {
unsigned int d = number % 10;
number /= 10;
sumOfFacts += factorial(d);
}
if (sumOfFacts == i)
result += i;
i++;
}
return result;
}
here the haskell solution
--BRUTE FORCE SOLUTION
solve:: Int
solve = sum (filter (\x-> sfc x 0 == x) [10..2540160])
--sum factorial of digits
sfc :: Int -> Int -> Int
sfc 0 acc = acc
sfc n acc = sfc n' (acc+fc r)
where
n' = div n 10
r = mod n 10 --n-(10*n')
fc 0 =1
fc 1 =1
fc 2 =2
fc 3 =6
fc 4 =24
fc 5 =120
fc 6 =720
fc 7 =5040
fc 8 =40320
fc 9 =362880
First, compile with optimizations. With ghc-7.10.1 -O2 -fllvm, the Haskell version runs in 0.54 secs for me. This is already pretty good.
If we want to do even better, we should first replace div with quot and mod with rem. div and mod do some extra work, because they handle the rounding of negative numbers differently. Since we only have positive numbers here, we should switch to the faster functions.
Second, we should replace the pattern matching in fc with an array lookup. GHC uses a branching construct for Int patterns, and uses binary search when the number of cases is large enough. We can do better here with a lookup.
The new code looks like this:
import qualified Data.Vector.Unboxed as V
facs :: V.Vector Int
facs =
V.fromList [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880]
--BRUTE FORCE SOLUTION
solve:: Int
solve = sum (filter (\x-> sfc x 0 == x) [10..2540160])
--sum factorial of digits
sfc :: Int -> Int -> Int
sfc 0 acc = acc
sfc n acc = sfc n' (acc + V.unsafeIndex facs r)
where
(n', r) = quotRem n 10
main = print solve
It runs in 0.095 seconds on my computer.
There are two random functions f1(),f2().
f1() returns 1 with probability p1, and 0 with probability 1-p1.
f2() returns 1 with probability p2, and 0 with probability 1-p2.
I want to implement a new function f3() which returns 1 with probability p3(a given probability), and returns 0 with probability 1-p3. In the implemetion of function f3(), we can use function f1() and f2(), but you can't use any other random function.
If p3=0.5, an example of implemention:
int f3()
{
do
{
int a = f1();
int b = f1();
if (a==b) continue;
// when reachs here
// a==1 with probability p1(1-p1)
// b==1 with probability (1-p1)p1
if (a==1) return 1;//now returns 1 with probability 0.5
if (b==1) return 0;
}while(1)
}
This implemention of f3() will give a random function returns 1 with probability 0.5, and 0 with probability 0.5. But how to implement the f3() with p3=0.4? I have no idea.
I wonder, is that task possible? And how to implement f3()?
Thanks in advance.
p1 = 0.77 -- arbitrary value between 0 and 1
function f1()
if math.random() < p1 then
return 1
else
return 0
end
end
-- f1() is enough. We don't need f2()
p3 = 0.4 -- arbitrary value between 0 and 1
--------------------------
function f3()
left = 0
rigth = 1
repeat
middle = left + (right - left) * p1
if f1() == 1 then
right = middle
else
left = middle
end
if right < p3 then -- completely below
return 1
elseif left >= p3 then -- completely above
return 0
end
until false -- loop forever
end
This can be solved if p3 is a rational number.
We should use conditional probabilities for this.
For example, if you want to make this for p3=0.4, the method is the following:
Calculate the fractional form of p3. In our case it is p3=0.4=2/5.
Now generate as many random variables from the same distribution (let's say, from f1, we won't use f2 anyway) as the denominator, call them X1, X2, X3, X4, X5.
We should regenerate all these random X variables until their sum equals the numerator in the fractional form of p3.
Once this is achieved then we just return X1 (or any other Xn, where n was chosen independently of the values of the X variables). Since there are 2 1s among the 5 X variables (because their sum equals the numerator), the probability of X1 being 1 is exactly p3.
For irrational p3, the problem cannot be solved by using only f1. I'm not sure now, but I think, it can be solved for p3 of the form p1*q+p2*(1-q), where q is rational with a similar method, generating the appropriate amount of Xs with distribution f1 and Ys with distribution f2, until they have a specific predefined sum, and returning one of them. This still needs to be detailed.
First to say, that's a nice problem to tweak one's brain. I managed to solve the problem for p3 = 0.4, for what you just asked for! And I think, generalisation of such problem, is not so trivial. :D
Here is how, you can solve it for p3 = 0.4:
The intuition comes from your example. If we generate a number from f1() five times in an iteration, (see the code bellow), we can have 32 types of results like bellow:
1: 00000
2: 00001
3: 00010
4: 00011
.....
.....
32: 11111
Among these, there are 10 such results with exactly two 1's in it! After identifying this, the problem becomes simple. Just return 1 for any of the 4 combinations and return 0 for 6 others! (as probability 0.4 means getting 1, 4 times out of 10). You can do that like bellow:
int f3()
{
do{
int a[5];
int numberOfOneInA = 0;
for(int i = 0; i < 5; i++){
a[i] = f1();
if(a[i] == 1){
numberOfOneInA++;
}
}
if (numberOfOneInA != 2) continue;
else return a[0]; //out of 10 times, 4 times a[0] is 1!
}while(1)
}
Waiting to see a generalised solution.
Cheers!
Here is an idea that will work when p3 is of a form a/2^n (a rational number with a denominator that is a power of 2).
Generate n random numbers with probability distribution of 0.5:
x1, x2, ..., xn
Interpret this as a binary number in the range 0...2^n-1; each number in this range has equal probability. If this number is less than a, return 1, else return 0.
Now, since this question is in a context of computer science, it seems reasonable to assume that p3 is in a form of a/2^n (this a common representation of numbers in computers).
I implement the idea of anatolyg and Egor:
inline double random(void)
{
return static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
}
const double p1 = 0.8;
int rand_P1(void)
{
return random() < p1;
}
int rand_P2(void)//return 0 with 0.5
{
int x, y; while (1)
{
mystep++;
x = rand_P1(); y = rand_P1();
if (x ^ y) return x;
}
}
double p3 = random();
int rand_P3(void)//anatolyg's idea
{
double tp = p3; int bit, x;
while (1)
{
if (tp * 2 >= 1) {bit = 1; tp = tp * 2 - 1;}
else {bit = 0; tp = tp * 2;}
x = rand_P2();
if (bit ^ x) return bit;
}
}
int rand2_P3(void)//Egor's idea
{
double left = 0, right = 1, mid;
while (1)
{
dashenstep++;
mid = left + (right - left) * p1;
int x = rand_P1();
if (x) right = mid; else left = mid;
if (right < p3) return 1;
if (left > p3) return 0;
}
}
With massive math computings, I get, assuming P3 is uniformly distributed in [0,1), then the expectation of Egor is (1-p1^2-(1-p1)^2)^(-1). And anatolyg is 2(1-p1^2-(1-p1)^2)^(-1).
Speaking Algorithmically , Yes It is possible to do that task done .
Even Programmatically , It is possible , but a complex problem .
Lets take an example .
Let
F1(1) = .5 which means F1(0) =.5
F2(2) = .8 which means F1(0) =.2
Let Suppose You need a F3, such that F3(1)= .128
Lets try Decomposing it .
.128
= (2^7)*(10^-3) // decompose this into know values
= (8/10)*(8/10)*(2/10)
= F2(1)&F2(1)*(20/100) // as no Fi(1)==2/10
= F2(1)&F2(1)*(5/10)*(4/10)
= F2(1)&F2(1)&F1(1)*(40/100)
= F2(1)&F2(1)&F1(1)*(8/10)*(5/10)
= F2(1)&F2(1)&F1(1)&F2(1)&F1(1)
So F3(1)=.128 if we define F3()=F2()&F2()&F2()&F1()&F1()
Similarly if you want F4(1)=.9 ,
You give it as F4(0)=F1(0) | F2(0) =F1(0)F2(0)=.5.2 =.1 ,which mean F4(1)=1-0.1=0.9
Which means F4 is zero only when both are zero which happens .
So making use this ( & , | and , not(!) , xor(^) if you want ) operations with a combinational use of f1,f2 will surely give you the F3 which is made purely out of f1,f2,
Which may be NP hard problem to find the combination which gives you the exact probability.
So, Finally the answer to your question , whether it is possible or not ? is YES and this is one way of doing it, may be many hacks can be made into it this to optimize this, which gives you any optimal way .