Adding values in various combinations - algorithm

Not sure how best to explain it, other than using an example...
Imagine having a client with 10 outstanding invoices, and one day they provide you with a cheque, but do not tell you which invoices it's for.
What would be the best way to return all the possible combination of values which can produce the required total?
My current thinking is a kind of brute force method, which involves using a self-calling function that runs though all the possibilities (see current version).
For example, with 3 numbers, there are 15 ways to add them together:
A
A + B
A + B + C
A + C
A + C + B
B
B + A
B + A + C
B + C
B + C + A
C
C + A
C + A + B
C + B
C + B + A
Which, if you remove the duplicates, give you 7 unique ways to add them together:
A
A + B
A + B + C
A + C
B
B + C
C
However, this kind of falls apart after you have:
15 numbers (32,767 possibilities / ~2 seconds to calculate)
16 numbers (65,535 possibilities / ~6 seconds to calculate)
17 numbers (131,071 possibilities / ~9 seconds to calculate)
18 numbers (262,143 possibilities / ~20 seconds to calculate)
Where, I would like this function to handle at least 100 numbers.
So, any ideas on how to improve it? (in any language)

This is a pretty common variation of the subset sum problem, and it is indeed quite hard. The section on the Pseudo-polynomial time dynamic programming solution on the page linked is what you're after.

This is strictly for the number of possibilities and does not consider overlap. I am unsure what you want.
Consider the states that any single value could be at one time - it could either be included or excluded. That is two different states so the number of different states for all n items will be 2^n. However there is one state that is not wanted; that state is when none of the numbers are included.
And thus, for any n numbers, the number of combinations is equal to 2^n-1.
def setNumbers(n): return 2**n-1
print(setNumbers(15))
These findings are very closely related to combinations and permutations.
Instead, though, I think you may be after telling whether given a set of values any combination of them sum to a value k. For this Bill the Lizard pointed you in the right direction.
Following from that, and bearing in mind I haven't read the whole Wikipedia article, I propose this algorithm in Python:
def combs(arr):
r = set()
for i in range(len(arr)):
v = arr[i]
new = set()
new.add(v)
for a in r: new.add(a+v)
r |= new
return r
def subsetSum(arr, val):
middle = len(arr)//2
seta = combs(arr[:middle])
setb = combs(arr[middle:])
for a in seta:
if (val-a) in setb:
return True
return False
print(subsetSum([2, 3, 5, 8, 9], 8))
Basically the algorithm works as this:
Splits the list into 2 lists of approximately half the length. [O(n)]
Finds the set of subset sums. [O(2n/2 n)]
Loops through the first set of up to 2floor(n/2)-1 values seeing if the another value in the second set would total to k. [O(2n/2 n)]
So I think overall it runs in O(2n/2 n) - still pretty slow but much better.

Sounds like a bin packing problem. Those are NP-complete, i.e. it's nearly impossible to find a perfect solution for large problem sets. But you can get pretty close using heuristics, which are probably applicable to your problem even if it's not strictly a bin packing problem.

This is a variant on a similar problem.
But you can solve this by creating a counter with n bits. Where n is the amount of numbers. Then you count from 000 to 111 (n 1's) and for each number a 1 is equivalent to an available number:
001 = A
010 = B
011 = A+B
100 = C
101 = A+C
110 = B+C
111 = A+B+C
(But that was not the question, ah well I leave it as a target).

It's not strictly a bin packing problem. It's a what combination of values could have produced another value.
It's more like the change making problem, which has a bunch of papers detailing how to solve it. Google pointed me here: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.57.3243

I don't know how often it would work in practice as there are many exceptions to this oversimplified case, but here's a thought:
In a perfect world, the invoices are going to be paid up to a certain point. People will pay A, or A+B, or A+B+C, but not A+C - if they've received invoice C then they've received invoice B already. In the perfect world the problem is not to find to a combination, it's to find a point along a line.
Rather than brute forcing every combination of invoice totals, you could iterate through the outstanding invoices in order of date issued, and simply add each invoice amount to a running total which you compare with the target figure.
Back in the real world, it's a trivially quick check you can do before launching into the heavy number-crunching, or chasing them up. Any hits it gets are a bonus :)

Here is an optimized Object-Oriented version of the exact integer solution to the Subset Sums problem(Horowitz, Sahni 1974). On my laptop (which is nothing special) this vb.net Class solves 1900 subset sums a second (for 20 items):
Option Explicit On
Public Class SubsetSum
'Class to solve exact integer Subset Sum problems'
''
' 06-sep-09 RBarryYoung Created.'
Dim Power2() As Integer = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32764}
Public ForceMatch As Boolean
Public watch As New Stopwatch
Public w0 As Integer, w1 As Integer, w1a As Integer, w2 As Integer, w3 As Integer, w4 As Integer
Public Function SolveMany(ByVal ItemCount As Integer, ByVal Range As Integer, ByVal Iterations As Integer) As Integer
' Solve many subset sum problems in sequence.'
''
' 06-sep-09 RBarryYoung Created.'
Dim TotalFound As Integer
Dim Items() As Integer
ReDim Items(ItemCount - 1)
'First create our list of selectable items:'
Randomize()
For item As Integer = 0 To Items.GetUpperBound(0)
Items(item) = Rnd() * Range
Next
For iteration As Integer = 1 To Iterations
Dim TargetSum As Integer
If ForceMatch Then
'Use a random value but make sure that it can be matched:'
' First, make a random bitmask to use:'
Dim bits As Integer = Rnd() * (2 ^ (Items.GetUpperBound(0) + 1) - 1)
' Now enumerate the bits and match them to the Items:'
Dim sum As Integer = 0
For b As Integer = 0 To Items.GetUpperBound(0)
'build the sum from the corresponding items:'
If b < 16 Then
If Power2(b) = (bits And Power2(b)) Then
sum = sum + Items(b)
End If
Else
If Power2(b - 15) * Power2(15) = (bits And (Power2(b - 15) * Power2(15))) Then
sum = sum + Items(b)
End If
End If
Next
TargetSum = sum
Else
'Use a completely random Target Sum (low chance of matching): (Range / 2^ItemCount)'
TargetSum = ((Rnd() * Range / 4) + Range * (3.0 / 8.0)) * ItemCount
End If
'Now see if there is a match'
If SolveOne(TargetSum, ItemCount, Range, Items) Then TotalFound += 1
Next
Return TotalFound
End Function
Public Function SolveOne(ByVal TargetSum As Integer, ByVal ItemCount As Integer _
, ByVal Range As Integer, ByRef Items() As Integer) As Boolean
' Solve a single Subset Sum problem: determine if the TargetSum can be made from'
'the integer items.'
'first split the items into two half-lists: [O(n)]'
Dim H1() As Integer, H2() As Integer
Dim hu1 As Integer, hu2 As Integer
If ItemCount Mod 2 = 0 Then
'even is easy:'
hu1 = (ItemCount / 2) - 1 : hu2 = (ItemCount / 2) - 1
ReDim H1((ItemCount / 2) - 1), H2((ItemCount / 2) - 1)
Else
'odd is a little harder, give the first half the extra item:'
hu1 = ((ItemCount + 1) / 2) - 1 : hu2 = ((ItemCount - 1) / 2) - 1
ReDim H1(hu1), H2(hu2)
End If
For i As Integer = 0 To ItemCount - 1 Step 2
H1(i / 2) = Items(i)
'make sure that H2 doesnt run over on the last item of an odd-numbered list:'
If (i + 1) <= ItemCount - 1 Then
H2(i / 2) = Items(i + 1)
End If
Next
'Now generate all of the sums for each half-list: [O( 2^(n/2) * n )] **(this is the slowest step)'
Dim S1() As Integer, S2() As Integer
Dim sum1 As Integer, sum2 As Integer
Dim su1 As Integer = 2 ^ (hu1 + 1) - 1, su2 As Integer = 2 ^ (hu2 + 1) - 1
ReDim S1(su1), S2(su2)
For i As Integer = 0 To su1
' Use the binary bitmask of our enumerator(i) to select items to use in our candidate sums:'
sum1 = 0 : sum2 = 0
For b As Integer = 0 To hu1
If 0 < (i And Power2(b)) Then
sum1 += H1(b)
If i <= su2 Then sum2 += H2(b)
End If
Next
S1(i) = sum1
If i <= su2 Then S2(i) = sum2
Next
'Sort both lists: [O( 2^(n/2) * n )] **(this is the 2nd slowest step)'
Array.Sort(S1)
Array.Sort(S2)
' Start the first half-sums from lowest to highest,'
'and the second half sums from highest to lowest.'
Dim i1 As Integer = 0, i2 As Integer = su2
' Now do a merge-match on the lists (but reversing S2) and looking to '
'match their sum to the target sum: [O( 2^(n/2) )]'
Dim sum As Integer
Do While i1 <= su1 And i2 >= 0
sum = S1(i1) + S2(i2)
If sum < TargetSum Then
'if the Sum is too low, then we need to increase the ascending side (S1):'
i1 += 1
ElseIf sum > TargetSum Then
'if the Sum is too high, then we need to decrease the descending side (S2):'
i2 -= 1
Else
'Sums match:'
Return True
End If
Loop
'if we got here, then there are no matches to the TargetSum'
Return False
End Function
End Class
Here is the Forms code to go along with it:
Public Class frmSubsetSum
Dim ssm As New SubsetSum
Private Sub btnGo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGo.Click
Dim Total As Integer
Dim datStart As Date, datEnd As Date
Dim Iterations As Integer, Range As Integer, NumberCount As Integer
Iterations = CInt(txtIterations.Text)
Range = CInt(txtRange.Text)
NumberCount = CInt(txtNumberCount.Text)
ssm.ForceMatch = chkForceMatch.Checked
datStart = Now
Total = ssm.SolveMany(NumberCount, Range, Iterations)
datEnd = Now()
lblStart.Text = datStart.TimeOfDay.ToString
lblEnd.Text = datEnd.TimeOfDay.ToString
lblRate.Text = Format(Iterations / (datEnd - datStart).TotalMilliseconds * 1000, "####0.0")
ListBox1.Items.Insert(0, "Found " & Total.ToString & " Matches out of " & Iterations.ToString & " tries.")
ListBox1.Items.Insert(1, "Tics 0:" & ssm.w0 _
& " 1:" & Format(ssm.w1 - ssm.w0, "###,###,##0") _
& " 1a:" & Format(ssm.w1a - ssm.w1, "###,###,##0") _
& " 2:" & Format(ssm.w2 - ssm.w1a, "###,###,##0") _
& " 3:" & Format(ssm.w3 - ssm.w2, "###,###,##0") _
& " 4:" & Format(ssm.w4 - ssm.w3, "###,###,##0") _
& ", tics/sec = " & Stopwatch.Frequency)
End Sub
End Class
Let me know if you have any questions.

