Solutions
A
Popular programming journal Obscure C Techniques for Experts has published a novel way to save space for a doubly-linked list program. Instead of storing
two pointers (one next and one previous), this new technique stores a single value: the XOR of previous and next pointers. Check Wikipedia XOR linked list for details.
The below code (filename xorlist.c
) implements XOR linked list:
The corresponding program output:
Ensure your code meets the expected operations and initialization of such a list as well as the insertion, and deletion, of elements from such a list.
Obviously, the above C code listing was incomplete, you shall provide the functioned implementations. A01
, A02
, A03
, and A04
are C expressions. You must obey the following rules when filling them:
intptr_t
and uintptr_t
types are extremely useful for casting pointers when you want to do address arithmetic. You shall consider to explicitly use the types provided by <inttypes.h>
.(xorlist_t *) (*head)->link
to (xorlist_t*)(*head)->link
or (xorlist_t *)(*head)->link
. Be aware of the spaces! Details determine success or failure.
- A01 = ?
(*head)->link
- A02 = ?
(intptr_t) *head
- A03 = ?
(intptr_t) *head
- A04 = ?
(intptr_t) current
B
Fill in B01
, B02
, B03
and B04
to complete the reverse
function which takes in a head
to the head of a linked list and returns a new copy of the linked list in reverse order. You must allocate space for the new linked list that you return. An (incomplete) example program using reverse is also shown below.
You shall provide the functioned implementations. B01
is a declaration for function parameter. B02
, B03
, and B04
are C expressions. You must obey the following rules when filling them:
struct list_node *h
to struct list_node* h
. Be aware of the spaces! Details determine success or failure.
- B01 = ?
struct list_node **head
- B02 = ?
(*head)->val
- B03 = ?
next
- B04 = ?
ret
C
Let's try to determine endianness at compile time. If someone needs to know the endianess at compile time, there are 2 different use cases:
In the majority of use cases, one wants just to convert from little to big endian, and vice versa (or actually to and from host endianness!). Assume that we are going to provide endian conversion functions/macros start with the end_
prefix.
You shall provide the functioned implementations. Both C01
and C02
are hexadecimal integer literals, meaning that they should start with 0x
. C03
, C04
, C05
, and C06
are C expressions. You might consider to call end_bswap32
function when it is necessary. You must obey the following rules when filling them:
end_bswap32(n)
to end_bswap32( n )
. Be aware of the spaces! Details determine success or failure.
- C01 = ?
0xff00
- C02 = ?
0xff0000
- C03 = ?
end_bswap32(n)
- C04 = ?
n
- C05 = ?
n
- C06 = ?
end_bswap32(n)
D
Given the following bitstream 111111002, answer the following questions:
What is the value if it was interpreted in two's complement? __ D01 __ (Answer in decimal)
- D01 = ?
-4
(Flip all the bits and add 1) * -1 = (0b0000 0011 + 1) * -1 = -4
You are given the following field breakdown and specifications of an 8-bit floating point, which follows the same rules as standard 32-bit IEEE floats, except with different field lengths: (Sign: 1 bit; Exponent: 3 bits; Significand: 4 bits)
Exponent Value | Significand Value | Floating Point Value |
---|---|---|
Smallest | Zero, Non-Zero | ±0, Denormalized |
Largest | Zero, Non-zero | ±Infinity, NaN |
What is the floating point value of 111111002? __ D02 __
- D02 = ?
NaN
Exponent field is the largest exponent (0b111) and the significant is non-zero-> NaN
Now we modify the floating point description in part 2, so that the exponent field is now in two's complement instead of in bias notation. Compute the floating point value of 111111002. __ D03 __
- D03 = ?
-0.875
Exponent: 0b111 = -1, Signif: 0.75 = = -0.875
E
You received a sequence of IEEE standard 16-bit floating point numbers from a trusted source. Note that a 16-bit floating point is 1 sign bit, 5 exponent bits, and
10 mantissa bits. The bias for the exponent is -15
. Unfortunately, some of the data was corrupted during communication, rendering it unreadable. For the following problems, we will use x
to refer to a bit that was corrupted (in other words, we don’t know what the sender wanted that bit to be). For example, if I received the data 0b0xx1
, the sender sent one of 0b0001
, 0b0101
, 0b0011
, or 0b0111
.
0b1110xxxxxxxxxxxx
. What is the decimal value of the smallest number the sender could have sent (i.e. it is less than all of the other possibilities)? __ E01 __ You must provide the decimal form, do not leave as a power of 2.
- E01 = ?
-8188
By the previous observation, the smallest number is encoded by 0xEFFF. This has sign bit 1, exponent 0b11011 - 15 = 12, and mantissa (1).1111111111 = . The answer would be
- E02 = ?
0x7777
One property of floating point numbers is that their order is the same as that of sign-magnitude integers (ignoring NaNs); for example, 0x5555 < 0x7555. In order to maximize the number, we therefore want to set all thex
s to 1. This yields the encoding 0x7777.
F
Following the bit-level floating-point coding rules, implement the function with the following prototype:
For IEEE 754 single-precision floating-point number f
, this function computes (int) f
. Your function should round toward zero. If f
cannot be represented as an integer, then the function should return 0x80000000
.
Fill F01
, F02
, F03
, F04
and F05
to make the above C code really functioned as expected. Both F01
and F03
are decimal. F02
is a hexadecimal integer literal. Both F04
and F05
are C expressions. You must obey the following rules when filling them:
M << (E - 1)
to M<<(E-1)
. Be aware of the spaces! Details determine success or failure.
- F01 = ? (Answer in decimal)
23- F02 = ? (Answer in HEX)
0x7FFFFF- F03 = ? (Answer in decimal)
23- F04 = ?
M << (E - 23)
- F05 = ?
M >> (23 - E)
G
Implement C function which gets a number and returns if it is positive (i.e., > 0
).
if
<= 0
then return false, if> 0
then return true.
Example: 0 false, -12 false, 29 true.
However, you CAN NOT use any flow control (e.g. if, else, for, switch, case, goto, while, ?
) nor logical operators (e.g. &&
, ||
, >
, <
, ==
, <=
, >=
). Instead, you SHALL use operator <<
, >>
, &
, |
, +
, ^
, ~
, !
to implement such routine. Assume sizeof(int) = 4
.
Fill G01
and G02
to make the above C code really functioned as expected. G01
is decimal, and G02
is a C expresssion. You must obey the following rules when filling them:
x &= 1
to x = x&1
. Be aware of the spaces! Details determine success or failure.
- G01 = ?
1
- G02 = ?
x |= tmp
ORx = x | tmp
ORx = tmp | x
ORx ^= tmp
ORx = x ^ tmp
ORx = tmp ^ x