Is there an algorithm for figuring out the following things?
If the result of a division is a repeating decimal (in binary).
If it repeats, at what digit (represented as a power of 2) does the repetition start?
What digits repeat?
Some examples:
1/2 = 1/10 = 0.1 // 1 = false, 2 = N/A, 3 = N/A, 4 = N/A
1/3 = 1/11 = 0.010101... // 1 = true, 2 = -2, 3 = 10
2/3 = 10/11 = 0.101010... // 1 = true, 2 = -1, 3 = 10
4/3 = 100/11 = 1.010101... // 1 = true, 2 = 0, 3 = 10
1/5 = 1/101 = 0.001100110011... // 1 = true, 2 = -3, 3 = 1100
Is there a way to do this? Efficiency is a big concern. A description of the algorithm would be preferred over code, but I'll take what answer I can get.
It's also worth noting that the base isn't a big deal; I can convert the algorithm over to binary (or if it's in, say base 256 to use chars for ease, I could just use that). I say this because if you're explaining it might be easier for you to explain in base 10 :).
if the divisor is not a power of 2 (in general, contains prime factors not shared with the base of representation)
repeat cycle length will be driven by the largest prime factor of the dividend (but not connected with the length of the representation of that factor -- see 1/7 in decimal), but the first cycle length may differ from the repeat unit (e.g. 11/28 = 1/4+1/7 in decimal).
the actual cycle will depend on the numerator.
I can give a hint - repeating decimals in base ten are all fraction with the denominator having at least one prime factors other than two and five. If the denominator contains no prime factors two or five, they can always be represented with a denominator of all nines. Then the nominator is the repeating part and the number of nines is the length of the repeating part.
3 _
- = 0.3
9
1 142857 ______
- = ------ = 0.142857
7 999999
If there are prime factors two or five in the denominator, the repeating part starts not at the first position.
17 17 ______
-- = ----- = 0.4857142
35 5 * 7
But I cannot remember how to derive the non-repeating part and its length.
This seem to translate well to base two. Only fraction with a power of two denominator are non-repeating. This can be easily checked by asserting that only a single bit in the denominator is set.
1/2 = 1/10 = 0.1
1/4 = 1/100 = 0.01
3/4 = 11/100 = 0.11
5/8 = 101/1000 = 0.101
All fraction with odd denominators should be repeating and the pattern and its length can be obtained by expressing the fraction with a denominator in the form 2^n-1.
__
1/3 = 1/(2^2-1) = 1/11 = 0.01
__
2/3 = 2/(2^2-1) = 10/11 = 0.10
__
4/3 => 1 + 1/3 => 1.01
__
10/3 => 3 + 1/3 => 11.01
____
1/5 = 3/15 = 3/(2^4-1) = 11/1111 = 0.0011
________
11/17 = 165/255 = 11/(2^8-1) = 10100101/11111111 = 0.10100101
As for base ten, I cannot tell how to handle denominators containing but not being a power of two - for example 12 = 3 * 2^2.
First of all, one of your examples is wrong. The repeating part of 1/5 is 0011 rather than 1100, and it begins at the very beginning of the fractional part.
A repeating decimal is something like:
a/b = c + d(2-n + 2-n-k + 2-n-2k + ...)
= c + 2-n * d / (1 - 2-k)
in which n and d are what you want.
For example,
1/10(dec) = 1/1010(bin) = 0.0001100110011... // 1 = true, 2 = -1, 3 = 0011
could be represented by the formula with
a = 1, b = 10(dec), c = 0, d = 0.0011(bin), n = 1, k = 4;
(1 - 2-k) = 0.1111
Therefore, 1/10 = 0.1 * 0.0011/0.1111. The key part of a repeating decimal representation is generated by dividing by (2n - 1) or its any multiple of 2. So you can either find a way to express your denominator as such (like building constant tables), or do a big number division (which is relatively slow) and find the loop. There's no quick way to do this.
Check out decimal expansion, and specifically about the period of a fraction.
You can do a long division, noting the remainders. The structure of the remainders will give you the structure of any rational decimal:
the last remainder is zero: it is a decimal without any repeating part
the first and the last remainder are equal: the decimal is repeating right after the dot
the distance between the first and the first remainder equal to the last are the non-repeating digits, the remainder is the repeating part
In general the distances will give you the amount of digits for each part.
You can see this algorithm coded in C++ in the method decompose() here.
Try 228142/62265, it has a period of 1776 digits!
To find the repeating pattern, just keep track of the values you use along the line:
1/5 = 1/101:
1 < 101 => 0
(decimal separator here)
10 < 101 => 0
100 < 101 => 0
1000 >= 101 => 1
1000 - 101 = 11
110 >= 101 => 1
110 - 101 = 1
10 -> match
As you reach the same value as you had at the second bit, the process will just repeat from that point producing the same bit pattern over and over. You have the pattern "0011" repeating from the second bit (first after decimal separator).
If you want the pattern to start with a "1", you can just rotate it until it matches that condition:
"0011" from the second bit
"0110" from the third bit
"1100" from the fourth bit
Edit:
Example in C#:
void FindPattern(int n1, int n2) {
int digit = -1;
while (n1 >= n2) {
n2 <<= 1;
digit++;
}
Dictionary<int, int> states = new Dictionary<int, int>();
bool found = false;
while (n1 > 0 || digit >= 0) {
if (digit == -1) Console.Write('.');
n1 <<= 1;
if (states.ContainsKey(n1)) {
Console.WriteLine(digit >= 0 ? new String('0', digit + 1) : String.Empty);
Console.WriteLine("Repeat from digit {0} length {1}.", states[n1], states[n1] - digit);
found = true;
break;
}
states.Add(n1, digit);
if (n1 < n2) {
Console.Write('0');
} else {
Console.Write('1');
n1 -= n2;
}
digit--;
}
if (!found) {
Console.WriteLine();
Console.WriteLine("No repeat.");
}
}
Called with your examples it outputs:
.1
No repeat.
.01
Repeat from digit -1 length 2.
.10
Repeat from digit -1 length 2.
1.0
Repeat from digit 0 length 2.
.0011
Repeat from digit -1 length 4.
As others have noted, the answer involves a long division.
Here is a simple python function which does the job:
def longdiv(numerator,denominator):
digits = []
remainders = [0]
n = numerator
while n not in remainders: # until repeated remainder or no remainder
remainders.append(n) # add remainder to collection
digits.append(n//denominator) # add integer division to result
n = n%denominator * 10 # remainder*10 for next iteration
# Result
result = list(map(str,digits)) # convert digits to strings
result = ''.join(result) # combine list to string
if not n:
result = result[:1]+'.'+result[1:] # Insert . into string
else:
recurring = remainders.index(n)-1 # first recurring digit
# Insert '.' and then surround recurring part in brackets:
result = result[:1]+'.'+result[1:recurring]+'['+result[recurring:]+']'
return result;
print(longdiv(31,8)) # 3.875
print(longdiv(2,13)) # 0.[153846]
print(longdiv(13,14)) # 0.9[285714]
It’s heavily commented, so it shouldn’t be too hard to write in other languages, such as JavaScript.
The most important parts, as regards recurring decimals are:
keep a collection of remainders; the first remainder of 0 is added as a convenience for the next step
divide, noting the integer quotient and the remainder
if the new remainder is 0 you have a terminating decimal
if the new remainder is already in the collection, you have a recurring decimal
repeat, adlib and fade etc
The rest of the function is there to format the results.
Related
I just come across this interesting question from a book and I am unable to find the answer.
I have a given number X and a target number Y, task is to find such permutation of all the digits of X such that it is closest to Y.
Numbers are in form of array. No array size limit is given there.
Example
Given number X = 1212
Target number Y = 1500
Answer = 1221
Here, abs(1500-1221) is smallest among all permutations of X.
Given number X = 1212
Target number Y = 1900
Answer = 2112
Here, abs(1900-2112) is smallest among all permutations of X.
Given number X = 1029
Target number Y = 2000
Answer = 2019
Here, abs(2000-2019) is smallest among all permutations of X.
One of the solution I can find is to generate all permutations of the given number and at each stage calculates the difference. But this is very slow.
I tried to find the greedy approach, where I will iterate through all the indices of the target number Y and at each index I will put that digit of the given number X such that abs(Y[i] - X[i]) is minimum. But this fails for many cases.
I am trying to think of a DP approach, but unable to come up with any.
Any lead to the answer will be helpful.
Edit -
Adding pseudo code for my greedy approach
for each index i in [0,Y]:
min_index = 0;
for each index j in [1, X.length]:
if abs(X[j] - Y[i]) < abs(X[min_index] - Y[i]):
min_val = j
print X[min_index]
remove min_index from X
Example X = 1212 and Y = 1900.
step 1 - output 1 and remove index 0 from X.
step 2 - output 2 and remove index 1 from X.
step 3 - output 1 and remove index 2 from X.
step 2 - output 1 and remove index 3 from X.
answer = 1212 which is wrong (correct answer is 2112).
So fails for this test case and lots more.
So, the problem can be seen as follow:
Starting from the largest significant digits, for each of these index, there are three cases:
The current digit will be less than the desired digit, so for the rest of the digits, we try to create the largest number possible => for the rest of the digits, we sorted them in descending order , i.e if we have 0, 2, 7, 5 left -> we will create 7520
The current digit will be larger than the desired digit, so for the rest of the digits, we try to create the smallest number possible => for the rest of the digits, we sorted them in ascending order , i.e if we have 0, 2, 7, 5 left -> we will create 0275
If the current digit is equal to the desired digit, we will append it to the prefix and try to find better match in next iteration.
Pseudo-code:
int prefix, result;
for each index i from 0 to Y.length() {
int larger = prefix + smallestDigitLargerThan(Y(i)) + OtherDigitInAscendingOrder;
int smaller = prefix + largestDigitSmallerThan(Y(i)) + OtherDigitInDescendingOrder;
update result based on larger and smaller;
if there is no digit equals to Y(i)
break;
else {
remove Y(i) in X
prefix = prefix*10 + Y(i)
}
}
}
if prefix == Y {
//We have a full match
return prefix;
}
return result;
For example
X = 1029
Y = 2000
At index 0 -> Y(0) = 2,
int smaller = 0 (prefix) + 1(largest digit that is less than 2) + 920 (other digit in descending order) = 1920
int larger = 0 (prefix) + 9(smallest digit that is greater than 2) + 012 (other digit in ascending order) = 9012
int result = 1920
int prefix = 2
At index 1 -> Y(1) = 0,
int smaller = //Not exist
int larger = 2 + 1 + 09 = 2109
int result = 1920
int prefix = 20
At index 2 -> Y(2) = 0,
int smaller = //Not exist
int larger = 20 + 1 + 9 = 2019
int result = 2019
//Break as there is no digit match Y(2) = 0 from X
Other example:
X = 1212
Y = 1500
At index 0 -> Y(0) = 1,
int smaller = //Not exist
int larger = 0 + 2 + 112 = 2112
int result = 2112
int prefix = 1
At index 1 -> Y(1) = 5,
int smaller = 1 + 2 + 21 = 1221
int larger = //Not exist
int result = 1221
//Break from here as there is no digit match Y(1) = 5 in X
Beam search with width of 3 could be an approach. The idea is to construct the numbers from the largest to the smallest digit, and filling the rest with zeros. You construct the nearest and the second nearest numbers at each step for each number in the beam, and discarding all numbers which are worse than the top three. (In fact you're needing a beam size of two at most. The case of three is only needed, if the distance of two entries in the beams are equal.) During computation the constructed numbers Aand B should never be equal (except for the special case that X only contains the same digit.)
Here are the beams for the second example. The * denotes the best beam, and no * means that both are equally good:
2000* -> 2100* -> 2112*
2200 -> 2211
1000 -> 1200
1100
This is for the first example:
1000 -> 1200* -> 1221*
1100 -> 1122
2000 -> 2100
2200
Third example needs a beam size of 3 for second step, because the distance of second best beams 1900 and 2100 to 2000 is 100:
1000 -> 1900 -> 1901
1100
2000* -> 2000* -> 2019*
2100 2109
Note: I've joined the 3. and the 4. step in all examples.
The numbers X = 1992and Y = 2000 are an interesting example
1000 -> 1900 -> 1992*
1200
2000* -> 2100 -> 2199
2900
because the best beam is changing during computation.
I wrote a small python program for demonstration:
import sys
X = sys.argv[1]
Y = int(sys.argv[2])
def remove(s, i):
return s[:i] + s[i+1:]
def expand(t):
result = set()
val = t[0]
chars = t[1]
index = len(val) - len(chars)
for i in range(len(chars)):
s = val[:index] + chars[i]
r = remove(chars, i)
if index < len(val):
s += val[index + 1:]
result.add((s, r))
return result
beams = [("0" * len(X), X)]
for i in range(len(X)):
newBeams = set()
for t in beams:
newBeams.update(expand(t))
beams = sorted(newBeams, key = lambda t: abs(Y - int(t[0])))[:3]
print beams
print "Result:", beams[0][0]
The code is not optimal but this algorithm has polynomial running time, O(n² ln n) at most, and this estimate is very generous.
How can we find the number of numbers less than a given number with no repeating digits in it?
For example the number of such numbers less than 100 is 90. (11, 22, 33,44, 55,66,77,88,99 have repeating digits so are excluded).
Similarly for less than 1000, digits like 101, 110, 122, 202 etc have to be excluded.
Here is a way to make it quicker. Notice that there is a correlation between the number of digits in the max number and the solution (number of numbers which I will call NON)
100 (3 digits) => NON = 10 * 9
1000 (4 digits) => NON = 10 * 9 * 8
10000 (5 digits) => NON = 10 * 9 * 8 * 7
...
10000000000 (11 digits) => NON = 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1
after one billion you're bound to repeat a digit
You can consider two cases:
numbers shorter than the limit
numbers that that differ from the limit at some digit
The count of d-digit numbers is 9*9*8*... = 9*9!/(9-d)! (the first digit may not be zero). The count of all numbers shorter than d is the count of 0-digit numbers + .. count of d-1-digit numbers. These sums may be precomputed (or even hard-coded).
The count of d-digit numbers with f first digits given is (10-f)*...*(10-(d-1)) = (10-f)!/(10-d)!. You can precomupte the factorials as well.
Pseudocode :
To precompute fac:
- fac = int[10];
- fac[0] = 1;
- for i in 1..10:
- fac[i] = fac[i-1] * i;
To precompute count_shorter:
- cs = int[10];
- cs[0] = 0;
- cs[1] = 1; // if zero is allowed
- for i in 1..10:
- cs[i+1] = cs[i] + 9 * fac[9] / fac[10-i]
- count_shorter = cs;
To determine the count of numbers smaller than d:
- sl = strlen(d)
- if sl > 10
- return count_shorter[11]
- else
- sum = 0
account for shorter numbers:
- sum += count_shorter[sl]
account for same-length numbers; len=count of digits shared with the limit:
- sum += 9* fac[9] / fac[10-sl];
- for every len in 1..{sl-1}:
count the unused digits less than d[len]; credits to #MvG for noting:
- first_opts = d[len]-1;
- for every i in 0..{len-1}:
- if d[i] < d[len]
- first_opts -= 1;
- sum += first_opts * fac[9-len] / fac[10-sl]
- return sum
Here is some code that does this. Comments in the code. The basic idea is that you iterate over the digits of the last counted number one at a time, and for every digit position you can count the numbers that have the same digits prior to that position but a smaller digit at that current position. The functions build upon one another, so the cntSmaller function at the very end is the one you'd actually call, and also the one with the most detailed comments. I've checked that this agrees with a brute-force implementation for all arguments up to 30000. I've done extensive comparisons against alternate implementations, so I'm fairly confident that this code is correct.
from math import factorial
def take(n, r):
"""Count ways to choose r elements from a set of n without
duplicates, taking order into account"""
return factorial(n)/factorial(n - r)
def forLength(length, numDigits, numFirst):
"""Count ways to form numbers with length non-repeating digits
that take their digits from a set of numDigits possible digits,
with numFirst of these as possible choices for the first digit."""
return numFirst * take(numDigits - 1, length - 1)
def noRepeated(digits, i):
"""Given a string of digits, recursively compute the digits for a
number which is no larger than the input and has no repeated
digits. Recursion starts at i=0."""
if i == len(digits):
return True
while digits[i] in digits[:i] or not noRepeated(digits, i + 1):
digits[i] -= 1
for j in range(i + 1, len(digits)):
digits[j] = 9
if digits[i] < 0:
digits[i] = 9
return False
return True
def lastCounted(n):
"""Compute the digits of the last number that is smaller than n
and has no repeated digits."""
digits = [int(i) for i in str(n - 1)]
while not noRepeated(digits, 0):
digits = [9]*(len(digits) - 1)
while digits[0] == 0:
digits = digits[1:]
assert len(digits) == len(set(digits))
return digits
def cntSmaller(n):
if n < 2:
return 0
digits = lastCounted(n)
cnt = 1 # the one from lastCounted is guaranteed to get counted
l = len(digits)
for i in range(1, l):
# count all numbers with less digits
# first digit non-zero, rest all other digits
cnt += forLength(i, 10, 9)
firstDigits = set(range(10))
for i, d in enumerate(digits):
# count numbers which are equal to lastCounted up to position
# i but have a smaller digit at position i
firstHere = firstDigits & set(range(d)) # smaller but not duplicate
if i == 0: # this is the first digit
firstHere.discard(0) # must not start with a zero
cnt += forLength(l - i, 10 - i, len(firstHere))
firstDigits.discard(d)
return cnt
Edit: cntSmaller(9876543211) returns 8877690 which is the maximum number of numbers you can form with non-repeating digits. The fact that this is more than 10!=3628800 had me confused for a while, but this is correct: when you consider your sequences padded to length 10, then sequences of leading zeros are allowed in addition to a zero somewhere in the number. This increases the count above that of the pure permutations.
Given a bunch of integers, I want to convert them to base n and for each bit, add the bits up and mod them by n.
Example: Let n = 3, and suppose I want to add the bits mod 3 in 4, 4, 4, 2. These numbers in base 3 is 11, 11, 11, 02. The least significant bit adds up to 1 + 1 + 1 + 2 = 5 = 2 mod 3. The second least significant bit adds up to 1 + 1 + 1 + 0 = 3 = 0 mod 3. The answer is then 02 base 3 = 2. Alternatively, if we didn't convert to base 3 before the addition, and just did it in binary, we have 100, 100, 100, 010. The resulting bits from least significant to most significant is: 0 + 0 + 0 + 0 = 0 mod 3, 0 + 0 + 0 + 1 = 1 mod 3, 1 + 1 + 1 + 0 = 0 mod 3, so the answer is 010 = 2.
The case where n = 2 is pretty easy, you can just XOR everything. Is there a way to generalize this?
Here's a ditty in ruby:
#! /usr/bin/env ruby
def naryxor(n, terms)
puts "Calculating the #{n}-ary XOR of #{terms.join(", ")}..."
raise "Negative terms are forbidden" if terms.any? { |i| i < 0 }
xor = [] # "Digits" of our n-ary xor result
done = false
while not done
done = true # Assume we're done until proven otherwise
xor.insert(0, 0) # Insert a new total digit at the front
terms = terms.select { |i| i > 0 }.collect do |i|
done = false # Not all remaining terms were zero
digit = i % n # Find the least n-ary digit
rest = (i - digit) / n # shift it off
xor[0] += digit # add it to our xor
rest # Replace this integer with its remainder
end
xor[0] %= n # Take the mod once, after summing.
end
xor[1..-1] # Drop untouched leading digit
end
raise "Usage: ./naryxor.rb arity term term..." if ARGV.size <= 1
puts naryxor(ARGV[0].to_i, ARGV[1..-1].collect(&:to_i)).join("")
Running it:
$ ./naryxor.rb 3 4 4 4 2
Calculating the 3-ary XOR of 4, 4, 4, 2...
02
This is just expands the n-ary representations of the passed integers and does the dumb thing. If n were taken to be a power of two, we could do some more interesting bit-twiddles to avoid the integer divisions, but you gave no such guarantee.
I don't think there's a mathematical property that leads to an efficient general short-cut. The reason XOR works for base 2 is because XOR has the convenient property of being an addition with carry discard.
A simple recursive function can apply the algorithm, e.g. taking advantage of Scala's BigInt class for base conversion:
def sums(radix: Int, digits: List[List[String]]): String =
if(digits exists { _.nonEmpty }) // there's at least 1 bit left to add
(digits.flatMap { _.headOption } // take the 1st bit of all numbers
.map { BigInt(_, radix) } // convert to int representation
.sum
.toInt % radix // modulo by base
).toString +
sums(radix, digits map { _.drop(1) }) // do next most significant bit
else
"" // base case: no digits left to add
def sum(radix: Int, ns: List[Int]): Int =
BigInt(
sums(
radix,
ns // use BigInt to convert from int representation to string
.map { BigInt(_) }
.map { _.toString(radix).split("").drop(1).toList.reverse }
)
.reverse,
radix
).toInt
scala> sum(3, List(4,4,4,2))
res0: Int = 2
Your question is tagged 'performance' but doesn't lay out any additional constraints about memory or runtime to inform an improved approach.
I'm making a function that converts a number into a string with predefined characters. Original, I know. I started it, because it seemed fun at the time. To do on my own. Well, it's frustrating and not fun.
I want it to be like binary as in that any left character is worth more than its right neigbour. Binary is inefficient because every bit has only 1 positive value. Xnary is efficient, because a 'bit' is never 0.
The character set (in this case): A - Z.
A = 1 ..
Z = 26
AA = 27 ..
AZ = 52
BA = 53 ..
BZ = 2 * 26 (B) + 26 * 1 (Z) = 78... Right?
ZZ = 26 * 26 (Z) + 26 * 1 (Z) = 702?? Right??
I found this here, but there AA is the same as A and AAA. The result of the function is never AA or AAA.
The string A is different from AA and AAA however, so the number should be too. (Unlike binary 1, 01, 001 etc.) And since a longer string is always more valuable than a shorter... A < AA < AAA.
Does this make sense? I've tried to explain it before and have failed. I've also tried to make it before. =)
The most important thing: since A < AA < AAA, the value of 'my' ABC is higher than the value of the other script. Another difference: my script doesn't exist, because I keep failing.
I've tried with this algorithm:
N = 1000, Size = 3, (because 26 log(1000) = 2.x), so use 676, 26 and 1 for positions:
N = 1000
P0 = 1000 / 676 = 1.x = 1 = A
N = 1000 - 1 * 676 = 324
P1 = 324 / 26 = 12.x = 12 = L
N = 324 - 12 * 26 = 12
P1 = 12 / 1 = 12 = L
1000 => ALL
Sounds fair? Apparently it's crap. Because:
N = 158760, Size = 4, so use 17576, 676, 26 and 1
P0 = 158760 / 17576 = 9.x = 9 = I
N = 158760 - 9 * 17576 = 576
P1 = 576 / 676 = 0.x = 0 <<< OOPS
If 1 is A (the very first of the xnary), what's 0? Impossible is what it is.
So this one is a bust. The other one (on jsFiddle) is also a bust, because A != AA != AAA and that's a fact.
So what have I been missing for a few long nights?
Oh BTW: if you don't like numbers, don't read this.
PS. I've tried searching for similar questions but none are similar enough. The one references is most similar, but 'faulty' IMO.
Also known as Excel column numbering. It's easier if we shift by one, A = 0, ..., Z = 25, AA = 26, ..., at least for the calculations. For your scheme, all that's needed then is a subtraction of 1 before converting to Xnary resp. an addition after converting from.
So, with that modification, let's start finding the conversion. First, how many symbols do we need to encode n? Well, there are 26 one-digit numbers, 26^2 two-digit numbers, 26^3 three-digit numbers etc. So the total of numbers using at most d digits is 26^1 + 26^2 + ... + 26^d. That is the start of a geometric series, we know a closed form for the sum, 26*(26^d - 1)/(26-1). So to encode n, we need d digits if
26*(26^(d-1)-1)/25 <= n < 26*(26^d-1)/25 // remember, A = 0 takes one 'digit'
or
26^(d-1) <= (25*n)/26 + 1 < 26^d
That is, we need d(n) = floor(log_26(25*n/26+1)) + 1 digits to encode n >= 0. Now we must subtract the total of numbers needing at most d(n) - 1 digits to find the position of n in the d(n)-digit numbers, let's call it p(n) = n - 26*(26^(d(n)-1)-1)/25. And the encoding of n is then simply a d(n)-digit base-26 encoding of p(n).
The conversion in the other direction is then a base-26 expansion followed by an addition of 26*(26^(d-1) - 1)/25.
So for N = 1000, we encode n = 999, log_26(25*999/26+1) = log_26(961.5769...) = 2.x, we need 3 digits.
p(999) = 999 - 702 = 297
297 = 0*26^2 + 11*26 + 11
999 = ALL
For N = 158760, n = 158759 and log_26(25*158759/26+1) = 3.66..., we need four digits
p(158759) = 158759 - 18278 = 140481
140481 = 7*26^3 + 25*26^2 + 21*26 + 3
158759 = H Z V D
This appears to be a very standard "implement conversion from base 10 to base N" where N happens to be 26, and you're using letters to represent all digits.
If you have A-Z as a 26ary value, you can represent 0 through (26 - 1) (like binary can represent 0 - (2 - 1).
BZ = 1 * 26 + 25 *1 = 51
The analogue would be:
19 = 1 * 10 + 9 * 1 (1/B being the first non-zero character, and 9/Z being the largest digit possible).
You basically have the right idea, but you need to shift it so A = 0, not A = 1. Then everything should work relatively sanely.
In the lengthy answer by #Daniel I see a call to log() which is a red flag for performance. Here is a simple way without much complex math:
function excelize(colNum) {
var order = 0, sub = 0, divTmp = colNum;
do {
divTmp -= 26**order;
sub += 26**order;
divTmp = (divTmp - (divTmp % 26)) / 26;
order++;
} while(divTmp > 0);
var symbols = "0123456789abcdefghijklmnopqrstuvwxyz";
var tr = c => symbols[symbols.indexOf(c)+10];
Number(colNum-sub).toString(26).split('').map(c=>tr(c)).join('');
}
Explanation:
Since this is not base26, we need to substract the base times order for each additional symbol ("digit"). So first we count the order of the resulting number, and at the same time count the substract. And then we convert it to base 26 and substract that, and then shift the symbols to A-Z instead of 0-P.
these two algorithms are used to check valid member numbers
the first is the one I was given by the company,
the second is one I devised, from my tests I can't see any difference between them functionally,
are there any cases anyone can see where they would return different outputs?
test input:
6014355021355010
or
6014355065446212
or
6014351000254605
The check digit is calculated using the first 15 digits as follows:
Sum the digits in the even numbered positions from left to right
Multiply each digit in the odd numbered positions (from left to
right) by the number 2. If any results
are 2 digits, sum the digits into one.
Sum the digits from each
multiplication into a final result.
Add the final results of steps 1 and 2.
Take the last digit of the result from step 3 and subtract from 10 to
give the check digit.
Take the last digit from the 16 Digit number and compare to the check digit
if they are equal, it is valid
vs
The check digit is calulated using the whole 16 digits as follows:
Sum the digits in the even numbered positions from left to right
Multiply each digit in the odd numbered positions (from left to
right) by the number 2. If any results
are 2 digits, sum the digits into one.
Sum the digits from each
multiplication into a final result.
Add the final results of steps 1 and 2.
Take the final result and Modulus 10
If the result is 0, it is valid
Update:
ok so. I have tried to create both these algorithms in php,
the second one, i have created successfully,
the first however, i can not seem to get to work.
possibly i have read this wrong, but, here is the original brief i was given for the first algorithm:
16 digit number modulus 10 check digit calculation
The check digit is calculated using the first 15 digits as follows:
1. Sum the digits in the even numbered positions from left to right
2. Multiply each digit in the odd numbered positions (from left to right) by the number 2
If any results are 2 digits, sum the digits into one.
Sum the digits from each multiplication into a final result.
3. Add the final results of steps 1 and 2.
4. Take the last digit of the result from step 3 and subtract from 10 to give the check digit.
If the result of step 3 is a multiple of 10, then the check digit will be zero.
Example 6014 3590 0000 0928
1.0 0 + 4 + 5 + 0 + 0 + 0 + 9 = 18
2.0 6 * 2 = 12 so 1 + 2 = 3
2.1 1 * 2 = 2
2.2 3 * 2 = 6
2.3 9 * 2 = 18 so 1 + 8 = 9
2.4 0 * 2 = 0
2.5 0 * 2 = 0
2.6 0 * 2 = 0
2.7 2 * 2 = 4
2.8 3 + 2 + 6 + 9 + 0 + 0 + 0 + 4 = 24
3.0 18 + 24 = 42
4.0 The check digit is 10 - 2 = 8
5.0 8 = the 16th digit (601435900000092[8])
Update2:
ok, so i have corrected the algorithm,
also, i should mention, that there are two other checks
if(length of number != 16)
return 1;
and
if(first 5 characters != 601435)
return 1;
so are there any counters to this?
cheers,
Matt
Algorithm test [php]
<?php
$file = file_get_contents('fb.csv');
$numbers = explode("\n", $file);
function validate_flybuys($number) {
$r = array ('o' => '0', 'i' => '1', 'l' => '1', 'e' => '3', ' ' => '');
$flybuys = trim(strtolower($number));
$flybuys = str_replace(array_keys($r), $r, $flybuys);
if('601435' != substr($flybuys, 0, 6) || strlen($flybuys) != 16)
return 1;
$evens = 0;
$odds = '';
for($i = 0; $i <= 15; $i+=2) {
$odds .= $flybuys[$i];
$evens += $flybuys[$i+1];
}
$odds = str_split($odds);
foreach($odds as &$odd) {
$odd = $odd*2;
if($odd >= 10) {
$odd = str_split($odd);
$odd = $odd[0] + $odd[1];
}
}
return (array_sum($odds)+$evens) % 10;
}
function validate_flybuys2($number) {
$r = array ('o' => '0', 'i' => '1', 'l' => '1', 'e' => '3', ' ' => '');
$flybuys = trim(strtolower($number));
$flybuys = str_replace(array_keys($r), $r, $flybuys);
if('601435' != substr($flybuys, 0, 6) || strlen($flybuys) != 16)
return 1;
$evens = 0;
$odds = '';
for($i = 0; $i <= 14; $i+=2) {
$odds .= $flybuys[$i];
if($i != 14)
$evens += $flybuys[$i+1];
}
$odds = str_split($odds);
foreach($odds as &$odd) {
$odd = $odd*2;
if($odd >= 10) {
$odd = str_split($odd);
$odd = $odd[0] + $odd[1];
}
}
$total = (array_sum($odds))+$evens;
$total = str_split($total);
$check = 10 - $total[1];
$check = $check % 10;
if($check == substr($flybuys, 15, 1))
return 0;
else
return $check;
}
foreach($numbers as $number) {
$valid = validate_flybuys($number);
$valid2 = validate_flybuys2($number);
if($valid != $valid2 || $valid != 0) {
echo '<hr />';
echo 'NUMBER: '.$number.'<br />';
echo 'V1: '.$valid.'<br />';
echo 'V2: '.$valid2.'<br />';
}
}
if anyone is interested and comments i can post some sample numbers to test against :)
oh and feel free to optimize the code 8D
EDIT: This proof only works if the step 5 and 6 of the first algorithm are an equal check instead of a modulus calculation. The equal check seems to be meant by the original brief as mentioned in the comments.
EDIT2: I think the first algorithm should look like this. But you should better verify this, maybe from the one who gave you the original brief.
Sum the digits in the even numbered positions from left to right
Multiply each digit in the odd numbered positions (from left to right) by the number 2. If any results are 2 digits, sum the digits into one. Sum the digits from each multiplication into a final result.
Add the final results of steps 1 and 2.
Take the last digit of the result from step 3 and substract from 10 to give the check digit.
Take the last digit of the 16digit-number and if it is the same as the computed check digit the number is valid
To verifiy mathematically that both algorithms are equal you can use congruency.
Let's say a is the sum from step 3 of the first algorithm, b is the sum of step 3 of the second algorithm and c is the 16th digit (the check digit).
Than the difference between a and b is that c is added to b but not to a, which means:
a ≡ b - c mod 10
The check from the first algorithm is performed by substracting a from 10 and check if it is congruent c for modulus 10. (for addition and substraction it doesn't matter when the modulus is performed)
10 - a ≡ c mod 10
this is equal to:
-a ≡ c mod 10
Now you can substitute a with the first one, which results in
-(b - c) ≡ c mod 10
this is equal to:
c - b ≡ c mod 10
and this is equal to:
-b ≡ 0 mod 10
b ≡ 0 mod 10
and that is the check, which is performed in the second algorithm. So both algorithms returns the same result.
Edit2: Please see my other answer with a counter example with the correct algorithms.
Edit: I was using 15 not 16 numbers in the second algorithm.
They are not equivalent.
Take 383838383838383-6 which is valid for first algorithm, but the second algorithm gives 4 as the check digit != 0.
Edit: Sums are 56 for the even part and 48 for odd, sum is 104.
The algorithms are different:
Take 0000000000000257
The original algorithm says it's not valid: Sum of even numbered digits is 2, the odds sum is 1 => total of 3. 10-3 = 7. 257 MOD 7 = 5 != 0 => Not valid
You algorithm sums even to 9, odds to 1 => total 10. 10 MOD 10 == 0 => Valid.
So they are not equivalent
qed. :-)
Your php code has some problems.
$check = 10 - $total[1]; is only valid if the total sum is a 2-digit number. Because your numbers always start with 601435 the total sum has not less than 2 digits. But at least 6014359999999990 and 6014359999999999 would be validated wrong in V2.
The line return $check; can return 0. That way 6014355021355012 or 6014355021355017 are verified as being valid, while they are not.
I would replace the lines:
$total = str_split($total);
$check = 10 - $total[1];
$check = $check % 10;
if($check == substr($flybuys, 15, 1))
return 0;
else
return $check;
with
return (substr($flybuys, 15, 1) + $total) % 10;
So V1 and V2 returns the same value.