Is this a correct way to store dates? - date

I found this example of storing dates in the book Algorithms 4th edition, using only a single integer. I'm not sure if it is correct.
This is the class definition for a Date.
public class Date
{
private final int value;
public Date(int m, int d, int y)
{ value = y*512 + m*32 + d; }
public int month()
{ return (value / 32) % 16; }
public int day()
{ return value % 32; }
public int year()
{ return value / 512; }
public String toString()
{ return month() + "/" + day()
}
Where do the numbers 512 and 32 come from, and why do we modulo by 16 when calculating the month.

Yes, if your integer has 32 bits, then you can store in it all valid dates from 01-01-0001 up to (more or less) 01-01-8388608, where 8388608 is a year.
Also, the order of the integer values is the same as the natural order of dates.
But how is it done?
First observation is that all possible numbers of days in month fit into the interval [0, 31] (note that 0 will never be used).
Thus, you can store that using just five bits.
Similarly, all possible months fit into the interval [0, 15], so now you only need 4 bits.
Whole date is saved like this:
...011111100001 <---------- year
||||||||||||1100 <------ month
||||||||||||||||10011 <- day
------------------------
011111100001110010011
If you want to get the value of the year, you have to get rid of the initial 9 bits. You can delete one bit by simply dividing the value by 2. To get rid of the 9 bits, you have to divide 9 times by 2, or - in one step - by 2^9 = 512.
In the above example, when you divide 011111100001110010011 by 2^9:
011111100001110010011
1000000000 = 2^9
---------------------
011111100001
you get 011111100001 (or 2017 in decimal).
In short:
division by 2^n == deleting last n bits of a number, shifting everything to the right.
dividion modulo 2^n == looking only at the last n bits.

Related

Hash an 8 digit number that contains non repetitive digits from 1 to 8 only

Given that a number can contain only digits from 1 to 8 (with no repetition), and is of length 8, how can we hash such numbers without using a hashSet?
We can't just directly use the value of the number of the hashing value, as the stack size of the program is limited. (By this, I mean that we can't directly make the index of an array, represent our number).
Therefore, this 8 digit number needs to be mapped to, at maximum, a 5 digit number.
I saw this answer. The hash function returns a 8-digit number, for a input that is an 8-digit number.
So, what can I do here?
There's a few things you can do. You could subtract 1 from each digit and parse it as an octal number, which will map one-to-one every number from your domain to the range [0,16777216) with no gaps. The resulting number can be used as an index into a very large array. An example of this could work as below:
function hash(num) {
return parseInt(num
.toString()
.split('')
.map(x => x - 1), 8);
}
const set = new Array(8**8);
set[hash(12345678)] = true;
// 12345678 is in the set
Or if you wanna conserve some space and grow the data structure as you add elements. You can use a tree structure with 8 branches at every node and a maximum depth of 8. I'll leave that up to you to figure out if you think it's worth the trouble.
Edit:
After seeing the updated question, I began thinking about how you could probably map the number to its position in a lexicographically sorted list of the permutations of the digits 1-8. That would be optimal because it gives you the theoretical 5-digit hash you want (under 40320). I had some trouble formulating the algorithm to do this on my own, so I did some digging. I found this example implementation that does just what you're looking for. I've taken inspiration from this to implement the algorithm in JavaScript for you.
function hash(num) {
const digits = num
.toString()
.split('')
.map(x => x - 1);
const len = digits.length;
const seen = new Array(len);
let rank = 0;
for(let i = 0; i < len; i++) {
seen[digits[i]] = true;
rank += numsBelowUnseen(digits[i], seen) * fact(len - i - 1);
}
return rank;
}
// count unseen digits less than n
function numsBelowUnseen(n, seen) {
let count = 0;
for(let i = 0; i < n; i++) {
if(!seen[i]) count++;
}
return count;
}
// factorial fuction
function fact(x) {
return x <= 0 ? 1 : x * fact(x - 1);
}
kamoroso94 gave me the idea of representing the number in octal. The number remains unique if we remove the first digit from it. So, we can make an array of length 8^7=2097152, and thus use the 7-digit octal version as index.
If this array size is bigger than the stack, then we can use only 6 digits of the input, convert them to their octal values. So, 8^6=262144, that is pretty small. We can make a 2D array of length 8^6. So, total space used will be in the order of 2*(8^6). The first index of the second dimension represents that the number starts from the smaller number, and the second index represents that the number starts from the bigger number.

Converting long-math to work with doubles

If I have a calculation that is performed using long (64-bit integer) values with a final result that never exceeds 52 bits (the precision of a double-precision floating point), what is the best way to implement this calculation using double such that it always yields the same answer?
The difficulty comes in when performing, for example, a multiplication of two large numbers: If the long overflows, it drops the highest order bits, but if the double "overflows" (i.e. the result ends up with more than 52 significant bits), it drops the lowest order bits.
As an example, let's take the next(...) function in Java's Random class (edited a bit):
protected int next(int bits) {
seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1); // seed is a long
return (int) (seed >>> (48 - bits));
}
(Notice how the multiplication will likely overflow a long, but the result is ANDed down to 48 bits)
If I needed to exactly replicate the behavior of this function (or any other using long) in a language without the long data-type (e.g. JavaScript), what would be the most efficient way of doing this? One of the GWT-implementations of this function splits the seed into two halves of 24 bits each to eliminate overflows (again edited a bit):
double hi = seedhi * 0xECE66D + seedlo * 0x5DE; // seedhi and seedlo are doubles
double lo = seedlo * 0xECE66D + 0xB;
double carry = Math.floor(lo >> 24);
hi += carry;
lo &= (1L << 24) - 1;
hi &= (1L << 24) - 1;
seedhi = hi;
seedlo = lo;
Is this the best one can do, or are there some tricks/hacks to make this more elegant?

