Base 36 value math problem
-
I am having a major 'head against wall' problem here... Given two base 36 values ('A0ZWS0P' and 'A0ZWS9P', for example) and a third (random) value, how would you go about determining whether the random value was 'between' the starting and ending values? I am working in 2012 VB.Net
C# (sorry; I don't do "VB")...
IsInBetween( "A0ZWS0A" ); IsInBetween( "A0ZWS0P" ); IsInBetween( "A0ZWS7P" ); IsInBetween( "A0ZWSAP" ); private static void IsInBetween( string value ) { string s1 = "A0ZWS0P"; string s2 = "A0ZWS9P"; bool isInbetween = value.CompareTo( s1 ) == 0 || value.CompareTo( s2 ) == 0 || ( value.CompareTo( s1 ) > 0 && value.CompareTo( s2 ) < 0 ); Console.WriteLine( "Is {0} between {1} {2}? {3}", value, s1, s2, isInbetween ); }
-
C# (sorry; I don't do "VB")...
IsInBetween( "A0ZWS0A" ); IsInBetween( "A0ZWS0P" ); IsInBetween( "A0ZWS7P" ); IsInBetween( "A0ZWSAP" ); private static void IsInBetween( string value ) { string s1 = "A0ZWS0P"; string s2 = "A0ZWS9P"; bool isInbetween = value.CompareTo( s1 ) == 0 || value.CompareTo( s2 ) == 0 || ( value.CompareTo( s1 ) > 0 && value.CompareTo( s2 ) < 0 ); Console.WriteLine( "Is {0} between {1} {2}? {3}", value, s1, s2, isInbetween ); }
I will try this....I also am a C# guy, for the last 10 years or so, but the job specced VB so, learn it I did :-D
-
I will try this....I also am a C# guy, for the last 10 years or so, but the job specced VB so, learn it I did :-D
-
I am having a major 'head against wall' problem here... Given two base 36 values ('A0ZWS0P' and 'A0ZWS9P', for example) and a third (random) value, how would you go about determining whether the random value was 'between' the starting and ending values? I am working in 2012 VB.Net
A base 36 numbering scheme should be the math rappresentation of a normal numer expressed with 36 different ciphers. :) It should be quite an easy task to create a function that converts the strings that you have to plain binary numbers (base 2) understandable to the computer. This function is equivalent to an ascii to bin conversion, only the symbols that have top be handled are 36. The sequence, I suppose, is: 0 1 2 3 4 5 6 7 8 9 A B C D E F G . . . . . Z The generic rappresentation of a number expressed in base x is: Vn*X^n + V(n-1)*X^n-1 + V(n-2)*X^n-2 + ... + V(0) In plain the sum of all ciphers by the power of the base at the position taken as exponent. This is sample to convert a base 36 number to a base 2 numberEDIT: This sample converts any ascii rappresentation of a number in all bases between 2 and 36. It acts as the standard atoi, atol, etc. It converts all applicable characters up to the end of string or the first non number with respect to the choosed base. If the first string char is not a valid cipher, or the string is empty it returns NULL.
long long GenRadVal(char *str, int base)
{
if (base<2 || base>36)
return 0LL;long long val = 0; for (int i = 0; str\[i\]; i++) { int c = toupper(str\[i\]); if ((c < 0) || ((c > '9') && (c < 'A')) || (c > 'Z')) break; c = c > '9' ? c - 'A' + 10 : c - '0'; if (c >= base) break; val \*= base; val += c; } return val;
}
This will give you back a 64 bits number equivalent to the string. To go back to the original value you can use itoa() function in C. Now comparisons are easy.. :laugh: P.S. the reverse for this function is the stdlib function itoa() with base=36.
-
A base 36 numbering scheme should be the math rappresentation of a normal numer expressed with 36 different ciphers. :) It should be quite an easy task to create a function that converts the strings that you have to plain binary numbers (base 2) understandable to the computer. This function is equivalent to an ascii to bin conversion, only the symbols that have top be handled are 36. The sequence, I suppose, is: 0 1 2 3 4 5 6 7 8 9 A B C D E F G . . . . . Z The generic rappresentation of a number expressed in base x is: Vn*X^n + V(n-1)*X^n-1 + V(n-2)*X^n-2 + ... + V(0) In plain the sum of all ciphers by the power of the base at the position taken as exponent. This is sample to convert a base 36 number to a base 2 numberEDIT: This sample converts any ascii rappresentation of a number in all bases between 2 and 36. It acts as the standard atoi, atol, etc. It converts all applicable characters up to the end of string or the first non number with respect to the choosed base. If the first string char is not a valid cipher, or the string is empty it returns NULL.
long long GenRadVal(char *str, int base)
{
if (base<2 || base>36)
return 0LL;long long val = 0; for (int i = 0; str\[i\]; i++) { int c = toupper(str\[i\]); if ((c < 0) || ((c > '9') && (c < 'A')) || (c > 'Z')) break; c = c > '9' ? c - 'A' + 10 : c - '0'; if (c >= base) break; val \*= base; val += c; } return val;
}
This will give you back a 64 bits number equivalent to the string. To go back to the original value you can use itoa() function in C. Now comparisons are easy.. :laugh: P.S. the reverse for this function is the stdlib function itoa() with base=36.
This will not do a parse of the string as Base 36! It is treating the 'digits' as in reverse order. I.e., the right-most digit corresponds to the highest power of 36. The representation of non-overlapping ranges (see other comments above) will not survive this "parse". Here's one in C#:
static long Parse36(string s) { long v = 0; foreach(char c in s) { char uc = char.ToUpper(c); bool isDigit = ('0' <= uc && uc <= '9'); if (!(isDigit || ('A' <= uc && uc <= 'Z'))) throw new FormatException(); int d = uc - (isDigit ? '0' : ('A' - 10)); v = v \* 36 + d; } return v; }
(It can be simplified a bit if you can guarantee the strings contain only 0-9, A-Z uppercase.)
A positive attitude may not solve every problem, but it will annoy enough people to be worth the effort.
-
My bad, I elided some details.... The values are part of numbering sequences for ticket books. Say I have a book with a number range of '9ER78Y' to 9ER79J', stored as strings ('start and 'end') (not my design, it was inherited). Now I am given a ticket number of '9ER79A' I need to find the book of tickets that contains this ticket. The only way I can see to do it is a brute force table scan, of over 500,000 books :( I am not sure an index would help, unless I added a discriminator column to represent the book start and end range
Do you need to do this within a DB query (SQL), or is the "search" in-memory? Are there any other constraints on the problem space that might be used to simplify things? (E.g., are the ranges all exactly the same size? or a multiple of some size?) If you need to do significant numbers of checking at a time, then some pre-processing of the data while loading into memory is a good tradeoff. If these are one-off checks against the DB, then pre-processing is probably not worth it.
A positive attitude may not solve every problem, but it will annoy enough people to be worth the effort.
-
My bad, I elided some details.... The values are part of numbering sequences for ticket books. Say I have a book with a number range of '9ER78Y' to 9ER79J', stored as strings ('start and 'end') (not my design, it was inherited). Now I am given a ticket number of '9ER79A' I need to find the book of tickets that contains this ticket. The only way I can see to do it is a brute force table scan, of over 500,000 books :( I am not sure an index would help, unless I added a discriminator column to represent the book start and end range
You can implement this with a form of binary search. 0. [Preparation] Sort the strings representing the first ticket in each book in ascending order: a. zero-pad any short strings (e.g. "ABC1" should be padded to "00ABC1" b. sort the strings using a case-insensitive sort c. pad the list with a dummy ending value (e.g. "ZZZZZZ"). d. pad the list with a dummy starting value (e.g. "000000"). 1. [Eliminate low values] Use a binary search to find the location of largest value less than or equal to the target string. If the result points to the starting dummy value, then no such value exists. 2. [Eliminate high values] Use a binary search to find the location of the smallest value larger than the target string. If the result points to the ending dummy value, then no such value exists. The range [low, high) contains your result. If low != high, the range should contain a single element that is the desired ticket book. If low == high, no ticket book was found. Note that you can handle missing books in the sequence by adding dummy book starting values to the array.
If you have an important point to make, don't try to be subtle or clever. Use a pile driver. Hit the point once. Then come back and hit it again. Then hit it a third time - a tremendous whack. --Winston Churchill
-
This will not do a parse of the string as Base 36! It is treating the 'digits' as in reverse order. I.e., the right-most digit corresponds to the highest power of 36. The representation of non-overlapping ranges (see other comments above) will not survive this "parse". Here's one in C#:
static long Parse36(string s) { long v = 0; foreach(char c in s) { char uc = char.ToUpper(c); bool isDigit = ('0' <= uc && uc <= '9'); if (!(isDigit || ('A' <= uc && uc <= 'Z'))) throw new FormatException(); int d = uc - (isDigit ? '0' : ('A' - 10)); v = v \* 36 + d; } return v; }
(It can be simplified a bit if you can guarantee the strings contain only 0-9, A-Z uppercase.)
A positive attitude may not solve every problem, but it will annoy enough people to be worth the effort.
-
I am having a major 'head against wall' problem here... Given two base 36 values ('A0ZWS0P' and 'A0ZWS9P', for example) and a third (random) value, how would you go about determining whether the random value was 'between' the starting and ending values? I am working in 2012 VB.Net
I dont know if this will help, but here's a few snippets I made to convert between bases in Javascript
var characters='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
To convert decimal to base 36:
var decimal=21828139225;
var a=decimal,code='';while(a!=0) var code=characters.charAt(a%characters.length)+code,a=Math.floor(a/characters.length);
alert(code);
To convert base 36 to decimal:
var code='A0ZWS0P';
for(var i=decimal=0,len=code.length;i
A while back, I took this whole base conversion thing way too far, and made the ultimate base conversion tool which can be found at https://www.dropbox.com/s/qmize4qx4hf6lrn/Number%20System%20Conversion%20and%20Encryption.html?dl=0
If you're ever in doubt, you can always resort back to the conversion chart, it never lies!Happy Coding!
-
I am having a major 'head against wall' problem here... Given two base 36 values ('A0ZWS0P' and 'A0ZWS9P', for example) and a third (random) value, how would you go about determining whether the random value was 'between' the starting and ending values? I am working in 2012 VB.Net
I would simply pad the 3 strings on left with '0's so that all values have same length. After that, it is a simply string comparison problem. From other answers, I see that you have 500000 books I guess you have a database, and that books contain consecutive numbers - make sure all first ticket number of books have the same length by padding 'o' on left. - make this field an index - search the base to find the first book with number <= random
Patrice “Everything should be made as simple as possible, but no simpler.” Albert Einstein
-
C# (sorry; I don't do "VB")...
IsInBetween( "A0ZWS0A" ); IsInBetween( "A0ZWS0P" ); IsInBetween( "A0ZWS7P" ); IsInBetween( "A0ZWSAP" ); private static void IsInBetween( string value ) { string s1 = "A0ZWS0P"; string s2 = "A0ZWS9P"; bool isInbetween = value.CompareTo( s1 ) == 0 || value.CompareTo( s2 ) == 0 || ( value.CompareTo( s1 ) > 0 && value.CompareTo( s2 ) < 0 ); Console.WriteLine( "Is {0} between {1} {2}? {3}", value, s1, s2, isInbetween ); }