For the record, here is some fairly simple Java code that uses recursion to solve this problem. It is optimised for simplicity rather than performance, although with 100 elements it seems to be quite fast. With 1000 elements it takes dramatically longer, so if you are processing larger amounts of data you could better use a more sophisticated algorithm.
public static List<Double> getMatchingAmounts(Double goal, List<Double> amounts) {
List<Double> remaining = new ArrayList<Double>(amounts);
for (final Double amount : amounts) {
if (amount > goal) {
continue;
} else if (amount.equals(goal)) {
return new ArrayList<Double>(){{ add(amount); }};
}
remaining.remove(amount);
List<Double> matchingAmounts = getMatchingAmounts(goal - amount, remaining);
if (matchingAmounts != null) {
matchingAmounts.add(amount);
return matchingAmounts;
}
}
return null;
}

Related

How to find the shortest square sum of a number

Find and output the given number's shortest square sum.
Example: 12 = 2^2 + 2^2 + 2^2 (not 3^2 + 1^2 + 1^2 + 1^2)
Output: {2 2 2}
This is min-coin-change problem, where the coins are [1,4,9,...,(ceil(sqrt(n)))^2].
It can be solved using Dynamic Programming (DP) by following the recurrence formula:
D(i,0) = 0
D(i,x) = infinity x<0
D(0,x) = infinity x>0
D(i,x) = min { D(i,x-i^2) + 1, D(i-1,x) }
When building your matrix (assuming bottom-up DP), the element denoted in the matrix in D(ceil(sqrt(n)),n) is the minimal number of "coins" (squared numbers) needed to build your input number.
Getting the actual elements is done by tracking back your choices in the matrix after it is built, and at each point checking if you added a summand or not.
This is explained in more details for similar problems in this thread and this thread.
Here is a visual basic solution to the problem.
An edit would need to be done to cache intermediate answers so that the algorithm would be significantly faster. Currently ... only a value of about 40 to 50 is quickly computed. This is fully working and tested. It only returns the shortest answer and one where the higher value are to the left of other values.
Private Function ShortestSquareSum(x As Integer) As Integer()()
If x < 0 Then
Throw New ArgumentException("Parameter cannot be negative.", "x")
ElseIf x = 0 Then
Return New Integer()() {New Integer() {}}
Else
Dim answers As New List(Of Integer())
Dim shortest As Integer? = Nothing
For y As Integer = Math.Floor(Math.Sqrt(x)) To 1 Step -1
Dim remaining As Integer = x - y * y
Dim tempAnswers As Integer()() = ShortestSquareSum(x - y * y)
For Each answer As Integer() In tempAnswers
Dim currentAnswer As New List(Of Integer)
currentAnswer.Add(y)
currentAnswer.AddRange(answer)
If Not shortest.HasValue OrElse currentAnswer.Count < shortest Then
shortest = currentAnswer.Count
answers.Clear()
answers.Add(currentAnswer.ToArray())
ElseIf currentAnswer.Count = shortest AndAlso (answer.Count = 0 OrElse y > answer(0)) Then
answers.Add(currentAnswer.ToArray())
End If
Next
Next
Return answers.ToArray()
End If
End Function
public static void shortest_square(int n)
{
int i=2;
List<Integer> list= new ArrayList<Integer>();
while(i<=n) || n!=0)
{
if(n%(i*i)==0)
{
n=n-(i*i);
list.add(i);
}
else
{
i++;
}
}
System.out.println(list);
}

Find the smallest regular number that is not less than N

