Мне дан набор данных, и мне необходимо упаковать его в значение uint64_t, которое в следующем примере принимает форму типа "weatherlog_t"
Мне запрещено использовать арифметические операторы (+, ++, -, -, *,%, /, ...), однако мне разрешено использовать побитовые операторы (&, |, ^, << , >>, ~) и логические операторы (!, =, -,! =, && и ||)
Однако у меня есть предопределенные функции add () и sub (), которые обрабатывают побитовое сложение и вычитание, и они используются в следующем примере. Они были проверены, и я уверен, что они работают в той степени, в которой это необходимо.
Согласно инструкции, 64-битное значение должно быть расположено следующим образом:
/* - year :: 6 bits -- stored as the number of years since the year 2000.
- month :: 4 bits
- day :: 5 bits
- zip_code :: 16 bits
- high_temp :: in degrees Fahrenheit, stored as an 8-bit signed integer
- low_temp :: in degrees Fahrenheit, stored as 8-bit signed integer
- precipitation :: in mm. stored as a 10-bit unsigned integer.
- average_wind_speed :: 7 bits. unsigned int km/hr.
All of these are packed into a 64 bit unsigned integer in the above order.
We'd store:
- year :: 2015, which is 15 years from 2000, so 001111
- month :: September, which is the 9th month, so 1001.
- day :: 16, which is 1 0000
- zip_code :: 19122 which is 0100 1010 1011 0010
- high_temp :: 85F, so 0101 0101
- low_temp :: 65F, so 0100 0001
- precipitation :: 35 mm so 00 0010 0011
- average wind speed :: 5 km/h, so 000 0101
And all would be packed into a single 64-bit unsigned integer:
00 1111 1001 10000 0100 1010 1011 0010 0101 0101 0100 0001 00 0010 0011 000 0101
OR
0011 1110 0110 0000 1001 0101 0110 0100 1010 1010 1000 0010 0001 0001 1000 0101 */
Пока что у меня есть:
weatherlog_t pack_log_entry(unsigned int year, unsigned int month, unsigned int day,
unsigned int zip, int high_temp, int low_temp,
unsigned int precip, unsigned int avg_wind_speed) {
weatherlog_t ret = 0;
unsigned int newYear = sub(year, 2000);
ret = (ret << 6);
ret = add(ret, newYear);
ret = (ret << 4);
ret = add(ret, month);
ret = (ret << 5);
ret = add(ret, day);
ret = (ret << 16);
ret = add(ret, zip);
ret = (ret << 8);
ret = add(ret, high_temp);
ret = (ret << 8);
ret = add(ret, low_temp);
ret = (ret << 10);
ret = add(ret, precip);
ret = (ret << 6);
ret = add(ret, avg_wind_speed);
return ret;
}
Однако, когда я захожу и проверяю это, проверяя двоичное значение ret, кажется, что он останавливается на 32-битах, а смещение влево после этой точки приводит к потере любых битов, оставшихся от 32-го левого бита. Я изо всех сил пытаюсь понять, что я делаю неправильно, хотя я новичок в побитовой арифметике и пока не до конца понимаю, как он взаимодействует с языком Си.
РЕДАКТИРОВАТЬ: По запросу, код для add () и вычитания ()
unsigned int add(unsigned int i, unsigned int j) {
/* can be done in a total of 7 lines, including one to declare an unsigned int, */
/* two for a while loop, and one for the return
You're not required to do it in 7 lines though . */
while(j != 0){
unsigned int carry = i & j;
i = i ^ j;
j = carry << 1;
}
return i;
}
unsigned int sub(unsigned int i, unsigned int j) {
/* Similar 7 lines, although there is a shorter way */
while (j != 0){
unsigned int borrow = (~i) & j;
i = i ^ j;
j = borrow << 1;
}
return i;
}