iPhone Converting ISBN13 to ISBN10

I'm trying to program it such that it would calculate the check digit of isbn 10 from isbn 13. Can anyone give some advice on how to carry it out?
Firstly, how do i actually loop through a 13 digit isbn, remove the prefixed 978 in front before i proceed on to calculate the check digit of the isbn10? Thank you in advance!:)
This is how you can remove the first 3 digits:
NSString *str = #"978XXXXXXXXX";
NSString *newStr = [str substringFromIndex:3];
And as for your ISBN10:
The final character of a ten digit International Standard Book Number is a check digit computed so that multiplying each digit by its position in the number (counting from the right) and taking the sum of these products modulo 11 is 0. The digit the farthest to the right (which is multiplied by 1) is the check digit, chosen to make the sum correct. It may need to have the value 10, which is represented as the letter X. For example, take the ISBN 0-201-53082-1. The sum of products is 0×10 + 2×9 + 0×8 + 1×7 + 5×6 + 3×5 + 0×4 + 8×3 + 2×2 + 1×1 = 99 ≡ 0 modulo 11. So the ISBN is valid.
While this may seem more complicated than the first scheme, it can be validated simply by adding all the products together then dividing by 11. The sum can be computed without any multiplications by initializing two variables, t and sum, to 0 and repeatedly performing t = t + digit; sum = sum + t; (which can be expressed in C as sum += t += digit;). If the final sum is a multiple of 11, the ISBN is valid.
Taken from here.

binary to decimal in objective-c

I want to convert the decimal number 27 into binary such a way that , first the digit 2 is converted and its binary value is placed in an array and then the digit 7 is converted and its binary number is placed in that array. what should I do?
thanks in advance
That's called binary-coded decimal. It's easiest to work right-to-left. Take the value modulo 10 (% operator in C/C++/ObjC) and put it in the array. Then integer-divide the value by 10 (/ operator in C/C++/ObjC). Continue until your value is zero. Then reverse the array if you need most-significant digit first.
If I understand your question correctly, you want to go from 27 to an array that looks like {0010, 0111}.
If you understand how base systems work (specifically the decimal system), this should be simple.
First, you find the remainder of your number when divided by 10. Your number 27 in this case would result with 7.
Then you integer divide your number by 10 and store it back in that variable. Your number 27 would result in 2.
How many times do you do this?
You do this until you have no more digits.
How many digits can you have?
Well, if you think about the number 100, it has 3 digits because the number needs to remember that one 10^2 exists in the number. On the other hand, 99 does not.
The answer to the previous question is 1 + floor of Log base 10 of the input number.
Log of 100 is 2, plus 1 is 3, which equals number of digits.
Log of 99 is a little less than 2, but flooring it is 1, plus 1 is 2.
In java it is like this:
int input = 27;
int number = 0;
int numDigits = Math.floor(Log(10, input)) + 1;
int[] digitArray = new int [numDigits];
for (int i = 0; i < numDigits; i++) {
number = input % 10;
digitArray[numDigits - i - 1] = number;
input = input / 10;
}
return digitArray;
Java doesn't have a Log function that is portable for any base (it has it for base e), but it is trivial to make a function for it.
double Log( double base, double value ) {
return Math.log(value)/Math.log(base);
}
Good luck.

how to create unique integer number from 3 different integers numbers(1 Oracle Long, 1 Date Field, 1 Short)

the thing is that, the 1st number is already ORACLE LONG,
second one a Date (SQL DATE, no timestamp info extra), the last one being a Short value in the range 1000-100'000.
how can I create sort of hash value that will be unique for each combination optimally?
string concatenation and converting to long later:
I don't want this, for example.
Day Month
12 1 --> 121
1 12 --> 121
When you have a few numeric values and need to have a single "unique" (that is, statistically improbable duplicate) value out of them you can usually use a formula like:
h = (a*P1 + b)*P2 + c
where P1 and P2 are either well-chosen numbers (e.g. if you know 'a' is always in the 1-31 range, you can use P1=32) or, when you know nothing particular about the allowable ranges of a,b,c best approach is to have P1 and P2 as big prime numbers (they have the least chance to generate values that collide).
For an optimal solution the math is a bit more complex than that, but using prime numbers you can usually have a decent solution.
For example, Java implementation for .hashCode() for an array (or a String) is something like:
h = 0;
for (int i = 0; i < a.length; ++i)
h = h * 31 + a[i];
Even though personally, I would have chosen a prime bigger than 31 as values inside a String can easily collide, since a delta of 31 places can be quite common, e.g.:
"BB".hashCode() == "Aa".hashCode() == 2122
Your
12 1 --> 121
1 12 --> 121
problem is easily fixed by zero-padding your input numbers to the maximum width expected for each input field.
For example, if the first field can range from 0 to 10000 and the second field can range from 0 to 100, your example becomes:
00012 001 --> 00012001
00001 012 --> 00001012
In python, you can use this:
#pip install pairing
import pairing as pf
n = [12,6,20,19]
print(n)
key = pf.pair(pf.pair(n[0],n[1]),
pf.pair(n[2], n[3]))
print(key)
m = [pf.depair(pf.depair(key)[0]),
pf.depair(pf.depair(key)[1])]
print(m)
Output is:
[12, 6, 20, 19]
477575
[(12, 6), (20, 19)]