Regular numbers are numbers that evenly divide powers of 60. As an example, 602 = 3600 = 48 × 75, so both 48 and 75 are divisors of a power of 60. Thus, they are also regular numbers.
This is an extension of rounding up to the next power of two.
I have an integer value N which may contain large prime factors and I want to round it up to a number composed of only small prime factors (2, 3 and 5)
Examples:
f(18) == 18 == 21 * 32
f(19) == 20 == 22 * 51
f(257) == 270 == 21 * 33 * 51
What would be an efficient way to find the smallest number satisfying this requirement?
The values involved may be large, so I would like to avoid enumerating all regular numbers starting from 1 or maintaining an array of all possible values.
One can produce arbitrarily thin a slice of the Hamming sequence around the n-th member in time ~ n^(2/3) by direct enumeration of triples (i,j,k) such that N = 2^i * 3^j * 5^k.
The algorithm works from log2(N) = i+j*log2(3)+k*log2(5); enumerates all possible ks and for each, all possible js, finds the top i and thus the triple (k,j,i) and keeps it in a "band" if inside the given "width" below the given high logarithmic top value (when width < 1 there can be at most one such i) then sorts them by their logarithms.
WP says that n ~ (log N)^3, i.e. run time ~ (log N)^2. Here we don't care for the exact position of the found triple in the sequence, so all the count calculations from the original code can be thrown away:
slice hi w = sortBy (compare `on` fst) b where -- hi>log2(N) is a top value
lb5=logBase 2 5 ; lb3=logBase 2 3 -- w<1 (NB!) is log2(width)
b = concat -- the slice
[ [ (r,(i,j,k)) | frac < w ] -- store it, if inside width
| k <- [ 0 .. floor ( hi /lb5) ], let p = fromIntegral k*lb5,
j <- [ 0 .. floor ((hi-p)/lb3) ], let q = fromIntegral j*lb3 + p,
let (i,frac)=properFraction(hi-q) ; r = hi - frac ] -- r = i + q
-- properFraction 12.7 == (12, 0.7)
-- update: in pseudocode:
def slice(hi, w):
lb5, lb3 = logBase(2, 5), logBase(2, 3) -- logs base 2 of 5 and 3
for k from 0 step 1 to floor(hi/lb5) inclusive:
p = k*lb5
for j from 0 step 1 to floor((hi-p)/lb3) inclusive:
q = j*lb3 + p
i = floor(hi-q)
frac = hi-q-i -- frac < 1 , always
r = hi - frac -- r == i + q
if frac < w:
place (r,(i,j,k)) into the output array
sort the output array's entries by their "r" component
in ascending order, and return thus sorted array
Having enumerated the triples in the slice, it is a simple matter of sorting and searching, taking practically O(1) time (for arbitrarily thin a slice) to find the first triple above N. Well, actually, for constant width (logarithmic), the amount of numbers in the slice (members of the "upper crust" in the (i,j,k)-space below the log(N) plane) is again m ~ n^2/3 ~ (log N)^2 and sorting takes m log m time (so that searching, even linear, takes ~ m run time then). But the width can be made smaller for bigger Ns, following some empirical observations; and constant factors for the enumeration of triples are much higher than for the subsequent sorting anyway.
Even with constant width (logarthmic) it runs very fast, calculating the 1,000,000-th value in the Hamming sequence instantly and the billionth in 0.05s.
The original idea of "top band of triples" is due to Louis Klauder, as cited in my post on a DDJ blogs discussion back in 2008.
update: as noted by GordonBGood in the comments, there's no need for the whole band but rather just about one or two values above and below the target. The algorithm is easily amended to that effect. The input should also be tested for being a Hamming number itself before proceeding with the algorithm, to avoid round-off issues with double precision. There are no round-off issues comparing the logarithms of the Hamming numbers known in advance to be different (though going up to a trillionth entry in the sequence uses about 14 significant digits in logarithm values, leaving only 1-2 digits to spare, so the situation may in fact be turning iffy there; but for 1-billionth we only need 11 significant digits).
update2: turns out the Double precision for logarithms limits this to numbers below about 20,000 to 40,000 decimal digits (i.e. 10 trillionth to 100 trillionth Hamming number). If there's a real need for this for such big numbers, the algorithm can be switched back to working with the Integer values themselves instead of their logarithms, which will be slower.
Okay, hopefully third time's a charm here. A recursive, branching algorithm for an initial input of p, where N is the number being 'built' within each thread. NB 3a-c here are launched as separate threads or otherwise done (quasi-)asynchronously.
Calculate the next-largest power of 2 after p, call this R. N = p.
Is N > R? Quit this thread. Is p composed of only small prime factors? You're done. Otherwise, go to step 3.
After any of 3a-c, go to step 4.
a) Round p up to the nearest multiple of 2. This number can be expressed as m * 2.
b) Round p up to the nearest multiple of 3. This number can be expressed as m * 3.
c) Round p up to the nearest multiple of 5. This number can be expressed as m * 5.
Go to step 2, with p = m.
I've omitted the bookkeeping to do regarding keeping track of N but that's fairly straightforward I take it.
Edit: Forgot 6, thanks ypercube.
Edit 2: Had this up to 30, (5, 6, 10, 15, 30) realized that was unnecessary, took that out.
Edit 3: (The last one I promise!) Added the power-of-30 check, which helps prevent this algorithm from eating up all your RAM.
Edit 4: Changed power-of-30 to power-of-2, per finnw's observation.
Here's a solution in Python, based on Will Ness answer but taking some shortcuts and using pure integer math to avoid running into log space numerical accuracy errors:
import math
def next_regular(target):
"""
Find the next regular number greater than or equal to target.
"""
# Check if it's already a power of 2 (or a non-integer)
try:
if not (target & (target-1)):
return target
except TypeError:
# Convert floats/decimals for further processing
target = int(math.ceil(target))
if target <= 6:
return target
match = float('inf') # Anything found will be smaller
p5 = 1
while p5 < target:
p35 = p5
while p35 < target:
# Ceiling integer division, avoiding conversion to float
# (quotient = ceil(target / p35))
# From https://stackoverflow.com/a/17511341/125507
quotient = -(-target // p35)
# Quickly find next power of 2 >= quotient
# See https://stackoverflow.com/a/19164783/125507
try:
p2 = 2**((quotient - 1).bit_length())
except AttributeError:
# Fallback for Python <2.7
p2 = 2**(len(bin(quotient - 1)) - 2)
N = p2 * p35
if N == target:
return N
elif N < match:
match = N
p35 *= 3
if p35 == target:
return p35
if p35 < match:
match = p35
p5 *= 5
if p5 == target:
return p5
if p5 < match:
match = p5
return match
In English: iterate through every combination of 5s and 3s, quickly finding the next power of 2 >= target for each pair and keeping the smallest result. (It's a waste of time to iterate through every possible multiple of 2 if only one of them can be correct). It also returns early if it ever finds that the target is already a regular number, though this is not strictly necessary.
I've tested it pretty thoroughly, testing every integer from 0 to 51200000 and comparing to the list on OEIS http://oeis.org/A051037, as well as many large numbers that are ±1 from regular numbers, etc. It's now available in SciPy as fftpack.helper.next_fast_len, to find optimal sizes for FFTs (source code).
I'm not sure if the log method is faster because I couldn't get it to work reliably enough to test it. I think it has a similar number of operations, though? I'm not sure, but this is reasonably fast. Takes <3 seconds (or 0.7 second with gmpy) to calculate that 2142 × 380 × 5444 is the next regular number above 22 × 3454 × 5249+1 (the 100,000,000th regular number, which has 392 digits)
You want to find the smallest number m that is m >= N and m = 2^i * 3^j * 5^k where all i,j,k >= 0.
Taking logarithms the equations can be rewritten as:
log m >= log N
log m = i*log2 + j*log3 + k*log5
You can calculate log2, log3, log5 and logN to (enough high, depending on the size of N) accuracy. Then this problem looks like a Integer Linear programming problem and you could try to solve it using one of the known algorithms for this NP-hard problem.
EDITED/CORRECTED: Corrected the codes to pass the scipy tests:
Here's an answer based on endolith's answer, but almost eliminating long multi-precision integer calculations by using float64 logarithm representations to do a base comparison to find triple values that pass the criteria, only resorting to full precision comparisons when there is a chance that the logarithm value may not be accurate enough, which only occurs when the target is very close to either the previous or the next regular number:
import math
def next_regulary(target):
"""
Find the next regular number greater than or equal to target.
"""
if target < 2: return ( 0, 0, 0 )
log2hi = 0
mant = 0
# Check if it's already a power of 2 (or a non-integer)
try:
mant = target & (target - 1)
target = int(target) # take care of case where not int/float/decimal
except TypeError:
# Convert floats/decimals for further processing
target = int(math.ceil(target))
mant = target & (target - 1)
# Quickly find next power of 2 >= target
# See https://stackoverflow.com/a/19164783/125507
try:
log2hi = target.bit_length()
except AttributeError:
# Fallback for Python <2.7
log2hi = len(bin(target)) - 2
# exit if this is a power of two already...
if not mant: return ( log2hi - 1, 0, 0 )
# take care of trivial cases...
if target < 9:
if target < 4: return ( 0, 1, 0 )
elif target < 6: return ( 0, 0, 1 )
elif target < 7: return ( 1, 1, 0 )
else: return ( 3, 0, 0 )
# find log of target, which may exceed the float64 limit...
if log2hi < 53: mant = target << (53 - log2hi)
else: mant = target >> (log2hi - 53)
log2target = log2hi + math.log2(float(mant) / (1 << 53))
# log2 constants
log2of2 = 1.0; log2of3 = math.log2(3); log2of5 = math.log2(5)
# calculate range of log2 values close to target;
# desired number has a logarithm of log2target <= x <= top...
fctr = 6 * log2of3 * log2of5
top = (log2target**3 + 2 * fctr)**(1/3) # for up to 2 numbers higher
btm = 2 * log2target - top # or up to 2 numbers lower
match = log2hi # Anything found will be smaller
result = ( log2hi, 0, 0 ) # placeholder for eventual matches
count = 0 # only used for debugging counting band
fives = 0; fiveslmt = int(math.ceil(top / log2of5))
while fives < fiveslmt:
log2p = top - fives * log2of5
threes = 0; threeslmt = int(math.ceil(log2p / log2of3))
while threes < threeslmt:
log2q = log2p - threes * log2of3
twos = int(math.floor(log2q)); log2this = top - log2q + twos
if log2this >= btm: count += 1 # only used for counting band
if log2this >= btm and log2this < match:
# logarithm precision may not be enough to differential between
# the next lower regular number and the target, so do
# a full resolution comparison to eliminate this case...
if (2**twos * 3**threes * 5**fives) >= target:
match = log2this; result = ( twos, threes, fives )
threes += 1
fives += 1
return result
print(next_regular(2**2 * 3**454 * 5**249 + 1)) # prints (142, 80, 444)
Since most long multi-precision calculations have been eliminated, gmpy isn't needed, and on IDEOne the above code takes 0.11 seconds instead of 0.48 seconds for endolith's solution to find the next regular number greater than the 100 millionth one as shown; it takes 0.49 seconds instead of 5.48 seconds to find the next regular number past the billionth (next one is (761,572,489) past (1334,335,404) + 1), and the difference will get even larger as the range goes up as the multi-precision calculations get increasingly longer for the endolith version compared to almost none here. Thus, this version could calculate the next regular number from the trillionth in the sequence in about 50 seconds on IDEOne, where it would likely take over an hour with the endolith version.
The English description of the algorithm is almost the same as for the endolith version, differing as follows:
1) calculates the float log estimation of the argument target value (we can't use the built-in log function directly as the range may be much too large for representation as a 64-bit float),
2) compares the log representation values in determining qualifying values inside an estimated range above and below the target value of only about two or three numbers (depending on round-off),
3) compare multi-precision values only if within the above defined narrow band,
4) outputs the triple indices rather than the full long multi-precision integer (would be about 840 decimal digits for the one past the billionth, ten times that for the trillionth), which can then easily be converted to the long multi-precision value if required.
This algorithm uses almost no memory other than for the potentially very large multi-precision integer target value, the intermediate evaluation comparison values of about the same size, and the output expansion of the triples if required. This algorithm is an improvement over the endolith version in that it successfully uses the logarithm values for most comparisons in spite of their lack of precision, and that it narrows the band of compared numbers to just a few.
This algorithm will work for argument ranges somewhat above ten trillion (a few minute's calculation time at IDEOne rates) when it will no longer be correct due to lack of precision in the log representation values as per #WillNess's discussion; in order to fix this, we can change the log representation to a "roll-your-own" logarithm representation consisting of a fixed-length integer (124 bits for about double the exponent range, good for targets of over a hundred thousand digits if one is willing to wait); this will be a little slower due to the smallish multi-precision integer operations being slower than float64 operations, but not that much slower since the size is limited (maybe a factor of three or so slower).
Now none of these Python implementations (without using C or Cython or PyPy or something) are particularly fast, as they are about a hundred times slower than as implemented in a compiled language. For reference sake, here is a Haskell version:
{-# OPTIONS_GHC -O3 #-}
import Data.Word
import Data.Bits
nextRegular :: Integer -> ( Word32, Word32, Word32 )
nextRegular target
| target < 2 = ( 0, 0, 0 )
| target .&. (target - 1) == 0 = ( fromIntegral lg2hi - 1, 0, 0 )
| target < 9 = case target of
3 -> ( 0, 1, 0 )
5 -> ( 0, 0, 1 )
6 -> ( 1, 1, 0 )
_ -> ( 3, 0, 0 )
| otherwise = match
where
lg3 = logBase 2 3 :: Double; lg5 = logBase 2 5 :: Double
lg2hi = let cntplcs v cnt =
let nv = v `shiftR` 31 in
if nv <= 0 then
let cntbts x c =
if x <= 0 then c else
case c + 1 of
nc -> nc `seq` cntbts (x `shiftR` 1) nc in
cntbts (fromIntegral v :: Word32) cnt
else case cnt + 31 of ncnt -> ncnt `seq` cntplcs nv ncnt
in cntplcs target 0
lg2tgt = let mant = if lg2hi <= 53 then target `shiftL` (53 - lg2hi)
else target `shiftR` (lg2hi - 53)
in fromIntegral lg2hi +
logBase 2 (fromIntegral mant / 2^53 :: Double)
lg2top = (lg2tgt^3 + 2 * 6 * lg3 * lg5)**(1/3) -- for 2 numbers or so higher
lg2btm = 2* lg2tgt - lg2top -- or two numbers or so lower
match =
let klmt = floor (lg2top / lg5)
loopk k mtchlgk mtchtplk =
if k > klmt then mtchtplk else
let p = lg2top - fromIntegral k * lg5
jlmt = fromIntegral $ floor (p / lg3)
loopj j mtchlgj mtchtplj =
if j > jlmt then loopk (k + 1) mtchlgj mtchtplj else
let q = p - fromIntegral j * lg3
( i, frac ) = properFraction q; r = lg2top - frac
( nmtchlg, nmtchtpl ) =
if r < lg2btm || r >= mtchlgj then
( mtchlgj, mtchtplj ) else
if 2^i * 3^j * 5^k >= target then
( r, ( i, j, k ) ) else ( mtchlgj, mtchtplj )
in nmtchlg `seq` nmtchtpl `seq` loopj (j + 1) nmtchlg nmtchtpl
in loopj 0 mtchlgk mtchtplk
in loopk 0 (fromIntegral lg2hi) ( fromIntegral lg2hi, 0, 0 )
trival :: ( Word32, Word32, Word32 ) -> Integer
trival (i,j,k) = 2^i * 3^j * 5^k
main = putStrLn $ show $ nextRegular $ (trival (1334,335,404)) + 1 -- (1126,16930,40)
This code calculates the next regular number following the billionth in too small a time to be measured and following the trillionth in 0.69 seconds on IDEOne (and potentially could run even faster except that IDEOne doesn't support LLVM). Even Julia will run at something like this Haskell speed after the "warm-up" for JIT compilation.
EDIT_ADD: The Julia code is as per the following:
function nextregular(target :: BigInt) :: Tuple{ UInt32, UInt32, UInt32 }
# trivial case of first value or anything less...
target < 2 && return ( 0, 0, 0 )
# Check if it's already a power of 2 (or a non-integer)
mant = target & (target - 1)
# Quickly find next power of 2 >= target
log2hi :: UInt32 = 0
test = target
while true
next = test & 0x7FFFFFFF
test >>>= 31; log2hi += 31
test <= 0 && (log2hi -= leading_zeros(UInt32(next)) - 1; break)
end
# exit if this is a power of two already...
mant == 0 && return ( log2hi - 1, 0, 0 )
# take care of trivial cases...
if target < 9
target < 4 && return ( 0, 1, 0 )
target < 6 && return ( 0, 0, 1 )
target < 7 && return ( 1, 1, 0 )
return ( 3, 0, 0 )
end
# find log of target, which may exceed the Float64 limit...
if log2hi < 53 mant = target << (53 - log2hi)
else mant = target >>> (log2hi - 53) end
log2target = log2hi + log(2, Float64(mant) / (1 << 53))
# log2 constants
log2of2 = 1.0; log2of3 = log(2, 3); log2of5 = log(2, 5)
# calculate range of log2 values close to target;
# desired number has a logarithm of log2target <= x <= top...
fctr = 6 * log2of3 * log2of5
top = (log2target^3 + 2 * fctr)^(1/3) # for 2 numbers or so higher
btm = 2 * log2target - top # or 2 numbers or so lower
# scan for values in the given narrow range that satisfy the criteria...
match = log2hi # Anything found will be smaller
result :: Tuple{UInt32,UInt32,UInt32} = ( log2hi, 0, 0 ) # placeholder for eventual matches
fives :: UInt32 = 0; fiveslmt = UInt32(ceil(top / log2of5))
while fives < fiveslmt
log2p = top - fives * log2of5
threes :: UInt32 = 0; threeslmt = UInt32(ceil(log2p / log2of3))
while threes < threeslmt
log2q = log2p - threes * log2of3
twos = UInt32(floor(log2q)); log2this = top - log2q + twos
if log2this >= btm && log2this < match
# logarithm precision may not be enough to differential between
# the next lower regular number and the target, so do
# a full resolution comparison to eliminate this case...
if (big(2)^twos * big(3)^threes * big(5)^fives) >= target
match = log2this; result = ( twos, threes, fives )
end
end
threes += 1
end
fives += 1
end
result
end
Here's another possibility I just thought of:
If N is X bits long, then the smallest regular number R ≥ N will be in the range
[2X-1, 2X]
e.g. if N = 257 (binary 100000001) then we know R is 1xxxxxxxx unless R is exactly equal to the next power of 2 (512)
To generate all the regular numbers in this range, we can generate the odd regular numbers (i.e. multiples of powers of 3 and 5) first, then take each value and multiply by 2 (by bit-shifting) as many times as necessary to bring it into this range.
In Python:
from itertools import ifilter, takewhile
from Queue import PriorityQueue
def nextPowerOf2(n):
p = max(1, n)
while p != (p & -p):
p += p & -p
return p
# Generate multiples of powers of 3, 5
def oddRegulars():
q = PriorityQueue()
q.put(1)
prev = None
while not q.empty():
n = q.get()
if n != prev:
prev = n
yield n
if n % 3 == 0:
q.put(n // 3 * 5)
q.put(n * 3)
# Generate regular numbers with the same number of bits as n
def regularsCloseTo(n):
p = nextPowerOf2(n)
numBits = len(bin(n))
for i in takewhile(lambda x: x <= p, oddRegulars()):
yield i << max(0, numBits - len(bin(i)))
def nextRegular(n):
bigEnough = ifilter(lambda x: x >= n, regularsCloseTo(n))
return min(bigEnough)
You know what? I'll put money on the proposition that actually, the 'dumb' algorithm is fastest. This is based on the observation that the next regular number does not, in general, seem to be much larger than the given input. So simply start counting up, and after each increment, refactor and see if you've found a regular number. But create one processing thread for each available core you have, and for N cores have each thread examine every Nth number. When each thread has found a number or crossed the power-of-2 threshold, compare the results (keep a running best number) and there you are.
I wrote a small c# program to solve this problem. It's not very optimised but it's a start.
This solution is pretty fast for numbers as big as 11 digits.
private long GetRegularNumber(long n)
{
long result = n - 1;
long quotient = result;
while (quotient > 1)
{
result++;
quotient = result;
quotient = RemoveFactor(quotient, 2);
quotient = RemoveFactor(quotient, 3);
quotient = RemoveFactor(quotient, 5);
}
return result;
}
private static long RemoveFactor(long dividend, long divisor)
{
long remainder = 0;
long quotient = dividend;
while (remainder == 0)
{
dividend = quotient;
quotient = Math.DivRem(dividend, divisor, out remainder);
}
return dividend;
}

Calculate Nth root with integer arithmetic

There are a couple of ways to find integer square roots using only integer arithmetic. For example this one. It makes for interesting reading and also a very interesting theory, particularly for my generation where such techniques aren't so useful any more.
The main thing is that it can't use floating point arithmetic, so that rules out newtons method and it's derivations. The only other way I know of to find roots is binomial expansion, but that also requires floating point arithmetic.
What techniques/algorithms are there for computing integral nth roots using only integer arithmetic?
Edit: Thanks for all the answers so far. They all seem to be slightly more intelligent trial and improvement. Is there no better way?
Edit2: Ok, so it would seem there is no smart way to do this without trial/improvement and either newtons method or a binary search. Can anyone provide a comparison of the two in theory? I have run a number of benchmarks between the two and found them quite similar.
You can use Newton's method using only integer arithmetic, the step is the same as for floating point arithmetic, except you have to replace floating point operators with the corresponding integer operators in languages which have different operators for these.
Let's say you want to find the integer-k-th root of a > 0, which should be the largest integer r such that r^k <= a. You start with any positive integer (of course a good starting point helps).
int_type step(int_type k, int_type a, int_type x) {
return ((k-1)*x + a/x^(k-1))/k;
}
int_type root(int_type k, int_type a) {
int_type x = 1, y = step(k,a,x);
do {
x = y;
y = step(k,a,x);
}while(y < x);
return x;
}
Except for the very first step, you have x == r <==> step(k,a,x) >= x.
One obvious way would be to use binary search together with exponentiation by squaring. This will allow you to find nthRoot(x, n) in O(log (x + n)): binary search in [0, x] for the largest integer k such that k^n <= x. For some k, if k^n <= x, reduce the search to [k + 1, x], otherwise reduce it to [0, k].
Do you require something smarter or faster?
One easy solution is to use the binary search.
Assume we are finding nth root of x.
Function GetRange(x,n):
y=1
While y^n < x:
y*2
return (y/2,y)
Function BinSearch(a,b,x,):
if a == b+1:
if x-a^n < b^n - x:
return a
else:
return b
c = (a+b)/2
if n< c^n:
return BinSearch(a,c,x,n)
else:
return BinSearch(c,b,x,n)
a,b = GetRange(x,n)
print BinSearch(a,b,x,n)
===Faster Version===
Function BinSearch(a,b,x,):
w1 = x-a^n
w2 = b^n - x
if a <= b+1:
if w1 < w2:
return a
else:
return b
c = (w2*a+w1*b)/(w1+w2)
if n< c^n:
return BinSearch(a,c,x,n)
else:
return BinSearch(c,b,x,n)
It seems to me that the Shifting nth root algorithm provides exactly what you want:
The shifting nth root algorithm is an algorithm for extracting the nth root of a positive real number which proceeds iteratively by shifting in n digits of the radicand, starting with the most significant, and produces one digit of the root on each iteration, in a manner similar to long division.
There are worked examples on the linked wikipedia page.
I made the algorithm in VBA in Excel. For now it only calculates roots of integers. It is easy to implement the decimals as well.
Just copy and paste the code into an EXCEL module and type the name of the function into some cell, passing the parameters.
Public Function RootShift(ByVal radicand As Double, degree As Long, Optional ByRef remainder As Double = 0) As Double
Dim fullRadicand As String, partialRadicand As String, missingZeroes As Long, digit As Long
Dim minimalPotency As Double, minimalRemainder As Double, potency As Double
radicand = Int(radicand)
degree = Abs(degree)
fullRadicand = CStr(radicand)
missingZeroes = degree - Len(fullRadicand) Mod degree
If missingZeroes < degree Then
fullRadicand = String(missingZeroes, "0") + fullRadicand
End If
remainder = 0
RootShift = 0
Do While fullRadicand <> ""
partialRadicand = Left(fullRadicand, degree)
fullRadicand = Mid(fullRadicand, degree + 1)
minimalPotency = (RootShift * 10) ^ degree
minimalRemainder = remainder * 10 ^ degree + Val(partialRadicand)
For digit = 9 To 0 Step -1
potency = (RootShift * 10 + digit) ^ degree - minimalPotency
If potency <= minimalRemainder Then
Exit For
End If
Next
RootShift = RootShift * 10 + digit
remainder = minimalRemainder - potency
Loop
End Function
Algorithm more simple in VBA.
Public Function RootNth(radicand As Double, degree As Long) As Double
Dim countDigits As Long, digit As Long, potency As Double
Dim minDigit As Long, maxDigit As Long, partialRadicand As String
Dim totalRadicand As String, remainder As Double
radicand = Int(radicand)
degree = Abs(degree)
RootNth = 0
partialRadicand = ""
totalRadicand = CStr(radicand)
countDigits = Len(totalRadicand) Mod degree
countDigits = IIf(countDigits = 0, degree, countDigits)
Do While totalRadicand <> ""
partialRadicand = partialRadicand + Left(totalRadicand, countDigits)
totalRadicand = Mid(totalRadicand, countDigits + 1)
countDigits = degree
minDigit = 0
maxDigit = 9
Do While minDigit <= maxDigit
digit = Int((minDigit + maxDigit) / 2)
potency = (RootNth * 10 + digit) ^ degree
If potency = Val(partialRadicand) Then
maxDigit = digit
Exit Do
End If
If potency < Val(partialRadicand) Then
minDigit = digit + 1
Else
maxDigit = digit - 1
End If
Loop
RootNth = RootNth * 10 + maxDigit
Loop
End Function

Generating Serial Number

So I'm creating a Activation class for a VB6 project and I've run into a brain fart. I've designed how I want to generate the Serial Number for this particular product in a following way.
XXXX-XXXX-XXXX-XXXX
Each group of numbers would be representative of data that I can read if I'm aware of the matching document that allows me to understand the codes with the group of digits. So for instance the first group may represent the month that the product was sold to a customer. But I can't have all the serial numbers in January all start with the same four digits so there's some internal math that needs to be done to calculate this value. What I've landed on is this:
A B C D = digits in the first group of the serial number
(A + B) - (C + D) = #
Now # would relate to a table of Hex values that would then represent the month the product was sold. Something like...
1 - January
2 - February
3 - March
....
B - November
C - December
My question lies here - if I know I need the total to equal B(11) then how exactly can I code backwards to generate (A + B) - (C + D) = B(11)?? It's a pretty simple equation, I know - but something I've just ran into and can't seem to get started in the right direction. I'm not asking for a full work-up of code but just a push. If you have a full solution available and want to share I'm always open to learning a bit more.
I am coding in VB6 but VB.NET, C#, C++ solutions could work as well since I can just port those over relatively easily. The community help is always greatly appreciated!
There's no single solution (you have one equation with four variables). You have to pick some random numbers. Here's one that works (in Python, but you get the point):
from random import randint
X = 11 # the one you're looking for
A_plus_B = randint(X, 30)
A = randint(max(A_plus_B - 15, 0), min(A_plus_B, 15))
B = A_plus_B - A
C_plus_D = A_plus_B - X
C = randint(max(C_plus_D - 15, 0), min(C_plus_D, 15))
D = C_plus_D - C
I assume you allow hexadecimal digits; if you just want 0 to 9, replace 15 by 9 and 30 by 18.
OK - pen and paper is always the solution... so here goes...
Attempting to find what values should be for (A + B) - (C + D) to equal a certain number called X. First I know that I want HEX values so that limits me to 0-F or 0-15. From there I need a better starting place so I'll generate a random number that will represent the total of (A + B), we'll call this Y, but not be lower than value X. Then subtract from that number Y value of X to determine that value that will represent (C + D), which we'll call Z. Use similar logic to break down Y and Z into two numbers each that can represent (A + B) = Y and (C + D) = Z. After it's all said and done I should have a good randomization of creating 4 numbers that when plugged into my equation will return a suitable result.
Just had to get past the brain fart.
This may seem a little hackish, and it may not take you where you're trying to go. However it should produce a wider range of values for your key strings:
Option Explicit
Private Function MonthString(ByVal MonthNum As Integer) As String
'MonthNum: January=1, ... December=12. Altered to base 0
'value for use internally.
Dim lngdigits As Long
MonthNum = MonthNum - 1
lngdigits = (Rnd() * &H10000) - MonthNum
MonthString = Right$("000" & Hex$(lngdigits + (MonthNum - lngdigits Mod 12)), 4)
End Function
Private Function MonthRecov(ByVal MonthString As String) As Integer
'Value returned is base 1, i.e. 1=January.
MonthRecov = CInt(CLng("&H" & MonthString) Mod 12) + 1
End Function
Private Sub Form_Load()
Dim intMonth As Integer
Dim strMonth As String
Dim intMonthRecov As Integer
Dim J As Integer
Randomize
For intMonth = 1 To 12
For J = 1 To 2
strMonth = MonthString(intMonth)
intMonthRecov = MonthRecov(strMonth)
Debug.Print intMonth, strMonth, intMonthRecov, Hex$(intMonthRecov)
Next
Next
End Sub

Calculating phi(k) for 1<k<N

Given a large N, I need to iterate through all phi(k) such that 1 < k < N :
time-complexity must be O(N logN)
memory-complexity must be sub O(N) (since the values of N will be around 1012)
Is it possible? If so, how?
This can be done with Memory complexity O(Sqrt(N)) and CPU complexity O(N * Log(Log(N))) with an optimized windowed Sieve of Eratosthenes, as implemented in the code example below.
As no language was specified and as I do not know Python, I have implemented it in VB.net, however I can convert it to C# if you need that.
Imports System.Math
Public Class TotientSerialCalculator
'Implements an extremely efficient Serial Totient(phi) calculator '
' This implements an optimized windowed Sieve of Eratosthenes. The'
' window size is set at Sqrt(N) both to optimize collecting and '
' applying all of the Primes below Sqrt(N), and to minimize '
' window-turning overhead. '
' '
' CPU complexity is O( N * Log(Log(N)) ), which is virtually linear.'
' '
' MEM Complexity is O( Sqrt(N) ). '
' '
' This is probalby the ideal combination, as any attempt to further '
'reduce memory will almost certainly result in disproportionate increases'
'in CPU complexity, and vice-versa. '
Structure NumberFactors
Dim UnFactored As Long 'the part of the number that still needs to be factored'
Dim Phi As Long 'the totient value progressively calculated'
' (equals total numbers less than N that are CoPrime to N)'
'MEM = 8 bytes each'
End Structure
Private ReportInterval As Long
Private PrevLast As Long 'the last value in the previous window'
Private FirstValue As Long 'the first value in this windows range'
Private WindowSize As Long
Private LastValue As Long 'the last value in this windows range'
Private NextFirst As Long 'the first value in the next window'
'Array that stores all of the NumberFactors in the current window.'
' this is the primary memory consumption for the class and it'
' is 16 * Sqrt(N) Bytes, which is O(Sqrt(N)).'
Public Numbers() As NumberFactors
' For N=10^12 (1 trilion), this will be 16MB, which should be bearable anywhere.'
'(note that the Primes() array is a secondary memory consumer'
' at O(pi(Sqrt(N)), which will be within 10x of O(Sqrt(N)))'
Public Event EmitTotientPair(ByVal k As Long, ByVal Phi As Long)
'===== The Routine To Call: ========================'
Public Sub EmitTotientPairsToN(ByVal N As Long)
'Routine to Emit Totient pairs {k, Phi(k)} for k = 1 to N'
' 2009-07-14, RBarryYoung, Created.'
Dim i As Long
Dim k As Long 'the current number being factored'
Dim p As Long 'the current prime factor'
'Establish the Window frame:'
' note: WindowSize is the critical value that controls both memory'
' usage and CPU consumption and must be SQRT(N) for it to work optimally.'
WindowSize = Ceiling(Sqrt(CDbl(N)))
ReDim Numbers(0 To WindowSize - 1)
'Initialize the first window:'
MapWindow(1)
Dim IsFirstWindow As Boolean = True
'adjust this to control how often results are show'
ReportInterval = N / 100
'Allocate the primes array to hold the primes list:'
' Only primes <= SQRT(N) are needed for factoring'
' PiMax(X) is a Max estimate of the number of primes <= X'
Dim Primes() As Long, PrimeIndex As Long, NextPrime As Long
'init the primes list and its pointers'
ReDim Primes(0 To PiMax(WindowSize) - 1)
Primes(0) = 2 '"prime" the primes list with the first prime'
NextPrime = 1
'Map (and Remap) the window with Sqrt(N) numbers, Sqrt(N) times to'
' sequentially map all of the numbers <= N.'
Do
'Sieve the primes across the current window'
PrimeIndex = 0
'note: cant use enumerator for the loop below because NextPrime'
' changes during the first window as new primes <= SQRT(N) are accumulated'
Do While PrimeIndex < NextPrime
'get the next prime in the list'
p = Primes(PrimeIndex)
'find the first multiple of (p) in the current window range'
k = PrevLast + p - (PrevLast Mod p)
Do
With Numbers(k - FirstValue)
.UnFactored = .UnFactored \ p 'always works the first time'
.Phi = .Phi * (p - 1) 'Phi = PRODUCT( (Pi-1)*Pi^(Ei-1) )'
'The loop test that follows is probably the central CPU overhead'
' I believe that it is O(N*Log(Log(N)), which is virtually O(N)'
' ( for instance at N = 10^12, Log(Log(N)) = 3.3 )'
Do While (.UnFactored Mod p) = 0
.UnFactored = .UnFactored \ p
.Phi = .Phi * p
Loop
End With
'skip ahead to the next multiple of p: '
'(this is what makes it so fast, never have to try prime factors that dont apply)'
k += p
'repeat until we step out of the current window:'
Loop While k < NextFirst
'if this is the first window, then scan ahead for primes'
If IsFirstWindow Then
For i = Primes(NextPrime - 1) + 1 To p ^ 2 - 1 'the range of possible new primes'
'Dont go beyond the first window'
If i >= WindowSize Then Exit For
If Numbers(i - FirstValue).UnFactored = i Then
'this is a prime less than SQRT(N), so add it to the list.'
Primes(NextPrime) = i
NextPrime += 1
End If
Next
End If
PrimeIndex += 1 'move to the next prime'
Loop
'Now Finish & Emit each one'
For k = FirstValue To LastValue
With Numbers(k - FirstValue)
'Primes larger than Sqrt(N) will not be finished: '
If .UnFactored > 1 Then
'Not done factoring, must be an large prime factor remaining: '
.Phi = .Phi * (.UnFactored - 1)
.UnFactored = 1
End If
'Emit the value pair: (k, Phi(k)) '
EmitPhi(k, .Phi)
End With
Next
're-Map to the next window '
IsFirstWindow = False
MapWindow(NextFirst)
Loop While FirstValue <= N
End Sub
Sub EmitPhi(ByVal k As Long, ByVal Phi As Long)
'just a placeholder for now, that raises an event to the display form'
' periodically for reporting purposes. Change this to do the actual'
' emitting.'
If (k Mod ReportInterval) = 0 Then
RaiseEvent EmitTotientPair(k, Phi)
End If
End Sub
Public Sub MapWindow(ByVal FirstVal As Long)
'Efficiently reset the window so that we do not have to re-allocate it.'
'init all of the boundary values'
FirstValue = FirstVal
PrevLast = FirstValue - 1
NextFirst = FirstValue + WindowSize
LastValue = NextFirst - 1
'Initialize the Numbers prime factor arrays'
Dim i As Long
For i = 0 To WindowSize - 1
With Numbers(i)
.UnFactored = i + FirstValue 'initially equal to the number itself'
.Phi = 1 'starts at mulplicative identity(1)'
End With
Next
End Sub
Function PiMax(ByVal x As Long) As Long
'estimate of pi(n) == {primes <= (n)} that is never less'
' than the actual number of primes. (from P. Dusart, 1999)'
Return (x / Log(x)) * (1.0 + 1.2762 / Log(x))
End Function
End Class
Note that at O(N * Log(Log(N))), this routine is factoring each number at O(Log(Log(N))) on average which is much, much faster than the fastest single N factorization algorithms sited by some of the replies here. In fact, at N = 10^12 it is 2400 times faster!
I have tested this routine on my 2Ghz Intel Core 2 laptop and it computes over 3,000,000 Phi() values per second. At this speed, it would take you about 4 days to compute 10^12 values. I have also tested it for correctness up to 100,000,000 without any errors. It is based in 64-bit integers, so anything up to 2^63 (10^19) should be accurate (though too slow for anyone).
I also have a Visual Studio WinForm (also VB.net) for running/testing it, that I can provide if you want it.
Let me know if you have any questions.
As requested in the comments, I have added below a C# version of the code. However, because I am currently in the middle of some other projects, I do not have time to convert it myself, so I have used one of the online VB to C# conversion sites (http://www.carlosag.net/tools/codetranslator/). So be aware that this was auto-converted and I have not had time to test or check it myself yet.
using System.Math;
public class TotientSerialCalculator {
// Implements an extremely efficient Serial Totient(phi) calculator '
// This implements an optimized windowed Sieve of Eratosthenes. The'
// window size is set at Sqrt(N) both to optimize collecting and '
// applying all of the Primes below Sqrt(N), and to minimize '
// window-turning overhead. '
// '
// CPU complexity is O( N * Log(Log(N)) ), which is virtually linear.'
// '
// MEM Complexity is O( Sqrt(N) ). '
// '
// This is probalby the ideal combination, as any attempt to further '
// reduce memory will almost certainly result in disproportionate increases'
// in CPU complexity, and vice-versa. '
struct NumberFactors {
private long UnFactored; // the part of the number that still needs to be factored'
private long Phi;
}
private long ReportInterval;
private long PrevLast; // the last value in the previous window'
private long FirstValue; // the first value in this windows range'
private long WindowSize;
private long LastValue; // the last value in this windows range'
private long NextFirst; // the first value in the next window'
// Array that stores all of the NumberFactors in the current window.'
// this is the primary memory consumption for the class and it'
// is 16 * Sqrt(N) Bytes, which is O(Sqrt(N)).'
public NumberFactors[] Numbers;
// For N=10^12 (1 trilion), this will be 16MB, which should be bearable anywhere.'
// (note that the Primes() array is a secondary memory consumer'
// at O(pi(Sqrt(N)), which will be within 10x of O(Sqrt(N)))'
//NOTE: this part looks like it did not convert correctly
public event EventHandler EmitTotientPair;
private long k;
private long Phi;
// ===== The Routine To Call: ========================'
public void EmitTotientPairsToN(long N) {
// Routine to Emit Totient pairs {k, Phi(k)} for k = 1 to N'
// 2009-07-14, RBarryYoung, Created.'
long i;
long k;
// the current number being factored'
long p;
// the current prime factor'
// Establish the Window frame:'
// note: WindowSize is the critical value that controls both memory'
// usage and CPU consumption and must be SQRT(N) for it to work optimally.'
WindowSize = Ceiling(Sqrt(double.Parse(N)));
object Numbers;
this.MapWindow(1);
bool IsFirstWindow = true;
ReportInterval = (N / 100);
// Allocate the primes array to hold the primes list:'
// Only primes <= SQRT(N) are needed for factoring'
// PiMax(X) is a Max estimate of the number of primes <= X'
long[] Primes;
long PrimeIndex;
long NextPrime;
// init the primes list and its pointers'
object Primes;
-1;
Primes[0] = 2;
// "prime" the primes list with the first prime'
NextPrime = 1;
// Map (and Remap) the window with Sqrt(N) numbers, Sqrt(N) times to'
// sequentially map all of the numbers <= N.'
for (
; (FirstValue <= N);
) {
PrimeIndex = 0;
// note: cant use enumerator for the loop below because NextPrime'
// changes during the first window as new primes <= SQRT(N) are accumulated'
while ((PrimeIndex < NextPrime)) {
// get the next prime in the list'
p = Primes[PrimeIndex];
// find the first multiple of (p) in the current window range'
k = (PrevLast
+ (p
- (PrevLast % p)));
for (
; (k < NextFirst);
) {
// With...
UnFactored;
p;
// always works the first time'
(Phi
* (p - 1));
while (// TODO: Warning!!!! NULL EXPRESSION DETECTED...
) {
(UnFactored % p);
UnFactored;
(Phi * p);
}
// skip ahead to the next multiple of p: '
// (this is what makes it so fast, never have to try prime factors that dont apply)'
k = (k + p);
// repeat until we step out of the current window:'
}
// if this is the first window, then scan ahead for primes'
if (IsFirstWindow) {
for (i = (Primes[(NextPrime - 1)] + 1); (i
<= (p | (2 - 1))); i++) {
// the range of possible new primes'
// TODO: Warning!!! The operator should be an XOR ^ instead of an OR, but not available in CodeDOM
// Dont go beyond the first window'
if ((i >= WindowSize)) {
break;
}
if ((Numbers[(i - FirstValue)].UnFactored == i)) {
// this is a prime less than SQRT(N), so add it to the list.'
Primes[NextPrime] = i;
NextPrime++;
}
}
}
PrimeIndex++;
// move to the next prime'
}
// Now Finish & Emit each one'
for (k = FirstValue; (k <= LastValue); k++) {
// With...
// Primes larger than Sqrt(N) will not be finished: '
if ((Numbers[(k - FirstValue)].UnFactored > 1)) {
// Not done factoring, must be an large prime factor remaining: '
(Numbers[(k - FirstValue)].Phi * (Numbers[(k - FirstValue)].UnFactored - 1).UnFactored) = 1;
Numbers[(k - FirstValue)].Phi = 1;
}
// Emit the value pair: (k, Phi(k)) '
this.EmitPhi(k, Numbers[(k - FirstValue)].Phi);
}
// re-Map to the next window '
IsFirstWindow = false;
this.MapWindow(NextFirst);
}
}
void EmitPhi(long k, long Phi) {
// just a placeholder for now, that raises an event to the display form'
// periodically for reporting purposes. Change this to do the actual'
// emitting.'
if (((k % ReportInterval)
== 0)) {
EmitTotientPair(k, Phi);
}
}
public void MapWindow(long FirstVal) {
// Efficiently reset the window so that we do not have to re-allocate it.'
// init all of the boundary values'
FirstValue = FirstVal;
PrevLast = (FirstValue - 1);
NextFirst = (FirstValue + WindowSize);
LastValue = (NextFirst - 1);
// Initialize the Numbers prime factor arrays'
long i;
for (i = 0; (i
<= (WindowSize - 1)); i++) {
// With...
// initially equal to the number itself'
Phi = 1;
// starts at mulplicative identity(1)'
}
}
long PiMax(long x) {
// estimate of pi(n) == {primes <= (n)} that is never less'
// than the actual number of primes. (from P. Dusart, 1999)'
return ((x / Log(x)) * (1 + (1.2762 / Log(x))));
}
}
No one has found a faster way to calculate phi(k) (aka, Euler's totient function) than by first finding the prime factors of k. The world's best mathematicians have thrown many CPU cycles at the problem since 1977, since finding a faster way to solve this problem would create a weakness in the RSA public-key algorithm. (Both the public and the private key in RSA are calculated based on phi(n), where n is the product of two large primes.)
The computation of phi(k) has to be done using the prime factorization of k, which is the only sensible way of doing it. If you need a refresher on that, wikipedia carries the formula.
If you now have to compute all prime divisors of every number between 1 and a large N, you'll die of old age before seeing any result, so I'd go the other way around, i.e. build all numbers below N, using their possible prime factors, i.e. all primes less than or equal to N.
Your problem is therefore going to be similar to computing all divisors of a number, only you do not know what is the maximum number of times you may find a certain prime in the factorization beforehand. Tweaking an iterator originally written by Tim Peters on the python list (something I've blogged about...) to include the totient function, a possible implementation in python that yields k, phi(k) pairs could be as follows:
def composites(factors, N) :
"""
Generates all number-totient pairs below N, unordered, from the prime factors.
"""
ps = sorted(set(factors))
omega = len(ps)
def rec_gen(n = 0) :
if n == omega :
yield (1,1)
else :
pows = [(1,1)]
val = ps[n]
while val <= N :
pows += [(val, val - pows[-1][0])]
val *= ps[n]
for q, phi_q in rec_gen(n + 1) :
for p, phi_p in pows :
if p * q > N :
break
else :
yield p * q, phi_p * phi_q
for p in rec_gen() :
yield p
If you need help on computing all prime factors below N, I've also blogged about it... Keep in mind, though that computing all primes below 1012 is in itself quite a remarkable feat...
Is this from Project Euler 245? I remember that question, and I have given up on it.
The fastest way I found for calculating totient was to multiply the prime factors (p-1) together, given that k has no repeated factors (which was never the case if I remember the problem correctly).
So for calculating factors, it would probably be best to use gmpy.next_prime or pyecm (elliptic curve factorization).
You could also sieve the prime factors as Jaime suggests. For numbers up to 1012, the maximum prime factor is below 1 million which should be reasonable.
If you memoize factorizations, it could speed up your phi function even more.
For these kind of problems I'm using an iterator that returns for each integer m < N the list of primes < sqrt(N) that divide m. To implement such an iterator I'm using an array A of length R where R > sqrt(N). At each point the array A contains list of primes that divide integers m .. m+R-1. I.e. A[m % R] contains primes dividing m. Each prime p is in exactly one list, i.e. in A[m % R] for the smallest integer in the range m .. m+R-1 that is divisible by p. When generating the next element of the iterator simply the list in A[m % R] is returned. Then the list of primes are removed from A[m % R] and each prime p is appended to A[(m+p) % R].
With a list of primes < sqrt(N) dividing m it is easy to find the factorization of m, since there is at most one prime larger than sqrt(N).
This method has complexity O(N log(log(N))) under the assumption that all operations including list operations take O(1). The memory requirement is O(sqrt(N)).
There is unfortunately, some constant overhead here, hence I was looking for a more elegant way to generate the values phi(n), but so for I've not been successful.
Here's an efficient python generator. The caveat is that it doesn't yield the results in order. It is based on https://stackoverflow.com/a/10110008/412529 .
Memory complexity is O(log(N)) as it only has to store a list of prime factors for a single number at a time.
CPU complexity is just barely superlinear, something like O(N log log N).
def totientsbelow(N):
allprimes = primesbelow(N+1)
def rec(n, partialtot=1, min_p = 0):
for p in allprimes:
if p > n:
break
# avoid double solutions such as (6, [2,3]), and (6, [3,2])
if p < min_p: continue
yield (p, p-1, [p])
for t, tot2, r in rec(n//p, partialtot, min_p = p): # uses integer division
yield (t*p, tot2 * p if p == r[0] else tot2 * (p-1), [p] + r)
for n, t, factors in rec(N):
yield (n, t)
I think you can go the other way around. Instead of factorizing an integer k to get phi(k), you can attempt to generate all integers from 1 to N from primes and get phi(k) quickly. For example, if Pn is the maximum prime that is less than N, you can generate all integers less than N by
P1 i 1 * P2 i 2 * ... * Pn i n where each ij run from 0 to [log (N) / log (Pj)] ([] is the floor function).
That way, you can get phi(k) quickly wihout expensive prime factorization and still iterate through all k between 1 and N (not in order but I think you don't care about order).
Sieve the totients to n:
(define (totients n)
(let ((tots (make-vector (+ n 1))))
(do ((i 0 (+ i 1))) ((< n i))
(vector-set! tots i i))
(do ((i 2 (+ i 1))) ((< n i) tots)
(when (= i (vector-ref tots i))
(vector-set! tots i (- i 1))
(do ((j (+ i i) (+ i j))) ((< n j))
(vector-set! tots j
(* (vector-ref tots j) (- 1 (/ i)))))))))
This factorizes N = PQ, where P & Q are prime.
Works quite well, in Elixir or Erlang.
You can try different generators for your pseudo-random sequence. x*x + 1 is commonly used.
This line: defp f0(x, n), do: rem((x * x) + 1, n)
Other possible points of improvement: better or alternative gcd, rem and abs functions
defmodule Factorizer do
def factorize(n) do
t = System.system_time
x = pollard(n, 2_000_000, 2_000_000)
y = div(n, x)
p = min(x, y)
q = max(x, y)
t = System.system_time - t
IO.puts "
Factorized #{n}: into [#{p} , #{q}] in #{t} μs
"
{p, q}
end
defp gcd(a,0), do: a
defp gcd(a,b), do: gcd(b,rem(a,b))
defp pollard(n, a, b) do
a = f0(a, n)
b = f0(f0(b, n), n)
p = gcd(abs(b - a), n)
case p > 1 do
true -> p
false -> pollard(n, a, b)
end
end
defp f0(x, n), do: rem((x * x) + 1, n)
end

Resources